Delphi SAPI Text-To-Speech

Прежде всего: это не дубликат Delphi и SAPI. У меня есть конкретная проблема с объектом "SAPI в Delphi".

В Delphi 2009 я использовал превосходное руководство по типу импорта в Delphi 2009, чтобы получить компонент TSpVoice в палитре компонентов. Это отлично работает. С

var
  SpVoice: TSpVoice;

Я могу написать

SpVoice.Speak('This is an example.', 1);

чтобы получить асинхронный аудиовыход.

Первый вопрос

Согласно документации, я мог бы написать

SpVoice.Speak('This is an example.', 0);

чтобы получить синхронный аудиовыход, но вместо этого я получаю исключение EZeroDivide. Почему?

Второй вопрос

Но что более важно, я хотел бы динамически создавать объект SpVoice (я думаю, что это вызвано для "позднего связывания" объекта SpVoice), отчасти потому, что только небольшая часть всех сеансов моего приложения будет использовать его, а отчасти потому, что я не хочу предполагать существование сервера SAPI в системе конечного пользователя.

С этой целью я попробовал

procedure TForm1.FormClick(Sender: TObject);
var
  SpVoice: Variant;
begin
  SpVoice := CreateOleObject('SAPI.SpVoice');
  SpVoice.Speak('this is a test', 0);
end;

который, по-видимому, ничего не делает! (Замена 0 на 1 дает мне исключение EZeroDivide.)

Отказ

Я новичок в автоматизации COM/OLE. Прошу прощения за любое незнание или глупость, показанные мной в этом посте...

Update

В интересах каждого, кто сталкивается с той же проблемой, что и я, видео François объясняет, что в SAPI/Windows есть ошибка (какая-то некоторая несовместимость), что делает следующий код причиной исключения EZeroDivide:

procedure TForm1.FormClick(Sender: TObject);
var
  SpVoice: variant;
begin
  SpVoice := CreateOleObject('SAPI.SpVoice');
  SpVoice.Speak('This is a text.');
end;

Решение, представленное видео, заключается в изменении управляющего слова FPU:

procedure TForm1.FormClick(Sender: TObject);
var
  SpVoice: variant;
  SavedCW: Word;
begin
  SpVoice := CreateOleObject('SAPI.SpVoice');
  SavedCW := Get8087CW;
  Set8087CW(SavedCW or $4);
  SpVoice.Speak('This is a text.');
  Set8087CW(SavedCW);
end;

И, кроме того, если вы хотите играть асинхронно, тогда вы должны убедиться, что плеер не выходит за рамки!

Ответ 2

У меня была та же проблема в Delphi XE2. Решение Set8087CW(SavedCW or $4), представленное в вопросе, не работало для меня. Он просто заменил деление нулевым исключением на другое исключение с плавающей запятой.

Что для меня работало:

SavedCW := Get8087CW;
SetFPUExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);
SpVoice.Speak('All floating point exceptions disabled!', 0);
Set8087CW(SavedCW);