テキストの読み上げをTTS (TextToSpeech) を使うとできます。
TTSを使うには変換する音声データが言語別に必要でしたが、既に実機インストールされているかネットワーク経由で使えるようです。
2021.2.1
Text To Speech
以前は「Pico TTS」というのがありました。これはロボットのような音声でしたが、最近の音声変換はマシになってきました。といっても「ゆっくり茶番劇」よりはちょっと自然な感じ程度
TTS言語設定
TTSを試す上で端末のTTSとしての言語設定が必要です。
日本語の音声を再生させるための端末の設定を確認しておきます。例えばPixelの場合は
「設定」->「システム」->「言語と入力」->「テキスト読み上げの設定」
に入ると言語の設定があるので、日本語を選択し、そこでテストすることもできます。
設定は機種により異なるので、それらしいものを探すしかありません
以下は、default英語設定のemulatorから日本語に対応させた例です。
コーディングは大まかにこのようになります。
1. TestToSpeech インスタンス生成
1 2 3 |
TestToSpeech tts = new TextToSpeech( Context context, TextToSpeech.OnInitListener listener) |
2. onInit() で初期化の結果ステータスを取得
3. speak() メソッドで読み上げ開始
1 2 3 4 |
tts.speak(CharSequence text, int queueMode, Bundle params, String utteranceId) |
サンプルコード
今回は、読み上げの開始と終了タイミングを取得するために、setOnUtteranceProgressListener() を使います。
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
//package your.package.name; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.speech.tts.TextToSpeech; import android.speech.tts.UtteranceProgressListener; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; public class MainActivity extends AppCompatActivity implements View.OnClickListener, TextToSpeech.OnInitListener{ private TextToSpeech tts; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // TTS インスタンス生成 tts = new TextToSpeech(this, this); Button ttsButton = findViewById(R.id.button_tts); ttsButton.setOnClickListener(this); } @Override public void onInit(int status) { // TTS初期化 if (TextToSpeech.SUCCESS == status) { Log.d("debug", "initialized"); } else { Log.e("debug", "failed to initialize"); } } @Override public void onClick(View v) { speechText(); } private void shutDown(){ if (null != tts) { // to release the resource of TextToSpeech tts.shutdown(); } } private void speechText() { EditText editor = findViewById(R.id.edit_text); editor.selectAll(); // EditTextからテキストを取得 String string = editor.getText().toString(); if (0 < string.length()) { if (tts.isSpeaking()) { tts.stop(); return; } setSpeechRate(); setSpeechPitch(); tts.speak(string, TextToSpeech.QUEUE_FLUSH, null, "messageID"); setTtsListener(); } } // 読み上げのスピード private void setSpeechRate(){ if (null != tts) { tts.setSpeechRate((float) 1.0); } } // 読み上げのピッチ private void setSpeechPitch(){ if (null != tts) { tts.setPitch((float) 1.0); } } // 読み上げの始まりと終わりを取得 private void setTtsListener(){ int listenerResult = tts.setOnUtteranceProgressListener(new UtteranceProgressListener() { @Override public void onDone(String utteranceId) { Log.d("debug","progress on Done " + utteranceId); } @Override public void onError(String utteranceId) { Log.d("debug","progress on Error " + utteranceId); } @Override public void onStart(String utteranceId) { Log.d("debug","progress on Start " + utteranceId); } }); if (listenerResult != TextToSpeech.SUCCESS) { Log.e("debug", "failed to add utterance progress listener"); } } protected void onDestroy() { super.onDestroy(); shutDown(); } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <EditText android:id="@+id/edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:hint="@string/hint" android:inputType="text" android:autofillHints="@string/hint" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.6" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.4" /> <Button android:id="@+id/button_tts" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:text="@string/button" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.6" /> </androidx.constraintlayout.widget.ConstraintLayout> |
strings.xml
1 2 3 4 5 |
<resources> <string name="app_name">YourAppName</string> <string name="hint">"言語設定されたものを入力"</string> <string name="button">Text To Speech</string> </resources> |
サンプル動画
Reference:
TextToSpeech | Android Developers