SpeechRecognizerを使って音声テキスト及び音声データを取得する方法
昔書いたネタをそのまま書く。
※リソース開放方式まで考慮してないので、そこら辺は活用する場合にはそれなりに要修正必須
※onBufferReceivedが機種依存により呼ばれないのもあるそうです
android.speech.SpeechRecognizerを使って音声からテキストを起こすAPIがあるけど、この際に音声データ自体も保管しておくっていう事をする。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8" ?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="sample.test"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
res/layout/activity_main.xml
<?xml version="1.0" ?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:id="@+id/start_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start" />
<Button
android:id="@+id/stop_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="stop" />
</LinearLayout>
ただSpeechRecognizerをスタートするのとストップするだけのボタンを配置
MainActivity.java
package sample.test;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.speech.SpeechRecognizer;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final int SAMPLING = 8000;
private SpeechRecognizer recognizer;
private ByteArrayOutputStream baos = new ByteArrayOutputStream(SAMPLING * 2 * 80);
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
((Button)findViewById(R.id.start_btn)).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if(recognizer != null) {
recognizer.startListening(new Intent());
}
}
});
((Button)findViewById(R.id.stop_btn)).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if(recognizer != null) {
recognizer.stopListening();
recognizer.destroy();
}
OutputStream os = null;
try {
byte[] b = baos.toByteArray();
int len = b.length;
if(len <= 0) {
return;
}
short type = 1;
short channel = 1;
short perSampling = 16;
os = new FileOutputStream(
new File(getExternalCacheDir(),System.currentTimeMillis() + ".wav")
);
// WAVEヘッダーの書き出し?
write(os,"RIFF");
writeInt(os, 36 + len);
write(os, "WAVE");
write(os, "fmt ");
writeInt(os, 16);
writeShort(os, type);
writeShort(os, channel);
writeInt(os, SAMPLING);
writeInt(os, channel * SAMPLING * perSampling);
writeShort(os, (short)(channel * perSampling / 8));
writeShort(os, perSampling);
write(os, "data");
writeInt(os, len);
// WAVEボディ(PCM?)の書き出し
os.write(b);
} catch(IOException e) {
e.printStackTrace();
} finally {
if(os != null) {
try {
os.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
});
}
@Override
public void onStart() {
super.onStart();
recognizer = SpeechRecognizer.createSpeechRecognizer(this);
recognizer.setRecognitionListener(new RecognitionListener() {
public void onRmsChanged(float rmsdB) {
}
public void onResults(Bundle bundle) {
List<String> words = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
for(String word : words) {
Toast.makeText(MainActivity.this, word, Toast.LENGTH_LONG).show();
}
}
public void onReadyForSpeech(Bundle params) {
}
public void onPartialResults(Bundle results) {
}
public void onEvent(int type, Bundle params) {
}
public void onError(int error) {
}
public void onEndOfSpeech() {
}
public void onBufferReceived(byte[] buffer) {
try {
baos.write(buffer);
} catch(IOException e) {
e.printStackTrace();
}
}
public void onBeginningOfSpeech() {
}
});
}
@Override
public void onStop() {
super.onStop();
if(recognizer != null) {
recognizer.stopListening();
recognizer.destroy();
recognizer = null;
}
}
private void write(OutputStream out, String value) throws IOException {
for(int i = 0; i < value.length(); i++) {
out.write(value.charAt(i));
}
}
private void writeShort(OutputStream out, short value) throws IOException {
out.write(value >> 0);
out.write(value >> 8);
}
private void writeInt(OutputStream out, int value) throws IOException {
out.write(value >> 0);
out.write(value >> 8);
out.write(value >> 16);
out.write(value >> 24);
}
}
っていう感じ。SpeechRecognizerを使ってやる場合とかだと、音声からテキストを起こすだけじゃなくて、その音声を保管しておくことも可能、但し音声はPCMデータになっているので.wavとして保管にするにはWAVEヘッダーもろもろを処理する必要があるっぽい (音声系処理に関してはまったく知らないので)
ちなみにAndroidのソース(AOSP)にはandroid.speech.srec.WaveHeaderっていうのが入ってる(SDK内APIには無い)。それを使えば
WaveHeader wav = new WaveHeader(
WaveHeader.FORMAT_PCM,
(short)1,
11025,
(short)16,
b.length
);
OutputStream os = new FileOutputStream(new File("/sdcard/sample.wav"));
wav.write(os);
的に利用する事も可能
※WaveHeaderはAOSP/frameworks/base/core/java/android/speech/srecに入ってる