В этой статье мы познакомимся с программированием речи в Delphi. Хотите чтобы Delphi заговорил — читайте эту страницу!
Нудеюсь, что вы уже установили пакет функций Speech API и хотя бы один речевой движок. Речевые движки — это те модули, которые синтезируют речь. Для доступа к ним нужно использовать специальные функции, которые описаны в наборе функций Speech API. Поэтому для того, чтобы написать минимальную программу умеющую говорить, нужны эти два компонента. Сначала мы попробуем написать как раз эту программу-минимум а потом заставим персонаж MS Agent заговорить. То есть постараемся совместить технологию MSAgent и SpeechAPI. Тогда агент станет еще более приятным.
Ну, а для того чтобы всем эти заняться нам потребуется полезный модулек speech.pas, в котором объявлены полезные константы, типы, функции и интрефейсы. Не забудьте подключить его в разделе uses главного модуля приложения.
Попытаемся создать программу, где мы будем вводить текст для чтения в редакторе, выбирать движок для чтения в ComboBox’е и пару кнопок для чтения, паузы и остановки.
Объявим в секции private нужные для работы переменные:
1 2 3 4 5 6 7 8 9 10 | private { Private declarations } fITTSCentral: ITTSCentral; {Центральный интерфейс, через который производятся все действия с речью} fIAMM: IAudioMultimediaDevice; {Интерфейс для связи с аудиоустройством} aTTSEnum: ITTSEnum; {Интерфейс для перебора движков} fpModeInfo: PTTSModeInfo; {Указатель на параметры движка} |
Во ходе создания главной формы приложения нам нужно проверить установленные движки в системе, и их названия поместить в ComboBox. Это мы и сделаем:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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’е:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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 ; |
Ну и все, теперь следует сказать, что «механизм чтения» приводится в действие следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 все что угодно, содержание этой строки и будет синтезироваться в речь!
Для полного счастья не хватает приостановки чтения, то есть паузы, и полной остановки. Так вот осуществить это можно с помощью следующих методов:
1 2 3 4 5 | ... fITTSCentral . AudioPause; {Пауза в чтении} fITTSCentral . AudioResume; {Восстановление чтения после паузы} fITTSCentral . AudioReset; {Полная остановка чтения} ... |
Остальные процедуры на кнопочки чтения, паузы и стоп, думаю, вы сами нафантазируете, а чтобы получить полный исходный текст проекта воспользуйтесь ссылочкой в конце страницы. Это пока все! Собираюсь в ближайшее время рассказать о том как работать с другими атрибутами чтения, такими как скорость, тон, громкость и т.д. Но это потом, а пока то ,что есть!