Android 好用的第三方 ASR & TTS Library — Android Speech


GitHub: https://github.com/gotev/android-speech

作者的官方網站:http://gotev.github.io/android-speech/

使用方法:
Gradle

dependencies {
 compile 'net.gotev:speech:1.2.2'
}

調用前作者建議在將初始化寫在Application內,使用起來不用每個Activity去做初始化,可以共用同一個Application類別,也就是Singleton。

所以就先新增一個Initializer.java 去繼承 Application

public class Initializer extends Application {

@Override
public void onCreate() {
super.onCreate();

Speech.init(this);
}
}

當然新建完畢的Initializer類別後,別忘記要去AndroidManifest.xml去設定Application為Initializer類別

<application
android:name="com.example.Initializer"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >

由於是有使用到麥克風錄音,還要給予android.permission.RECORD_AUDIO的權限

<uses-permission android:name="android.permission.RECORD_AUDIO" />

接下來就可以直接在Activity內,避免當不使用時,記憶體洩漏,在onDestroy()內,加上Speech.getInstance().shutdown();

@Override
protected void onDestroy() {
super.onDestroy();
Speech.getInstance().shutdown();
}

於Activity內使用語音辨識時:

Speech.getInstance().startListening(SpeechDelegate speechDelegate) 無UI界面,直接調用

Speech.getInstance().startListening(SpeechProgressView speechProgressView) 有UI界面

下面為無UI介面的Speech.getInstance().startListening()的使用方法:

try {
Speech.getInstance().startListening(new SpeechDelegate() {
@Override
public void onStartOfSpeech() {
Log.i("speech", "speech recognition is now active");
}

@Override
public void onSpeechRmsChanged(float value) {
Log.d("speech", "rms is now: " + value);
}

@Override
public void onSpeechPartialResults(List<String> results) {
StringBuilder str = new StringBuilder();
for (String res : results) {
str.append(res).append(" ");
}

Log.i("speech", "partial result: " + str.toString().trim());
}

@Override
public void onSpeechResult(String result) {
Log.i("speech", "result: " + result);
}
});
} catch (SpeechRecognitionNotAvailable exc) {
Log.e("speech", "Speech recognition is not available on this device!");
// You can prompt the user if he wants to install Google App to have
// speech recognition, and then you can simply call:
//
// SpeechUtil.redirectUserToGoogleAppOnPlayStore(this);
//
// to redirect the user to the Google App page on Play Store
} catch (GoogleVoiceTypingDisabledException exc) {
Log.e("speech", "Google voice typing must be enabled!");
}

當然有人會問這樣好像不能指定語系,所以可以在跳用Speech.getInstance().startListening()前先呼叫 Speech.getInstance().setLocale(),將所指定語系Locale傳入即可

可以是用new Locale(),若知道語系的Locale也可以直接填入

下面使用的是Locale.TAIWAN指定是台灣語系的方式

當使用Speech.getInstance().setLocale(Locale.TAIWAN),在背後這個方法會幫我們同時指定Android Speech Recognition(ASR 語音辨識)跟 Text To Speech(TTS 文字轉語音)的語系,若是需要ASR跟TTS使用不同語系時,分別在調用Speech.getInstance().startListening() 跟Speech.getInstance().say()方法前,個別先調用Speech.getInstance().setLocale()

語音辨識有使用UI時:

activity_main.xml:

<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/linearLayout"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/tv_text"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp">

<net.gotev.speech.ui.SpeechProgressView
android:id="@+id/progress"
android:layout_width="120dp"
android:layout_height="150dp"/>

</LinearLayout>
SpeechProgressView就是左圖的樣式

MainActivity.java:

透過findViewById先找到 SpeechProgressView

textView = (TextView) findViewById(R.id.tv_text);
speechView = (SpeechProgressView) findViewById(R.id.progress);
speechView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
if (Speech.getInstance().isListening()) {
Speech.getInstance().stopListening();
}
Speech.getInstance().init(this);
speechView = (SpeechProgressView) findViewById(R.id.progress);
speechView.setOnTouchListener(this);
Speech.getInstance().setLocale(Locale.TAIWAN).startListening(speechView, new SpeechDelegate() {
@Override
public void onStartOfSpeech() {
Log.i("speech", "speech recognition is now active");
}

@Override
public void onSpeechRmsChanged(float value) {
Log.d("speech", "rms is now: " + value);
}

@Override
public void onSpeechPartialResults(List<String> results) {
StringBuilder str = new StringBuilder();
for (String res : results) {
str.append(res).append(" ");
}

Log.i("speech", "partial result: " + str.toString().trim());
}

@Override
public void onSpeechResult(String result) {
Log.i("speech", "result: " + result);
textView.setText(result.toString().trim());
Speech.getInstance().say(result);

}
});
} catch (SpeechRecognitionNotAvailable exc) {
Log.e("speech", "Speech recognition is not available on this device!");
// You can prompt the user if he wants to install Google App to have
// speech recognition, and then you can simply call:
//
// SpeechUtil.redirectUserToGoogleAppOnPlayStore(this);
//
// to redirect the user to the Google App page on Play Store
} catch (GoogleVoiceTypingDisabledException exc) {
Log.e("speech", "Google voice typing must be enabled!");
}
}
});

在語音辨識過程中,會有四個方法分別被調用:

onStartOfSpeech(): 開始語音辨識階段

onSpeechRmsChanged(float value): 錄音過程音量靈敏度變化

onSpeechPartialResults(List<String> results): 錄音過程中,會不斷去將鎖辨識出來的文字會傳回來,須在這邊將 results做一個字串的串接

@Override
public void onSpeechPartialResults(List<String> results) {
StringBuilder str = new StringBuilder();
for (String res : results) {
str.append(res).append(" ");
}
}

onSpeechResult(String result): 最後語音辨識完畢後的結果,會將串接完的字串在這邊取得。(這邊中文字串中間會有空格,所以需要另外自行處理)

另外在語音辨識中,幾個重要的方法:

Speech.getInstance().isListening();  回傳是否在傾聽錄音中
Speech.getInstance().stopListening(); 停止傾聽錄音
Speech.getInstance().setStopListeningAfterInactivity(1000); 傾聽錄音的閒置的Timeout時間,單位是ms

TextToSpeech 文字轉語音部份,調用方式有兩種:

Speech.getInstance().setLocale() 去做指定轉語音的語系,沒指定對的語系會無法正確發音

Speech.getInstance().say(String message); 直接將想要念出的訊息傳入即可

Speech.getInstance().say(String message, TextToSpeechCallback callback); 傳入一個TextToSpeechCallback的回調,有onStart、onCompleted、onError三個階段可以去做操作

Speech.getInstance().setLocale(Locale.TAIWAN);
Speech.getInstance().say("我會說中文喔");
Speech.getInstance().say("我會說中文喔", new TextToSpeechCallback() {
@Override
public void onStart() {

}

@Override
public void onCompleted() {

}

@Override
public void onError() {

}
});
}

在TextToSpeech中有幾個重要的方法:

Speech.getInstance().setTextToSpeechPitch((float)1.0); 語調1.0為正常
Speech.getInstance().setTextToSpeechRate((float) 1.0); 語速1.0為正常,越大越快
Speech.getInstance().setTextToSpeechQueueMode(TextToSpeech.QUEUE_ADD); 當在念語音時,若同時再次播放,前後次語音會疊在一起
Speech.getInstance().setTextToSpeechQueueMode(TextToSpeech.QUEUE_FLUSH); 當在念語音時,若同時再次播放,會將前次的語音停止在播放
One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.