Delphi SAPI Text-To-Speech - PullRequest
       45

Delphi SAPI Text-To-Speech

10 голосов
/ 13 июня 2010

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

Я использовал превосходное руководство по библиотеке типов импорта в 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.Прошу прощения за любое невежество или глупость, показанную мной в этом посте ...

Обновление

В интересах всех, кто сталкивается с той же проблемой, что и я, видео Франсуа объяснил, что естьошибка в 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 ]

4 голосов
/ 14 июня 2010

Вам может быть интересно посмотреть этот сеанс CodeRage 4 на "Включение речи Delphi Applications (zip)" Вы получите инструкции "как"... (и я думаю, что вы на Vista или +, так как нулевой разрыв не произошел на XP)

1 голос
/ 28 декабря 2012

У меня была такая же проблема в 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);
...