喋るgauche

今、matzさんが書いた 背広本を読んでいる。背広本って、仲間内の隠語だけれど、分かるよね。 「まつもとゆきひろ コードの世界」が正式タイトルだ。

こういう呼び方は、ラクダ本に端を発していると記憶している。にしき蛇も居たなあ。つるはし 本もあったなあ。英語で言う方が通りが良いか。ピッケル本だな。

悪魔本なんてのもあるなあ。通りが悪かったら SICP、「計算機プログラムの構造と解釈」こちらは、 新(和田先生訳の2版)旧(上下2冊セット)合わせて持っている。

更に有名なのが、ドラゴンブック。こちらは、最初からチャレンジ出来ないと分かっていたので、 さすがに買うのは控えてました。

Gaucheをやるなら、ふぐ本だな。こうして見ると、表紙と言語(分野)が、リンク出来そうで 出来ない感じがする。

よく、言語を○○に例えると、と言うのがあって、最近では、schemeを天使に例えた人がいた。 近寄りがたいと感じられたようだけど、私はschemeが一番身近に感じるなあ。

しつこく音声合成をば

まずは、合成と対になる音声認識でお笑いをば 商業版なら、もう少しましなものと思っていたけど、、、理解出来るのは、wait,sit,run だけ だったら、お犬様だなあ。がんばって、10月27日(だったかな)を目指してください。

あれから、しつこく音声合成を探していたら、音声合成で Hellow, world にいきついた。

我らがエース小黒さんもc-wrapperを引っさげて、参戦されている。 面白そうなので、入れてみようかな。まてまて、それより先に、FreeBSDにも喋って貰わねば。 Windowsしか動きませんなんてのでは、非常に不愉快だからだ。

それにしても、皆さん、sayで 喋らせるんですね。perl6は、デフォがsayだったように記憶してるんで、いいのかな? ラリーおじさんは、print より say の方が、タイプするのが簡単とか言って、sayを採用したと 記憶してます。(違ってたら、スマソ)

BSDで使える音声合成エンジン

一つは、唇が悩ましいeSpeak もう一つは、歴史があり そうな Festival。どちらも、ports/audioに 入っていました。

Festivalの方は、英語、イタリア語、メキシコ語をサポートしてるようです。eSpeakは英語 のみですね。ちょいと実行するだけなので、簡単(と思われる)eSpeakを入れてみました。

eSpeak

manは無かったので、あたりを付けて

[sakae@fb ~]$ espeak -h

eSpeak text-to-speech: 1.40  22.Dec.08

speak [options] ["<words>"]
  ....
-k <integer>
           Indicate capital letters with: 1=sound, 2=the word "capitals",
           higher values = a pitch increase (try -k20).
[sakae@fb ~]$ espeak -h | espeak --stdin

最後の行は、自身の説明書を自分自身に喋らせる例です。こういうのも、再帰と言うので しょうか? 説明書によると、ファイルを指定して読み上げさせたり、読み上げさせる変わりに、waveファイルに 落としたりできるようです。実際にやってみると、

[sakae@fb ~]$ ls -l say.man
-rw-r--r--  1 sakae  kuma  572 Jul  8 12:02 say.man
[sakae@fb ~]$ file say.man
say.man: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 22050 Hz

必要十分ですね。

喋るgauche

さて、材料は揃いました。小黒さんの c-wrapper版

(use objc-wrapper)

(c-load "Cocoa/Cocoa.h"
        :libs "-framework Foundation -framework Cocoa")

[[NSAutoreleasePool :alloc] :init]

(define say 
  (let1 s [[NSSpeechSynthesizer :alloc] :init]
    (lambda (str)
      [s :startSpeakingString (@ str)])))

(say "Hello, world")

より、短く書けるかな? (あのー、golf じゃないんですから、無理しなくてもいいよ)

(define (say s)
  (sys-system #`"espeak ,s"))

(say "hello world")

あれ、こんなに簡単だったかなあ?

schemeのソースを読み上げる時、"(" は、カッコと ")"は、コッカと読み上げて欲しいんだ けど、どうしたら良いだろう? gauche側で、espeakに渡す前に、変換しちゃうのがいいか、 espeak側で、"("を、カッコと発声させるのがいいか。悩むなあ。

気楽に構えていたら、こういうのはエラーに落ちるよ。

gosh> (say "Hellow world")
0
gosh> (say "hello (sakae)san")
Syntax error: "(" unexpected
512

何処に落とし穴が潜んでいるやら?

Say Yes じゃなくて、say me

そんじゃ、こんなのはどうだろう?

(define (say s . opt)
  (let-optionals* opt ((file-opt ""))
    (sys-system #`"espeak ,file-opt ,s")))
gosh> (say "spk.scm" "-f")
0

省略可能な第二引数に、"-f" を指定すると、第一引数をファイル名と解釈して、読み上げる やつだ。これなら、カッコを含んでいてもへっちゃらだい。って、超カッコ悪いぞ!!

でも、冷静に上記のエラーを見ると、512 って何よ? gauche が出しているエラーじゃ無い よね。shell側のエラーだよ、きっと!

[sakae@nil ~]$ espeak hellow world
[sakae@nil ~]$ echo $?
0
[sakae@nil ~]$ espeak hellow (sakae)san
-bash: syntax error near unexpected token `('
[sakae@nil ~]$ echo $?
258

ピンポン。ここまで分かれば

(define (say s . opt)
  (let-optionals* opt ((file-opt ""))
    (sys-system #`"espeak ,file-opt ',s'")))

これで大丈夫。微妙な穴だったよ。後は、みっともないオプションを直しておこう。

(define (say s . opt)
  (let-optionals* opt ((file ""))
    (when (keyword? file) (set! file "-f"))
    (sys-system #`"espeak ,file ',s'")))
gosh> (say "spk.scm" :file)
0