0

tesselに日本語を喋らせるnpmライブラリ作った

そういえばtesselに日本語を喋らせるをnpmにしたのだった
書くの忘れてた

https://www.npmjs.org/package/audio-vs1053b-textspeech


インストール

% npm install audio-vs1053b-textspeech


使う

まずaudioモジュールにスピーカーを接続しておく。

こんな感じでaudioモジュールをtextspeechモジュールに食わせてセットアップし、
var audio = require('audio-vs1053b').use(tessel.port['A']);
var textspeech = require('audio-vs1053b-textspeech').use(audio);

audio.on('ready', function(){
audio.setVolume(20, function(err){ // 音量調整
console.log('audio setup');
// この後に喋ったりさせる
});
});


簡単に喋らせれる。日本語でおk
textspeech.speech('こんにちは'); // japanese
textspeech.speech('hello world', {tl: 'en'}); // english

なお初めてしゃべる言葉はgoogle翻訳にmp3を取りに行くので10秒ぐらいかかる。
2回目以降はオンメモリのキャッシュに入っているので、すぐ発声できる。
でもaudioモジュールの通信がUARTなので、同時に他のセンサ系モジュール使ったりしてるとそっちのUARTもバリバリ通信おこなわれて、途切れ途切れになってちゃんと喋れなくなる。

tesselはaudioとかカメラとか大きなマルチメディアデータやりとりする系のモジュールがウリっぽい所あるのに、それ使ってると他のモジュールが動かなくなるのはなんかつらい。そもそもtesselのCPUであるARMから拡張ボード用に4つUART出してるけど、たぶん全部ソフトウェアUARTだから、ファームウェアの実装を効率化してもどうにかなる気がしない。どうするんだろ。


あとキャッシュのサイズも指定できる
textspeech.setCacheSize(5); // default is 3


前に書いたとおり(おそらく)streamのバグがある状態の上で妥協する感じで実装しているので、そのうち仕様変わるかもしれないので最新情報はnpmjs.orgのほうのドキュメント見てください

0

tesselに日本語を喋らせる

tesselのaudioモジュールを使うとLine出力でスピーカーに接続し、音がだせる。

再生できるのはmp3とwavファイル。


普通のmp3を再生


こんなコードで再生できる。tesselで実行するjsファイルと同じ階層に”cabbage.mp3″をを置いたら、fs.readFileSyncで読めた。実装をちゃんと追ってないから詳細はわからないがファイルシステムがあるらしい。

tessel-study/audio-play-mp3 at master · shokai/tessel-study
var tessel = require('tessel');
var fs = require('fs');
var audio = require('audio-vs1053b').use(tessel.port['A']);

audio.on('ready', function(){
console.log('audio ready');
audio.setVolume(20, function(err){
if(err) return console.error(err);
var data = fs.readFileSync('cabbage.mp3');
setInterval(function(){
audio.play(data, function(err){
if(err) return console.error(err);
console.log('audio done');
});
}, 2000);
});
});


日本語の音声を再生


強引だけどgoogle翻訳のmp3を取得して再生できた。ただし再生まで10秒ぐらいかかる。

tessel-study/audio-google-say at master · shokai/tessel-study
var tessel = require('tessel');
var fs = require('fs');
var stream = require('stream');
var request = require('request');
var wifi = require('wifi-cc3000');
var audio = require('audio-vs1053b').use(tessel.port['A']);

var led_green = tessel.led[0].output(1);
setInterval(function(){
led_green.toggle()
}, 200);

var getAudioStream = function(speech_text){
return request.get({
uri: 'http://translate.google.com/translate_tts',
qs: {
q: speech_text,
tl: 'ja'
},
headers: {
'User-Agent': 'Safari/1.0'
}
});
};

var say = function(speech_text){
console.log('say:'+speech_text);
if(!wifi.isConnected()){
console.error('wifi is not connected');
return;
}
var buf = new Buffer(10240);
var offset = 0;
var ws = stream.Writable({decodeStrings: false});
ws._write = function(chunk, enc, next){
if(chunk.length > buf.length - offset){
return next(new Error('buffer over'));
}
buf.write(chunk, offset, buf.length - offset);
offset += chunk.length;
next();
};
var req = getAudioStream(speech_text);
req.pipe(ws);
req.on('end', function(){
audio.play(buf);
});
};

audio.on('ready', function(){
console.log('audio ready');
audio.setVolume(20, function(err){
if(err) return console.error(err);
audio.emit('ready:volume');
});
});

audio.on('ready:volume', function(){
console.log('audio ready:volume');
if(err) return console.error(err);
setInterval(function(){
say('うどん居酒屋 かずどん');
}, 30*1000);
say('焼肉ざんまい');
});

stream


本当はaudio.createPlayStream()を使いたいんだけど、ビミョーに再生できるのに音声の最後が切れてしまう。音声の長さに関係なく、最後が切れる。
getAudioStream("ざんまい").pipe(audio.createAudioStream());

audio.createPlayStreamの実装も見たけど、どうもそっちじゃなくてstreamの実装の方にバグがある気がする。

0

ブラウザでtext to speech

ブラウザでテキストの音声読み上げができるというので試した。

http://shokai.github.io/text-to-speech-on-browser/



動いた / 動かない

Mac OSXとAndroid4.4とiOS7のSafariとChromeでは日本語が読み上げできた。
iOSはwebview(twitterアプリの内蔵ブラウザで試した)でも読み上げできたが、androidはwebviewでは無理っぽい。

古いOSは知らない。windowsだとどうなんだろう?

Firefoxには音声読み上げAPIが無い。


参考



コード

main.coffee
say = (str) ->
unless SpeechSynthesisUtterance
console.log "your browser does not support text-to-speech API"
return

msg = new SpeechSynthesisUtterance
voices = speechSynthesis.getVoices()
jp_voice = _.find voices, (v) -> /ja[-_]JP/.test v.lang

if jp_voice
console.log "say #{str} (#{jp_voice?.name})"
else
console.log "say #{str}"

msg.voice = jp_voice
msg.text = str
speechSynthesis.speak msg


$ ->
$("#btn_say").on 'click', ->
say $('#text').val()

say 'こんにちは'


細かいこと


voice プロパティ

Macはvoiceプロパティを設定してあげないとうんともすんとも言わない。getVoices()で取得して声を指定する。
逆にスマホ(android/iOS)だと、voiceプロパティは設定しなくても日本語をしゃべってくれた。英語とか日本語以外を喋らせるにはvoiceプロパティの設定が必要。

Macのchromeで1回目喋れない

なぜか1回目はgetVoices()が空配列を返してくる。
Macのsafariは問題ない。

iOSはユーザー操作後でないと読み上げできない

iOSはボタンを押すなどユーザー操作のイベントからでないと音声再生しない。

下の様にsetIntervalで喋らせた場合、何も操作しなくてもsay関数が呼ばれる。getVoicesもspeechSynthesis.speakも動くのに、音声が出ない。
一度でもボタン “#btn_say” の方を押せばsetInterval内の「こんにちは」も発声されるようになる。
$ ->
$("#btn_say").on 'click', ->
say $('#text').val()

setInterval ->
say 'こんにちは'
, 1000

0

Macのsayコマンドの音程を変更しつつ再生

Macのsayに日本語しゃべらせれるけど、声が1種類しかなくてもっとほしい。

soxについてるplayコマンドを使うと音程変えたりエフェクトいろいろかけたりしながら再生できるので

brew install sox


saypitchコマンドを作った
後ろに数字付けると音程調整できる
saypitch パソコンなくても書画カメラとnexus7で余裕だった -300
saypitch パソコンなくても書画カメラとnexus7で余裕だった 800
男っぽい声とかもだせる。

#!/bin/sh
## brew install sox

TMP=/tmp/saypitch.aiff
if test $2 ; then
PITCH=$2
else
PITCH=0
fi
say $1 -o $TMP && play $TMP pitch $PITCH norm reverb
rm $TMP

読む速度遅くしたり
saypitch "-r 250 パソコンなくても書画カメラとnexus7で余裕だった" -1000


というかsoxはおもしろい。
一緒にrecというコマンドも入って、これを使うとCUIからすぐに録音できる。
今のところこれが一番簡単な録音方法なのではないか

11

Raspberry Piに喋らせる

Raspberry Piが音声で状況報告してくれると、画面を接続していなくても状況がわかって便利です。
音はUSBスピーカで出した方がいいですね。ヘッドフォン端子からの出力は無音でもブチブチ音が出ててきびしい。

OSはraspbian使ってる。

OpenJTalkをインストールする


Mac/Linuxに日本語を喋らせるに書いたOpenJTalkをセットアップする

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

デフォルトの声が怖いのでMMD agentの声を入れる
wget http://downloads.sourceforge.net/project/mmdagent/MMDAgent_Example/MMDAgent_Example-1.3/MMDAgent_Example-1.3.zip
unzip MMDAgent_Example-1.3.zip
sudo cp -R MMDAgent_Example-1.3/Voice/* /usr/share/hts-voice/

OpenJTalkに喋らせるコマンドを作った。適当な場所に置いておく。
jsay はい
で喋る。


スピーカ

USBスピーカ接続するとドライバインストールや設定なしですぐ音がだせる。


音をヘッドフォン端子から出す

R-Pi Troubleshooting – eLinux.orgより
sudo amixer cset numid=3 1
1じゃなく2にするとHDMIから出る。0は自動判別


ヘッドフォン端子の音量調節

sudo apt-get install alsa-utils
amixer set PCM 0%
amixer set PCM 20%
のようにして設定する。
でもプチプチ音がひどい。

ファームウェアアップデート

ファームウェアアップデートしたら音が良くなるらしいのでやってみる
https://github.com/Hexxeh/rpi-update
READMEの通りにやる。
Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS
Performing self-update
sARM/GPU split is now defined in /boot/config.txt using the gpu_mem option!
Updating firmware (this will take a few minutes)
fatal: Failed to resolve 'HEAD' as a valid ref.
動かない。


結論:USBスピーカ買え