カイワレスタイル

ゲーム、アニメ、プログラム、興味のあることをツラツラと。

Raspberry Pi 2を喋らせる

今回は音声合成を試してみた。


音を鳴らすには

デフォルトでは音声はHDMI出力になっているらしい。
普段Macからターミナルで操作しているので、そのままでは音が鳴らない。
音声の出力先をRaspberry Pi 2本体のオーディオ端子に変更した。

$ amixer cset numid=3 1

amixer cset numid=3 1の1がオーディオ端子で2HDMI端子らしい。
オーディオ端子にスピーカーを接続し、音が出るか確認。

$ aplay /usr/share/sounds/alsa/Front_Center.wav

喋らせる準備

Raspberry piで音声合成するソフトは、AquesTalkとOpen-jtalkの2つが有力らしいが、個人的にゆっくりボイスが好きなので、それに近いAquesTalkの方を選んだ。

下記サイトからダウンロードする

AquesTalk Pi - Raspberry Pi用の音声合成

raspberry piから直接ダウンロードできなかったので、
macのブラウザで表示し、利用規約に同意してダウンロードした。

ダウンロードしたファイルをscpコマンドでraspberry piに転送。

$ scp [ダウンロードした場所]/aquestalkpi-20130827.tar.gz [アカウント名]@[raspberry piのIPアドレス]:~/

aquestalkpiを解凍

$ tar xzvf aquestalkpi-20130827.tar.gz
$ cd aquestalkpi

とりあえず喋らせてみる

$ ./AquesTalkPi "ゆっくりしていってね!" | aplay

今回は、定型文を喋らせたかったので、ファイル化してプログラムから呼び出すことにした。
まずwavファイルとして出力する。

$ ./AquesTalkPi -b "ザッケンナコラー!" -o yakuza01.wav
$ ./AquesTalkPi -b "スッゾコラー!" -o yakuza02.wav
$ ./AquesTalkPi -b "チェラッコラー!" -o yakuza03.wav
$ ./AquesTalkPi -b "テメッコラー!" -o yakuza04.wav
$ ./AquesTalkPi -b "ドグサレッガー!" -o yakuza05.wav
$ ./AquesTalkPi -b "イヤーーーッ!" -o IYA01.wav
$ ./AquesTalkPi -b "グワーーーッ!" -o GUWA01.wav

c言語からwavファイルを鳴らすには、直接aplayコマンドを呼べばいいと思い、systemコマンドで呼ぶことにした。
systemコマンドに渡す文字列引数の末尾に"&"を付けておけば、シェルと同様に終了を待たずに実行されるのが面白い。


プログラム

#include <iostream>
#include <iomanip>
#include <vector>
#include <cstdio>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/joystick.h>
#include <stdlib.h>

#define JOY_DEV "/dev/input/js0"

using namespace std;

int main() {
    int joy_fd(-1), num_of_axis(0), num_of_buttons(0);
    char name_of_joystick[80];
    vector<char> joy_button, joy_button_old;
    vector<int> joy_axis;
        
    const char *talkdata[] = {
        "aplay -q yakuza01.wav &",
        "aplay -q yakuza03.wav &",
        "aplay -q yakuza04.wav &",
        "aplay -q yakuza05.wav &",
        "aplay -q yakuza06.wav &",
        "aplay -q IYA01.wav &",
        "aplay -q GUWA01.wav &",
        "date +\"現在%m月%d%p%I時%M分%S秒ダッコラー!\" | ./AquesTalkPi -f -  | aplay -q &",
    };

    if((joy_fd = open(JOY_DEV, O_RDONLY)) < 0) {
        printf("Failed to open %s", JOY_DEV);
        cerr << "Failed to open " << JOY_DEV << endl;
        return -1;
    }

    ioctl(joy_fd, JSIOCGAXES, &num_of_axis);
    ioctl(joy_fd, JSIOCGBUTTONS, &num_of_buttons);
    ioctl(joy_fd, JSIOCGNAME(80), &name_of_joystick);

    joy_button.resize(num_of_buttons, 0);
    joy_axis.resize(num_of_axis, 0);
    
    joy_button_old.resize(num_of_buttons);

    printf("Joystick: %s axis: %d buttons: %d\n", name_of_joystick, num_of_axis, num_of_buttons);

    fcntl(joy_fd, F_SETFL, O_NONBLOCK); // using non-blocking mode

    while(true) {
        js_event js;

        read(joy_fd, &js, sizeof(js_event));

        switch(js.type & ~JS_EVENT_INIT) {
            case JS_EVENT_AXIS:
                joy_axis[(int)js.number] = js.value;
                break;
            case JS_EVENT_BUTTON:
                joy_button_old[(int)js.number] = joy_button[(int)js.number];
                joy_button[(int)js.number] = js.value;
                break;
        }
        
        for(int x=0 ; x<num_of_buttons ; ++x ) {
            if (( joy_button[x] == 1 )&&( joy_button_old[x] == 0 )) {
                if ( x < 9 ) {
                    printf("button[%d] on speak %s\n", x, talkdata[x]);
                    system(talkdata[x]);
                }
            }
        }

        usleep(100);
    }

    close(joy_fd);
    return 0;
}

せっかく自由に喋らせられるので、申し訳程度に現在時刻も喋らせるようにした。
aplayコマンドは同時に複数の音声が再生できるが、あまり同時リクエスト数が多いとエラーがでる模様。


音量調整

100均のスピーカーを繋いで再生させてみたが、音が小さすぎて聞こえない!
音量調整はalsamixerというコマンドで行う。

$ alsamixer

f:id:kaiware007:20150712231955p:plain

カーソルキーの上下で音量調整ができる。
ESCで設定して終了。
初期値が40%だったので70%にしてみたがまだ小さかった。
思い切って100%にしたら少しマシになった。
100均で買ったスピーカーだからだろうか…。


動作確認

ラズパイ喋らせてみた

音が出ると
楽しい! ✌ ('ω' ✌ )三 ✌ ('ω') ✌ 三( ✌ 'ω') ✌


参考資料

http://nwpct1.hatenablog.com/entry/2013/10/12/222115