awk で喋らせてみる

404 Blog Not Found:perl - SayKanji + Yahoo API = itte.plsaykanjiコマンドを定義して漢字仮名混じり文を読み上げる - ザリガニが見ていた...。を見て、awk をラッパーとして喋らせてみようという試みです。 このマシンが Linux (Fedora) ということもあり、手元にインストールしてある mecab で解析を行い、espeak で喋らせてみます。

#! /usr/bin/gawk -f
# say_japanese.awk

BEGIN {
    echo_cmd   = "/bin/echo";
    mecab_cmd  = "/usr/bin/mecab";
    mecab_opt  = "";
    espeak_cmd = "/usr/bin/espeak";
    espeak_opt = "";

    str = ARGV[1];
    mecab_exec = echo_cmd " " str "|" mecab_cmd " " mecab_opt;
    while (mecab_exec | getline > 0) {
        split($2, arr_mecab, ",");
        num++;
        if ($1 ~ /[:alnum:]+/ && $2 != "") {
            arr_alpha[num] = $1;
        } else {
            arr_alpha[num] = yomi2alpha(arr_mecab[9]);
        }
    }
    close(mecab_exec);

    espeak_exec = espeak_cmd " " espeak_opt "'";
    for (i = 1; i <= num; i++) {
        espeak_exec = espeak_exec " " arr_alpha[i];
    }
    espeak_exec = espeak_exec "'";

    system(espeak_exec);
}

function yomi2alpha(str) {
    gsub("ッチャ", "tcha", str);
    gsub("ッチュ", "tchu", str);
    gsub("ッチョ", "tcho", str);
    gsub("ッチ", "tchi", str);
    gsub("キャ", "kya", str);
    gsub("キュ", "kyu", str);
    gsub("キョ", "kyo", str);
    gsub("シャ", "sha", str);
    gsub("シュ", "syu", str);
    gsub("ショ", "sho", str);
    gsub("チャ", "cha", str);
    gsub("チュ", "chu", str);
    gsub("チョ", "cho", str);
    gsub("ニャ", "nya", str);
    gsub("ニュ", "nyu", str);
    gsub("ニョ", "nyo", str);
    gsub("ヒャ", "hya", str);
    gsub("ヒュ", "hyu", str);
    gsub("ヒョ", "hyo", str);
    gsub("ミャ", "mya", str);
    gsub("ミュ", "myu", str);
    gsub("ミョ", "myo", str);
    gsub("リャ", "rya", str);
    gsub("リュ", "ryu", str);
    gsub("リョ", "ryo", str);
    gsub("ギャ", "gya", str);
    gsub("ギュ", "gyu", str);
    gsub("ギョ", "gyo", str);
    gsub("ジャ", "ja", str);
    gsub("ジュ", "ju", str);
    gsub("ジョ", "jo", str);
    gsub("ビャ", "bya", str);
    gsub("ビュ", "byu", str);
    gsub("ビョ", "byo", str);
    gsub("ピャ", "pya", str);
    gsub("ピュ", "pyu", str);
    gsub("ピョ", "pyo", str);
    gsub("ア", "a", str);
    gsub("イ", "i", str);
    gsub("ウ", "u", str);
    gsub("エ", "e", str);
    gsub("オ", "o", str);
    gsub("カ", "ka", str);
    gsub("キ", "ki", str);
    gsub("ク", "ku", str);
    gsub("ケ", "ke", str);
    gsub("コ", "ko", str);
    gsub("サ", "sa", str);
    gsub("シ", "shi", str);
    gsub("ス", "su", str);
    gsub("セ", "se", str);
    gsub("ソ", "so", str);
    gsub("タ", "ta", str);
    gsub("チ", "chi", str);
    gsub("ツ", "tsu", str);
    gsub("テ", "te", str);
    gsub("ト", "to", str);
    gsub("ナ", "na", str);
    gsub("ニ", "ni", str);
    gsub("ヌ", "nu", str);
    gsub("ネ", "ne", str);
    gsub("ノ", "no", str);
    gsub("ハ", "ha", str);
    gsub("ヒ", "hi", str);
    gsub("フ", "fu", str);
    gsub("ヘ", "he", str);
    gsub("ホ", "ho", str);
    gsub("マ", "ma", str);
    gsub("ミ", "mi", str);
    gsub("ム", "mu", str);
    gsub("メ", "me", str);
    gsub("モ", "mo", str);
    gsub("ヤ", "ya", str);
    gsub("ユ", "yu", str);
    gsub("ヨ", "yo", str);
    gsub("ラ", "ra", str);
    gsub("リ", "ri", str);
    gsub("ル", "ru", str);
    gsub("レ", "re", str);
    gsub("ロ", "ro", str);
    gsub("ワ", "wa", str);
    gsub("ヲ", "wo", str);
    gsub("ン", "n", str);
    gsub("ガ", "ga", str);
    gsub("ギ", "gi", str);
    gsub("グ", "gu", str);
    gsub("ゲ", "ge", str);
    gsub("ゴ", "go", str);
    gsub("ザ", "za", str);
    gsub("ジ", "ji", str);
    gsub("ズ", "zu", str);
    gsub("ゼ", "ze", str);
    gsub("ゾ", "zo", str);
    gsub("ダ", "da", str);
    gsub("ヂ", "ji", str);
    gsub("ヅ", "zu", str);
    gsub("デ", "de", str);
    gsub("ド", "do", str);
    gsub("バ", "ba", str);
    gsub("ビ", "bi", str);
    gsub("ブ", "bu", str);
    gsub("ベ", "be", str);
    gsub("ボ", "bo", str);
    gsub("パ", "pa", str);
    gsub("ピ", "pi", str);
    gsub("プ", "pu", str);
    gsub("ペ", "pe", str);
    gsub("ポ", "po", str);
    gsub("nb", "mb", str);
    gsub("nm", "mm", str);
    gsub("np", "mp", str);

    while (match(str, "ー")) {
        str = substr(str, 1, RSTART - 1) \
              substr(str, RSTART - 1, 1) substr(str, RSTART + 1);
    }

    while (match(str, "ッ")) {
        str = substr(str, 1, RSTART - 1) \
              substr(str, RSTART + 1, 1) substr(str, RSTART + 1);
    }

    gsub("oo", "o", str);
    gsub("ou", "o", str);

    return str;
}

カタカナをアルファベットに変更する yomi2alpha() 関数のダラダラさは仕方がないとしても、あまり awk らしさの感じられないものになってしまいました。

$ gawk -f say_japanese.awk 'あなたは English しゃべれますか?'

音声はespeak で wav に落として ffmpeg で MP3 に変換したものを置いておきますが、某ゆっくりよりも酷いです。 ネタは巡音ルカ と 英語でおしゃべり!‐ニコニコ動画(ββ)ですが、思ったように喋ってくれませんね。

tag_gawk.pngtag_gawk.png