15
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-11-30

今回、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によって非同期処理が異なるため、しゃべる処理の移植はかなり複雑になりました。

15
3
0

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
  3. You can use dark theme
What you can do with signing up
15
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?