Не так давно (26 марта 2010 года) я рассказывал Вам о том, как применить технологию Text-To-Speech (чтение текста голосом) в Delphi 2010 с использованием Speech API (SAPI) Windows. И всё бы было хорошо, если б не одно маленькое, но суровое "НО". Дело в том, что при запуске проекта не из IDE Delphi вызов метода Speak у интерфейсов IspVoice и ISpeechVoice вызывал ошибку "Floating Point Division By Zero" (деление на ноль). При этом в Windows XP программа работала без проблем. Ошибку эту обнаружил читатель с ником ziz.
В поисках решения проблемы я решил немного расширить статью и рассмотреть ещё несколько моментов по работе с технологией Text-To-Speech в Delphi. Сегодня рассмотрим работу SAPI 5.4. с использованием объекта TspVoice. Так что импортируйте библиотеку SAPI 5.4. для Windows 7, генерируйте модуль SpeechLib_TLB.pas, как это рассказано в предыдущем посте и начнем.
Вначале реализуем чтение голосом какого-либо отрывка текста с использованием класса TspVoice.
var gpIVTxt: TSpVoice; begin gpIVTxt:=TSpVoice.Create(nil); gpIVTxt.Speak('Hello',SVSFlagsAsync); end;
Здесь мы используем асинхронный вывод. К слову сказать, синхронный вывод от асинхронного отличается тем, что асинхронный вывод используется в случае, когда в процессе синтеза речи программа должна выполнять какие-то дополнительные действия (подсвечивать синтаксис, обрабатывать данные в потоке и т.д.). В Windows 7 мне так и не удалось реализовать синхронный вывод (флаг SVSFDefoult) и с чем это связано пока сказать не могу. У кого-нибудь есть идеи на этот счёт?
Так что пока будем использовать везде асинхронный вывод.
Двигаемся дальше и попробуем изменить свойства голосового движка.
Характеристики голоса
Любой голосовой движок, использующий SAPI имеет следующие характеристики:
Volume - громкость голоса. Целочисленное значение. Изменяется линейно в диапазоне от 0 до 100. То есть значение 50 будет соответствовать половине предельной громкости используемого голоса.
Rate - скорость воспроизведения текста голосом. Может принимать значения от -10 до 10. Значение по умолчанию 0. Соответственно отрицательные значение характеристики замедляют произношение, положительные - ускоряют. SAPI 5-х версий не поддерживают значения Rate больше 10 или меньше -10, т.е. если Вы устанавливаете значение Rate=11, то голос будет воспроизводиться на скорости 10.
Попробуем реализовать изменение характеристик голоса в нашей программе. Разместим на форме два компонента TrackBar и 2 Label как показано на рисунке:

Соответственно первый TrackBar будет изменять громкость от 0 до 10, а второй - скорость от -10 до 10.
Теперь перенесем переменную gpIVTxt: TSpVoice в секцию public класса TForm1 и будем создавать класс TspVoice в момент создания формы, т.е.:
procedure TForm1.FormCreate(Sender: TObject); begin gpIVTxt:=TSpVoice.Create(nil); end;
Обработчики OnChange у TrackBar'ов будут следующими:
procedure TForm1.TrackBar1Change(Sender: TObject); begin VolumeLabel.Caption:=IntToStr(TrackBar1.Position); gpIVTxt.Volume:=TrackBar1.Position; end; procedure TForm1.TrackBar2Change(Sender: TObject); begin RateLabel.Caption:=IntToStr(TrackBar2.Position); gpIVTxt.Rate:=TrackBar2.Position; end;
Теперь запустите приложение и попробуйте изменять значение Rate и Volume во время произношения фразы. Т.к. используется асинхронный вывод, то характеристики голоса изменяются "на лету".
Английский голос - это конечно здорово, но как быть с русскими голосами в SAPI? Посмотрим как можно использовать русскоязычные движки в своей программе.
SAPI и русские голоса.
В качестве русскоязычного движка я выбрал движок от Acapela Group c названием "Алёна". Неплохой движок с пробным периодом в 30 дней. Какой движок выберите Вы - значения не имеет, т.к. работать мы будем с SAPI не влезая в особенности каждого движка, т.е., следуя схеме:

Будем использовать два верхних уровня.
Итак, для того, чтобы получить сведения о всех голосовых движках, установленных в системе, нам понадобится воспользоваться интерфейсом ISpeechObjectTokens, который имеет всего одно свойство Count - количество голосовых движков, установленных в системе. И один метод:
Item(i:index):ISpObjectToken
возвращающий элемент коллекции ISpeechObjectTokens. Для того, чтобы перечисли все движки в системе, можно воспользоваться следующей процедурой:
public ... Voices:ISpeechObjectTokens; ... procedure TForm1.GetMyVoices(List: TListBox); var i:integer; begin List.Clear; Voices:=gpIVTxt.GetVoices('',''); for i:=0 to Voices.Count - 1 do List.Items.Add(Voices.Item(i).GetDescription(0)); end;
Здесь мы вначале запрашиваем методом GetVoices все голоса поддерживаемые объектом TspVoice. И затем выводим в ListBox описания голосов. Результат будет выглядеть следующим образом:

Теперь мы можем назначить нашему объекту голос, например так:
gpIVTxt.Voice:=Voices.Item(0);
В этом случае будет использоваться голос "Anna (English)". А так:
gpIVTxt.Voice:=Voices.Item(1);
Голос "Alyona (Ruusian)".
При этом для нас нет разницы какой из голосов мы используем - русский или английский, встроенный в систему или скачаный с какого-нибудь варезника и установленный вручную - подход к управлению один и тот же (см. схему).
Для того, чтобы вывести сведения о голосов ListBox мы использовали в качестве данных - описание голоса. Кроме этого, каждый голос в системе может содержать следующие полезные атрибуты:
- Name - имя;
- Gender - пол;
- Age - возраст;
- Language - язык;
- Vendor - создатель;
Для того, чтобы получить значения какого-либо атрибута необходимо воспользоваться методом ISpeechObjectToken:
function GetAttribute(const AttributeName: WideString): WideString;
Допишем наше приложение таким образом, чтобы при выборе голоса в ListBox нам показывались все доступные свойства голоса. В моей программе это делается следующим образом:
procedure TForm1.ListBox1Click(Sender: TObject); begin Label7.Caption:=Voices.Item(ListBox1.ItemIndex).GetAttribute('Name'); Label8.Caption:=Voices.Item(ListBox1.ItemIndex).GetAttribute('Age'); Label9.Caption:=Voices.Item(ListBox1.ItemIndex).GetAttribute('Gender'); Label12.Caption:=Voices.Item(ListBox1.ItemIndex).GetAttribute('Language'); Label13.Caption:=Voices.Item(ListBox1.ItemIndex).GetAttribute('Vendor'); end;
А в запущенном приложении так:

Использовать значения атрибутов можно, например, при получении списка голосов. При этом строка поиска должна иметь следующий формат:
AttributeName=Value AttributeName!=Value
Следующие два вызова метода GetVoices абсолютно идентичны и в результате вернут 2 установленных в моей системе голоса:
Voices:=gpIVTxt.GetVoices('Gender=female',''); Voices:=gpIVTxt.GetVoices('Gender!=male','');
Ну и в заключение, выкладываю исходники, рассмотренного в статье приложения. Качайте:
Обзор Интернет-магазинов Рунета
Сегодня Интернет представляет собой не только какую-то виртуальную реальность, но и вполне удобный рынок товаров и услуг самого широкого спектра. ас уже не удивляют такие вещи как Интернет-аукционы или интернет-магазины, где можно купить или продать абсолютно всё - от шариковой ручки до загородного дома. Кстати, о домах и интернет-магазинах, недавно обнаружил специализированный интернет-магазин Ceramica-Classic, занимающийся продажей керамической плитки и отделочных материалов в Интернет. Так что, если Вас интересует, например, итальянская керамическая плитка, то не стоит бежать сразу в магазин - достаточно обратиться к ceramica-classic.ru и оформить заказ.
-----------------------
| Делись! | Загружай! | Плюсуй! |
| | |









05 мая 2010 в 10:40 пп
спасибо что помог)
офигенная статья, блог, и знания delphi)
05 мая 2010 в 11:33 пп
мануал по установке алёны)
12 Июл 2010 в 7:39 дп
Спасибо за метериал. Очень помог!
29 Сен 2010 в 8:53 пп
А у меня наоборот,
gpIVTxt.Speak(‘Hello’,SVSFlagsAsync);
с ассинхроном на 7 проблемы, а с Default все отлично работает
18 Окт 2010 в 3:40 пп
Почему-то при компиляции вашего исходника у меня вылезает сообщение об отсутствии SAPIEngineLib_TLB.dcu Обыскал весь компьютер! Нету у меня не SAPIEngineLib_TLB.dcu не SAPIEngineLib_TLB.pas
p.s Есть только SpeechLib_TLB.pas и SpeechLib_TLB.dcu
18 Окт 2010 в 3:41 пп
Да, забыл сказать, у меня Win7 и Delphi 2010
18 Окт 2010 в 6:00 пп
Импортировать его надо.
24 Окт 2010 в 12:48 дп
А как его импортировать?
24 Окт 2010 в 1:36 дп
Как обычную библиотеку типов. Через меню «Component — Import Component»
04 Ноя 2010 в 3:33 пп
Так я ее имопортировал, но у меня появляется только SpeechLib_TLB, а он требует еще SAPIEngineLib_TLB. Скиньте мне пожалуйста его на wlad-mozg@yandex.ru если вас не затруднит.
18 Ноя 2011 в 4:53 дп
Какую именно библиотеку импортировать? Speech 5.4 импортировал, но у меня тоже самое, как и у Xatrix нет SAPIEngineLib_TLB.
18 Ноя 2011 в 11:20 дп
Oleg, у меня только Speech 5.4 и *_tlb.pas тоже есть. При импорте библиотеки галку ставите на создание обертки для библиотеки? А созданный файл сохраняете куда-то?
18 Ноя 2011 в 2:11 пп
И галку ставлю и сохраняю.