LoginSignup
3

posted at

updated at

フリーソフト9VAeきゅうべえに音声合成機能をつけた

今回、9VAe Linux版にしゃべる機能を追加しました。

作成例>クリックすると Youtubeが開きます
0voice-kof.gif

ダウンロード 32bit
Linux-x86
64bit
Linux-x64
試し方
Linux Mint
Ubuntu
Intel(x86/x64)
32bit9va.png 64bit9va.png Windows用
Linux起動USBの作り方
ラズベリーパイ qva64x64.png 他のOS版
9VAe
  1. ZIPファイルをダウンロード(上をクリックしてから、[↓]ダウンロードボタン)
  2. Linux上で解凍
  3. フォルダの中の「9va-pi」を実行。9VAeが起動します。(Ubuntu、Mintでは動くはず。他のLinuxでは、9view(プレーヤー)しか起動しないものがあるようです)
    000-qva.svg.gif

開発方針

  • 9VAeは、1枚の絵に文字やイラストをいれて「ひとコマ」と設定するだけで、解説動画がつくれるのが特長です。
  • ひとコマアニメは、1枚絵を書いただけで、書いた順番に文字や、図形が再生されます。文字が1文字ずつ順番にでてくる動画がすぐ作れます。
  • この文字に「しゃべる」属性をつけるだけで、ゆっくり解説動画がつくれるようにします。
  • しゃべる声は、男声と女声の2種類とし、2人が会話しながら解説する動画がつくれること。
  • しゃべる声はユーザーがカスタマイズできるようにします。

わりきり仕様

  • 9VAe は、どんな環境(Win / Mac / iOS / iPad / Android / Linux / Amazon Fire / ラズベリーパイ)でも同じように動きます。異なる OS 間で 互換性があります。これはすごいことですが、これを実現するために、移植が難しい仕様はいれないのがポイント。しゃべる機能は以下のようにしました。
  • しゃべる声は、男声と女声の2種類
  • 同時にしゃべることはない。
  • 一度、しゃべりはじめると、最後まで、しゃべってから、次の発話がはじまる。
  • しゃべる速さ、ピッチ、音量はエンジンの設定にまかせる。これらの調整は、今後の課題とする。

この割り切り仕様で、無料で使えるものをさがし、Linux では、音声合成エンジン Open JTalk を使うことにしました。

実装に必要な機能

  • テキストをしゃべる
  • 今しゃべっているかどうか調べる
  • しゃべる音声をWAV ファイルに出力
  • 発声の中断

各OSで上の機能をみたす関数を用意すれば移植できそうです。

現在、Linux、Windows、Android/Chromebook、Macintosh に移植できています。上の機能を実現方法を表にまとめました。

OS 音声合成 WAV作成 中断 発声中チェック
Linux(日本語) OpenJTalk
(外部ツール)
-ow ファイルパス kill(pid, SIGKILL); waitpid(pid, &status, WNOHANG);
Linux(英語) eSpeak --stdout > 音声ファイル kill(pid, SIGKILL); waitpid(pid, &status, WNOHANG);
Windows(日本語) SofTalk
(外部ツール)
/PS:True /R:ファイルパス /W:しゃべる言葉 mciSendString("stop",,,) mciSendString("status",,,)
Windows(英語) eSpeak
(外部ツール)
-w 音声ファイル mciSendString("stop",,,) mciSendString("status",,,)
Android / Chromebook / Amazon Fire tts = new TextToSpeech(this, this); tts.synthesizeToFile(); tts.stop(); tts.speak()で発声追加。発声チェックはしない
Macintosh tts = [[NSSpeechSynthesizer alloc] init]; [tts startSpeakingString:しゃべる言葉 toURL:ファイルパス]; [tts stopSpeaking]; [tts isSpeaking];
iOS / iPad tts = [[AVSpeechSynthesizer alloc] init]; [tts writeUtterance:utterance toBufferCallback:]; [tts stopSpeaking]; [tts isSpeaking];

音声合成 Open JTalk

参考文献:Raspberry piで日本語音声合成(Open JTalk)を試してみる。

インストール方法(Linux)

$ sudo apt-get install open-jtalk
$ sudo apt-get install open-jtalk-mecab-naist-jdic
$ sudo apt-get install hts-voice-nitech-jp-atr503-m001

これで、男声でしゃべれるようになります。
コマンド入力するとき、数文字入力して、TABキーを押せば楽に入力できます。

女声のインストール方法

女性の声は Meiちゃんがよく使われているようです。

参考文献:OpenJTalkでおしゃべりする

$ wget https://sourceforge.net/projects/mmdagent/files/MMDAgent_Example/MMDAgent_Example-1.6/MMDAgent_Example-1.6.zip/download -O MMDAgent_Example-1.6.zip

$ unzip MMDAgent_Example-1.6.zip MMDAgent_Example-1.6/Voice/*
$ sudo cp -r MMDAgent_Example-1.6/Voice/mei/ /usr/share/hts-voice

音声コマンド

上のインストールを行ったあと、ターミナルで以下の命令をいれればしゃべりました。

  • テキストをしゃべる
$ echo 12345 | open_jtalk -m /usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice -x /var/lib/mecab/dic/open-jtalk/naist-jdic -ow test.wav
$ aplay test.wav

これで「いちまんにせんさんびゃくよんじゅうご」としゃべりました。12345の部分に UTF8 の文字をいれれば自由にしゃべります。

  • -ow 出力ファイル名 で、WAVファイルに出力できるようです。
  • aplay が WAVファイルを発声する命令です。-q オプションで表示が消えます。

参考文献:萌え声を探せ!Open JTalkのパラメータをいろいろ変化させてみた!

Linuxでの実装

  • 発声の中断、しゃべっているかどうかのチェック、しゃべり方の調整が行えるようにするために、「Open JTalk で WAV 作成する男声命令」「女声命令」を用意し、まず、WAVを作成することにしました。
talkman_jp.sh
#!/bin/sh
echo "$1" | open_jtalk -jm 1.2 -m /usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice -x /var/lib/mecab/dic/open-jtalk/naist-jdic -ow  /tmp/#9va_talk.wav && mv /tmp/#9va_talk.wav /tmp/9va_talk.wav

talkwoman_jp.sh
#!/bin/sh
echo "$1" | open_jtalk -m /usr/share/hts-voice/mei/mei_normal.htsvoice -x /var/lib/mecab/dic/open-jtalk/naist-jdic -ow /tmp/#9va_talk.wav  && mv /tmp/#9va_talk.wav /tmp/9va_talk.wav

まず、#9va_talk.wav というファイル名でWAVを作成し、出力後に 9va_talk.wavという名前に変更しています。名前固定がいまいちですが、わりきり仕様ということで・・・

この命令を読みだす部分は以下のようになってます。
作成した WAVファイルの再生は、Linuxでは「aplay」命令をつかっています。

AcGbl
#define TEXT_MAX_BUF 1024
#define aTALK_WAV_FILE "/tmp/9va_talk.wav" //Waveファイル
#define aTALK_WAV_CMD "aplay"  //Waveを再生する命令

typedef struct {
	pid_t  	pidMakeWav; 
	pthread_t thrMakeWav;
	char	prgMakeWav[600]; //jtalk を呼び出す Shell
	char	utf8Talk[TEXT_MAX_BUF]; //しゃべる言葉

	pid_t  	pidTalk; 
	pthread_t thrTalk;
	char	prgTalk[100]; //Wav再生
} AcGbl;



Wave 作成

thread_MakeWav
static void  *thread_MakeWav(void *ax){
    AcGbl *axx = (AcGbl *)ax; char *cmd = axx->prgMakeWav;
    pid_t pid = fork(); int status;
    if(pid==0){
        execlp(cmd , cmd, axx->utf8Talk, NULL);
	    exit(0);
    }
    waitpid(pid, &status, 0);
    axx->pidMakeWav =pid;
}

Wave再生

thread_Talk
static void  *thread_Talk(void *ax){
    AcGbl *axx = (AcGbl *)ax; char *cmd = aTALK_WAV_CMD;
    pid_t pid = fork();
    if(pid==0){
        execlp(cmd , cmd, "-q", aTALK_WAV_FILE, NULL);
	    exit(0);
    }
    axx->pidTalk =pid;
}
  • fork することで、バックグランドで音を鳴らしつづけます。再生が終わるとプロセスが終了するので、それを検出することで、しゃべり終わったかどうかをチェックします。

しゃべっているかどうかチェック

isTalking
int  isTalking(AcGbl *axx) 
{
    pid_t pid = axx->pidTalk; int status;
    pid = waitpid(pid, &status, WNOHANG);
    return pid==0; //再生中
}

発声の中断

stopTalk
void  stopTalk(AcGbl *axx) 
{
	int status;
	if(isTalking(axx)){
		kill(axx->pidTalk, SIGKILL); wait(&status);
		pthread_cancel(axx->thrTalk);
		pthread_join(axx->thrTalk, NULL);
	}
}

しゃべるテスト

test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stddef.h> //NULL
#include <sys/types.h> //fork
#include <sys/unistd.h> //fork
#include <sys/wait.h>
#include <sys/signal.h>


void main(int argc, char *argv[])
{
    AcGbl ag; memset(&ag,0,sizeof(&ag));

    puts("Start");
    strncpy(ag.prgMakeWav, "/sh命令を置いた場所/talkman_jp.sh",sizeof(ag.prgMakeWav));//男声 
    //strncpy(ag.prgMakeWav, "/sh命令を置いた場所/talkwoman_jp.sh",sizeof(ag.prgMakeWav));//女声 

    //しゃべらせたい言葉、UTF8 でいれる
    strncpy(ag.utf8Talk, "1234567",sizeof(ag.utf8Talk));

    puts("Make wave");
	thread_MakeWav(&ag); //WAVの作成

    puts("Talk 1");
	thread_Talk(&ag);
    for(;isTalking(&ag);) ;//しゃべり終わるのを待つ

    puts("Talk 2");
	thread_Talk(&ag);
    sleep(2); //2秒後に終了

    puts("Break");
    stopTalk(&ag); 
}

テストプログラムのコンパイルと実行

$ gcc -pthread test.c
$ ./a.out
  1. まず「ひゃくにじゅうさんまんよんせんごひゃくろくじゅうなな」としゃべります。
  2. 喋り終わるのをまってから、もう一度しゃべります。こんどは2秒あとに中断して終了します

9VAeでの文字入力としゃべる設定

  • Open JTalk がインストールされていなければ、しゃべりません。9VAe Linux版でしゃべる機能を試すには、Open JTalk をインストールしてください。
  • Linux Mint. Ubuntu32bitは上の方法でインストールできました。Ubuntu 64bit の場合はこちら(Smile Engineering blog)

文字入力としゃべる設定

9VAeで文字を入力したあと、文字の選択枠の中心の「+」をクリックすると表示されるメニューに「しゃべる」「コメント」の2項目を追加しました。「コメント」文字は表示されない文字で、画面にないせりふをしゃべるときに使います。
しゃべる属性をつけると、男声でしゃべるようになります。

001c-inp.svg.gif

しゃべるを解除するには、文字パレット(次の項目)の右端のボタンをつかいます。次の項目参照

女性の設定

右側の文字パレットの配置属性メニューに「男がしゃべる」「女がしゃべる」を追加しました。文字を選んで(複数も可能)「女がしゃべる」にすると女声になります。ただし女声をインストールしていなければ男声でしゃべります。

002-wmn.svg.gif

  • もう一度同じ設定をクリックすると「しゃべる」属性が解除されます。

しゃべる順序、しゃべる時間の調整

ページの時間を「ひとコマ」に設定すると、しゃべる音声の長さを計測し、ページの時間を自動設定します。

003-hit.svg.gif

しゃべる順番は、つぎのようになります。

  1. しゃべる設定されたコメント文字があれば、重なり順序の下からしゃべります。
  2. しゃべる設定された文字を重なり順序の下からしゃべります。
  3. 前の声がしゃべり終わるまで、つぎの文字をしゃべりません。
  4. 文字はページが切り替わっても最後までしゃべります。しゃべりはじめていない文字は、次のページにうつると読み飛ばされます。
  5. 再生中止ボタンを押すと、しゃべるのをやめます。

動画作成

以下の動画は、この方法で作成しました。

作成例>クリックすると Youtubeが開きます
0voice-kof.gif

マルチOS対応の仕組み

  • 9VAeきゅうべえは、Win/Mac/Android/iOS で動きます。ソースは9割が C言語で共通化されています。しかし、文字入力、描画、しゃべるなどは、OSごとに処理が異なり、各OS用のルーチンに差し替えています。
  • アニメ再生などの時間管理は、C の共通ソースにあり、CからOSルーチンをどう呼び出すかが問題となります。各OS処理を C から呼び出せるか、以下のようになっています。
OS OS側 C から直接呼べるか
Windows Win32 C++
Linux GTX C++
Android Java 〇(JNI)
Mac Objective-C ×
iOS/iPad Objective-C ×
  • C から直接呼び出せない場合は、非同期処理になります。例えば、文字をしゃべらせる時間がすぐにはわからないので、結果がわかってから処理を続ける仕組みが必要になります。
  • C からOSの関数を呼び出せても、処理結果がすぐには出ない処理もあります(文字入力など)。

OSによって非同期処理が異なるため、しゃべる処理の移植はかなり複雑になりました。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
3