Как оказывается, весь функционал этой системы и пакет разнообразных голосов доступны также из командной строки, через встроенную утилиту say. Ее можно проверить следующей командой:
$ say "You never knew I could talk to you, did you?"
Мы знали, что вам это понравится!
С этой программой можно сделать много чего, но для начала напишем сценарий-обертку, который поможет выявить установленные голоса и послушать, как они звучат. Сценарий в листинге 13.10 не заменяет команду say; он лишь упрощает работу с ней (обычное дело для подобных сценариев в этой книге).
Код
Листинг 13.10. Сценарий sayit
#!/bin/bash
# sayit — использует команду "say" для всего, что будет указано (только для OS X).
dosay="$(which say) −quality=127"
format="$(which fmt) −w 70"
voice="" # По умолчанию системный голос.
rate=""··# По умолчанию стандартная скорость произношения.
demovoices()
{
··# Предлагает прослушать произношение каждым доступным голосом.
··voicelist=$(say −v \? | grep "en_" | −c— c1-12 \
····| sed 's/ /_/;s/ //g;s/_$//')
··if ["$1" = "list"]; then
····echo "Available voices: $(echo $voicelist | sed 's/ /, /g;s/_/ /g') \
······| $format"
····echo "HANDY TIP: use \"$(basename $0) demo\" to hear all the voices"
····exit 0
··fi
··for name in $voicelist; do
····myname=$(echo $name | sed 's/_/ /')
····echo "Voice: $myname"
····$dosay −v "$myname" "Hello! I'm $myname. This is what I sound like."
··done
··exit 0
}
usage()
{
··echo "Usage: sayit [-v voice] [-r rate] [-f file] phrase"
··echo " or: sayit demo"
··exit 0
}
while getopts "df: r: v: " opt; do
··case $opt in
····d) demovoices list··;;
····f) input="$OPTARG"··;;
····r) rate="-r $OPTARG";;
····v) voice="$OPTARG"··;;
··esac
done
shift $(($OPTIND — 1))
if [$# −eq 0 −a — z "$input"]; then
··$dosay "Hey! You haven't given me any parameters to work with."
··echo "Error: no parameters specified. Specify a file or phrase."
··exit 0
fi
if ["$1" = "demo"]; then
··demovoices
fi
if [! -z "$input"]; then
··$dosay $rate −v "$voice" −f $input
else
··$dosay $rate −v "$voice" "$*"
fi
exit 0
Как это работает
В действительности в системе установлено больше голосов, чем указано в сводке (просто здесь перечислены голоса, оптимизированные для английского языка). Чтобы получить полный список, выполните оригинальную команду say с параметрами −v \?. Ниже приводится сокращенная версия полного списка голосов:
$ say −v \?
Agnes······en_US··# Разве не прекрасно иметь компьютер, который говорит с вами?
Albert···· en_US··# В моем горле живет лягушка. Да, самая настоящая лягушка!
Alex······ en_US··# Многие узнают меня по голосу.
Alice······it_IT··# Привет, меня зовут Алиса, я говорю по-итальянски.
-опущено-
Zarvox···· en_US··# Это похоже на мирную планету.
Zuzana···· cs_CZ··# Добрый день, меня зовут Сюзанна. Я говорю по-чешски.
$
Наши любимые дикторы — Пайп Орган (Pipe Organ, «Мы должны радоваться этому болезненному голосу») и Зарвокс (Zarvox, «Это похоже на мирную планету»).
Очевидно, что на выбор дается очень много голосов. Плюс, у некоторых из них очень неправильное английское произношение. Одно из решений этой проблемы — фильтровать дикторов по "en_" (или другому языку по вашему выбору), чтобы получить только голоса с нужным произношением. Для выбора американского английского языка можно использовать фильтр "en_US", но другие английские голоса тоже стоит послушать. Полный список голосов извлекается в строке .
Мы добавили в конец блока сложную череду подстановок с помощью sed, потому что этот список построен не совсем правильно: он включает имена, состоящие из одного (Fiona) и из двух слов (Bad News), а также дополнительные пробелы для выравнивания вывода по колонкам. Чтобы решить эту проблему, первый пробел в каждой строке заменяется символом подчеркивания, а все остальные пробелы удаляются. Если имя голоса состоит из одного слова, оно будет выглядеть так: "Ralph_", и заключительная подстановка sed удалит любые завершающие подчеркивания. В конце процесса остаются имена из двух слов с подчеркиванием, поэтому их нужно исправить перед выводом на экран. Однако код имеет интересный побочный эффект, в результате которого цикл while проще написать, использовав в качестве разделителя пробел.