前回までの記事で述べた通り、PCにBLEで送った音声は1,600Hzでサンプリングし、ADPCMで16bitのサンプルデータを3bitに圧縮しています。送られてきた音声データの保存の実装はHubotのアダプタ内で行いました。
audioRead: (data, isNotification) ->
self = @
if isNotification
s = data.toString 'UTF-8'
if s == 'TOP_OF_VOICE________'
console.log 'Start to get voice'
@abuf = new Buffer(0)
else if s == 'END_OF_VOICE________'
console.log 'Finished to get voice'
fs.open '/mydisk/share/test.pcm', 'w', '0644', (err, fd) ->
if err
console.log err
else
fs.write fd, self.abuf, 0, self.abuf.length, null, (err, written, buffer) ->
if err
console.log err
else
@abuf = Buffer.concat [@abuf, data]
このファイルを更にADPCMのデコード(Sun Microsystemsのソースを使用)、soxというフリーウェアでPCMからWAVに変換(周波数は16KHz、音量も正規化)して聞いたところ、思った通りかなり品質は悪く、とても聞き取りにくいものでした。何となく口を塞いだまま喋ってる感じです。高調波成分がほとんどカットされており、子音が聞き取れないです。
試しに、上記の音声をGoogleのGoogle Speech APIで認識させてみましたが、全くダメでした(補足:2017/2/19現在、このAPIは60分まで無料、それ以降は15秒ごとに$0.006かかるそうです)。ノイズに強くて認識率の高い、と言ってもやっぱりここまで品質が悪いと無理みたいですね・・。
ちなみに、このAPIはwavファイルをそのまま送ってもダメで、base64形式(改行は取り除く)で送らないといけないみたいです。ADPCMデコードからBase64形式への変換までの一連の処理は下記のようなScriptで行いました(decodeはSunのADPCMコーデックのソースに含まれています)。
#!/bin/sh ./decode < /mydisk/share/test.pcm > out.pcm sox -r 1600 -c 1 -b 16 -e signed-integer -t raw out.pcm /mydisk/share/out.wav rate 16k norm base64 /mydisk/share/out.wav | tr -d '\n' > /mydisk/share/out.b64
また、GoogleのAPIは「https://speech.googleapis.com/v1beta1/speech:syncrecognize?&key=APIキー」に下記のようなJSONをPOSTするだけでいけました。5秒の音声を送ってから認識結果が返ってくるまで、大体5.5秒程度かかりました。
{
"config":{
"encoding":"LINEAR16",
"sampleRate":16000,
"languageCode":"ja-JP"
},
"audio":{
"content":"BASE64に変換したWAVデータ(16kHz,16bitPCM)"
}
}