Speech API в Delphi (часть 1)

Источник:subritto.h1.ru
Дата публикации:2004
Twitter Facebook Vkontakte

Несколько слов от составителя

Изучив статьи Denisа Butorinа, мы пришли к выводу, что речь в них идет о Microsoft Speech API 4. В силу этого, если вы решите использовать приведенные в статье примеры, то будьте внимательны к тому, какая версия Microsoft SAPI установлена на вашем компьютере.

Простая программа, использующая Speech API

А сейчас мы познакомимся с программированием речи в Delphi. Хотите чтобы Делфи заговорил - читайте эту страницу!

Надеюсь, что вы уже установили Microsoft Speech API (SAPI) и хотя бы один речевой движок (text-to-speech engine). Если нет - то все можно скачать здесь.

«Речевые(голосовые) движки» - это те модули, которые синтезируют речь. Для доступа к ним нужно использовать специальные функции, которые описаны в наборе функций Speech API. Поэтому для того, чтобы написать минимальную программу, умеющую говорить, нужны эти два компонента. Сначала мы попробуем написать как раз эту программу-минимум, а потом заставим персонаж MS Agent заговорить. То есть постараемся совместить технологию MSAgent и SpeechAPI. Тогда агент станет еще более приятным.

Ну, а для того чтобы всем этим заняться, нам потребуется полезный модуль, в котором объявлены необходимые константы, типы, функции и интерфейсы. Не забудьте подключить его в разделе uses главного модуля приложения.

Попытаемся создать программу, где мы будем вводить текст для чтения в редакторе, выбирать движок для чтения в ComboBox'е и пару кнопок для чтения, паузы и остановки.

Объявим в секции private нужные для работы переменные:

private 
{Центральный интерфейс, через который }
{производятся все действия с речью} 
fITTSCentral: ITTSCentral; 

{Интерфейс для связи с аудиоустройством} 
fIAMM: IAudioMultimediaDevice; 

{Интерфейс для перебора движков} 
aTTSEnum: ITTSEnum; 

{Указатель на параметры движка}
fpModeInfo: PTTSModeInfo; 

В ходе создания главной формы приложения нам нужно проверить установленные в системе движки и поместить их названия в ComboBox. Это мы и сделаем:

procedure TForm1.FormCreate(Sender: TObject);
var 
NumFound : DWord; 
ModeInfo : TTSModeInfo;
begin 
try 
{Инициализация аудиоустройства} 
CoCreateInstance(CLSID_MMAudioDest, Nil, CLSCTX_ALL,  IID_IAudioMultiMediaDevice, fIAMM); 
except 
end; 
{Создание перечисляемого объекта для перебора всех движков в системе}
{ с помощью интерфейса ITTSEnum} 
CoCreateInstance(CLSID_TTSEnumerator, Nil, CLSCTX_ALL, 
      IID_ITTSEnum, aTTSEnum); 

{Сбрасываем на первый }
aTTSEnum.Reset;
{Получаем первый движок} 
aTTSEnum.Next(1, ModeInfo, @NumFound); 
While NumFound > 0 do 
begin 
ComboBox1.Items.Add(String(ModeInfo.szModeName)); 
{Получаем остальные}
aTTSEnum.Next(1, ModeInfo, @NumFound);  
end;
end;

В этом коде происходит создание экземпляров COM объектов класса CLSID_MMAudioDest и CLSID_TTSEnumerator. Для этого используется метод CoCreateInstance из библиотеки COM. Он создает экземпляр объекта на основании нужного класса CLSID(Class Identifier) и идентификатора интерфейса IID(Interface Identifier). В первом случае мы образуем объект для связи с аудио устройством, во втором - создаем экземпляр TTS, перечисляемого класса для перебора всех речевых синтезаторов, установленных в системе. После этого экземпляры классов окажутся соответственно в fIAMM и в aTTSEnum. После этого начинаем перебирать движки, узнавать их имена и добавлять в ComboBox. Кстати, не забудьте объявить в разделе uses модуль activex.pas, иначе Delphi будет ругаться насчет процедуры CoCreateInstance, и модуль ComObj.pas, иначе после выполнения процедуры CoCreateInstance переменная aTTSEnum будет оставаться равной nil, а значит программа будет обваливаться на следующей строке.

Теперь, если вы запустите программку, то в списке ComboBox'а увидите названия всех движков, установленных у вас в системе. Пока еще наша программка не умеет говорить, но уже знает необходимую инфу о речевых устройствах.

Теперь займемся загрузкой речевых синтезаторов для чтения текста. Поэтому пропишем событие изменения движка в ComboBox:

procedure TForm1.ComboBox1Change(Sender: TObject);
var 
NumFound: DWord; 

{Для хранения информации о текущем движке}
ModeInfo : TTSModeInfo;

begin 
try 
CoCreateInstance(CLSID_MMAudioDest, nil, CLSCTX_ALL,  IID_IAudioMultiMediaDevice, fIAMM); 
CoCreateInstance(CLSID_TTSEnumerator, nil, CLSCTX_ALL, 
       IID_ITTSEnum, aTTSEnum); 
aTTSEnum.Reset; {Перескакиваем на нужный движок} Form1.aTTSEnum.skip(ComboBox1.ItemIndex); 
aTTSEnum.Next(1, ModeInfo, @NumFound); 
if assigned(fpModeInfo) then 
{если fpModeInfo не равен nil} 
dispose(fpModeInfo); 
new(fpModeInfo); 
fpModeInfo^:=ModeInfo; 
{загружаем движок по его GUID} 
aTTSEnum.Select(fpModeInfo^.gModeID, fITTSCentral, IUnknown(fIAMM)); 
except 
end;
end;

Ну и все, теперь следует сказать, что "механизм чтения" приводится в действие следующим образом:

procedure TForm1.SpeakClick(Sender: TObject);
var 
SData: TSData; 
BufRich: string;
begin 
if not assigned(fITTSCentral) then 
begin 
ShowMessage('Не выбран движок!'); 
exit; 
end;

{Этот текст будет прочитан} 
 BufRich:='Это текст!'; 
SData.dwSize := length(BufRich) + 1; 
SData.pData := pChar(BufRich);
try
fITTSCentral.TextData(CHARSET_TEXT, 0, SData, nil, IID_ITTSBufNotifySink); 
except
 end;
end;

Подставляйте в BufRich все что угодно, содержание этой строки и будет синтезироваться в речь!

Для полного счастья не хватает приостановки чтения, то есть паузы, и полной остановки. Так вот осуществить это можно с помощью следующих методов:

 
...
{Пауза в чтении}
 fITTSCentral.AudioPause; 

{Восстановление чтения после паузы}
 fITTSCentral.AudioResume; 

{Полная остановка чтения}

 fITTSCentral.AudioReset; 
 ...

Остальные процедуры на кнопочки чтения, паузы и стоп, думаю, вы сами нафантазируете, а чтобы получить полный исходный текст проекта воспользуйтесь этой ссылкой(около 226Кб)


SAPI в Delphi (часть 2)



Распространение материалов сайта означает, что распространитель принимает условия лицензионного соглашения.
Идея и реализация: © Владимир Довыденков и Анатолий Камынин,  2004-2017
Rambler's Top100