Pull to refresh

text2wave из комплекта Festival в FreeBSD

Reading time 4 min
Views 6.8K
Доброго вам времени суток.

В данной статье хотелось бы рассмотреть грабли в виде скрипта text2wave из комплекта системы для генерации голоса Festival в FreeBSD. Столкнулся я с этой проблемой при создании голосового меню в Asterisk средствами Festival.

Кому интересно под кат.

Интро

Занимаясь, для собственного развития, развертыванием IP-АТС Asterisk, дошел до момента генерации голоса. Учитывая встроенную поддержку Festival и огромное количество инструкций доступных в интернете, взялся за дело. Установил Festival из портов. Скачал и установил русский голос. Накидал менюшку командой Festival(), и, о чудо, все заработало. Вот так вот сходу, как это редко бывает.

Проблема возникла с мобильными клиентами. X-lite на WinCE и встроенный клиент от Nokia упорно не желали рабостать с получившимся меню. Первый рвал сессию сразу, второму удавалось получить пару слогов, после чего и он тоже отваливался.

Непродолжительные поиски указали альтернативу использованию команды Festival() в диалплане. Это был вызов через AGI или через System() скрипта text2wave, сохранение с его помощью файла, а после проигрывание его с помощью комманд Playback() или Background(). Вооружившись парой инструкций я немедленно приступил к действию и тут то и получил граблями.

[root@AsteriskPV:/usr/local/share/festival/examples]# cp text2wave /usr/local/bin/
[root@AsteriskPV:/usr/local/share/festival/examples]# rehash
[root@AsteriskPV:/usr/local/share/festival/examples]# text2wave

WARNING
No default voice found in ("/usr/ports/audio/festival/work/festival/lib/voices/")
either no voices unpacked or voice-path is wrong
Scheme interpreter will work, but there is no voice to speak with.
WARNING


Грабли


Думаю, как так… ведь есть же голос, работает нормально…

^C
[root@AsteriskPV:/usr/local/share/festival/examples]# text2wave

WARNING
No default voice found in ("/usr/ports/audio/festival/work/festival/lib/voices/")
either no voices unpacked or voice-path is wrong
Scheme interpreter will work, but there is no voice to speak with.
WARNING


Присматриваюсь внимательнее, и понимаю, что как то не оттуда цепляет он голоса. Лезу в скрипт и нахожу там чудесную строчку

#!/bin/sh
"true" ; exec /usr/ports/audio/festival/work/festival/bin/festival --script $0 $*

То есть ссылается он на папку в которой собирался. Ну думаю делов то, и правлю

#!/bin/sh
"true" ; exec /usr/local/bin/festival --script $0 $*


Запускаем
[root@AsteriskPV:/usr/local/share/festival/examples]# text2wave
SIOD ERROR: unbound variable : P▒

и обламываемся.

В общем надо отметить, что данную картину я наблюдал большую часть дня. Тащить скрипт из инструкций оказалось более чем бесполезно, во FreeBSD он работать не будет. Равно как и предлагаемый метод запуска Festival в режиме сервера. Так что, все как всегда, берем десяток инструкций и при помощи напильника заставляем рабоать. Впрочем продолжаем.

После довольно продолжительного ковыряния и слепого тыканья, пришло понимание из папки work — работает, из /usr/local/bin — нет.

Простое сравнение показало проблему.
[root@AsteriskPV:/usr/local/share/festival/examples]# ll /usr/local/bin/festival
-r-xr-xr-x 1 root wheel 132 Nov 24 20:27 /usr/local/bin/festival


[root@AsteriskPV:/usr/local/share/festival/examples]# ll /usr/ports/audio/festival/work/festival/bin/festival
lrwxr-xr-x 1 root wheel 57 Nov 24 20:25 /usr/ports/audio/festival/work/festival/bin/festival -> /usr/ports/audio/festival/work/festival/src/main/festival


Скрипт запуска и сслыка на исполняемый файл. Результаты естественно разные. Ну что ж, полезем в скрипт.

[root@AsteriskPV:/usr/local/share/festival/examples]# cat /usr/local/bin/festival
#!/bin/sh
# path for audsp
PATH=/usr/local/libexec:$PATH
export PATH
exec festival.naked --libdir /usr/local/share/festival/lib $*


Мысленно склеиваем скрипты для запуска Festival и для генерации файлов при помощи него text2wave.
Получаем следующую команду
/usr/local/libexec/festival.naked --libdir /usr/local/share/festival/lib $* --script $0 $*
Любые попытки и комбинации двух этих опций приводят к уверенному результату.
[root@AsteriskPV:/usr/local/share/festival/examples]# /usr/local/libexec/festival.naked --libdir /usr/local/share/festival/lib --script text2wave $*
SIOD ERROR: unbound variable : P▒


Если убрать первый параметр, отваливается голос, если второй голос есть но Festival грузится в обычном интерактивном режиме.

Решение

Решение было очевидным, однако реализация так же заняла некоторое время. итогом стала небольшая модификация скрипта text2wave

"true" ; exec /usr/ports/audio/festival/work/festival/bin/festival --script $0 $*

меняем на
"true" ; exec /usr/local/libexec/festival.naked --script /usr/local/bin/text2wave $*


а
(load (path-append libdir "init.scm"))
меняем на
(set! libdir '/usr/local/share/festival/lib)
(load (path-append libdir "init.scm"))


Вот собственно и все. Теперь можно запускать
echo 123 | text2wave -o 123.ulaw -otype ulaw -
Ну и естесствено вызывать, хоть из System() хоть из AGI.
Как и всегда решение оказалось очевидным и простым, достаточно присмотреться.

Постскриптум №1.
В процессе поисков, было обнаружено решение для связки * и Festival, и мэйлинг лист эдинбургского университета.
Это выдержка из мейлинг-листов, перепосченная в десятке мест, очевидно это было лучшее решение которое нашли.

(Parameter.set 'Audio_Method 'Audio_Command)
(Parameter.set 'Audio_Required_Rate 11025)
(Parameter.set 'Audio_Required_Format 'riff)
(Parameter.set 'Audio_Command "lame --quiet --preset voice $FILE - >> $HOME/festival-output.mp3")


Постскриптум №2.
Для запуска Festival в режиме сервера используется довольно спорная связка со screen.
Выглядит она примерно так:
[root@SIP:/home/admin]# cat /usr/local/etc/rc.d/festival
#!/bin/sh

. /etc/rc.subr

name="festival"
start_cmd="${name}_start"
stop_cmd=":"

festival_start()
{
screen -d -m -s /usr/local/etc/festivalst.sh
}

festival_stop()
{
killall festival.naked
killall screen
}

festival_restart()
{
killall festival.naked
killall screen
screen -d -m -s /usr/local/etc/festivalst.sh
}

#load_rc_config $name
run_rc_command "$1"
[root@SIP:/home/admin]# cat /usr/local/etc/festivalst.sh
festival --server
Tags:
Hubs:
+4
Comments 3
Comments Comments 3

Articles