質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

1回答

1868閲覧

TTSは一つのテキストしか読み上げできないのでしょうか?

android_app_tw

総合スコア4

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

0クリップ

投稿2020/09/05 06:47

私は今AndroidStudioを勉強しています。
Texttospeechを使って二つのEditTextに入力した文章をそれぞれ分けて読み上げしたいのですが、二つ目の文章の読み上げができません。
今できているプログラムはこちらになります。
ここに、もう一つボタンを追加して、このボタンを押すことでedit2(id)を読み上げしたいと考えています。
可能であれば、追加するコードを全文載せていただけると嬉しいです。

public class Mindmap1Activity extends AppCompatActivity
implements View.OnClickListener, TextToSpeech.OnInitListener {

private TextToSpeech tts; private static final String TAG = "TestTTS"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_mindmap1) // 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(TAG, "initialized"); } else { Log.e(TAG, "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); editor.selectAll(); // EditTextからテキストを取得 String string = editor.getText().toString(); if (0 < string.length()){ if (tts.isSpeaking()) { tts.stop(); return; } setSpeechRate(1.0f); setSpeechPitch(1.0f); if (Build.VERSION.SDK_INT >= 21){ // SDK 21 以上 tts.speak(string, TextToSpeech.QUEUE_FLUSH, null, "messageID"); } else{ // tts.speak(text, TextToSpeech.QUEUE_FLUSH, null) に // KEY_PARAM_UTTERANCE_ID を HasMap で設定 HashMap<String, String> map = new HashMap<String, String>(); map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"messageID"); tts.speak(string, TextToSpeech.QUEUE_FLUSH, map); } setTtsListener(); } } // 読み上げのスピード private void setSpeechRate(float rate){ if (null != tts) { tts.setSpeechRate(rate); } } // 読み上げのピッチ private void setSpeechPitch(float pitch){ if (null != tts) { tts.setPitch(pitch); } } // 読み上げの始まりと終わりを取得 private void setTtsListener(){ // android version more than 15th if (Build.VERSION.SDK_INT >= 15){ int listenerResult = tts.setOnUtteranceProgressListener(new UtteranceProgressListener() { @Override public void onDone(String utteranceId) { Log.d(TAG,"progress on Done " + utteranceId); } @Override public void onError(String utteranceId) { Log.d(TAG,"progress on Error " + utteranceId); } @Override public void onStart(String utteranceId) { Log.d(TAG,"progress on Start " + utteranceId); } }); if (listenerResult != TextToSpeech.SUCCESS) { Log.e(TAG, "failed to add utterance progress listener"); } } else { Log.e(TAG, "Build VERSION is less than API 15"); } } protected void onDestroy() { super.onDestroy(); shutDown(); }

}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

これという仕様の記載を見つけられなかったのですがtts.speak()では同時にテキストの再生はできないと思われます。
試しにTTSのインスタンスをアプリ内で二つ作ってspeak()させてみましたが同時再生はできませんでした。STREAM_TYPEをSYSTEMとMUSICのように変えて見ましたがそれでもダメでした。また複数のTTSアプリを使ってどうなるかも試しましたが同時再生はできませんでした。

が仕様的にがんばれば実現できそうに思ったのでこんな感じで作って見ました。
色々自分で試しやすいようにKotlinを使いたかったので、共有していただいているコードに追加する形になっていないのはご容赦下さい。もしJavaのコードで確認したい場合はAndroidStudioでKotlin->Java変換を試して見て下さい。

tts.speak()ではなくtts.synthesizeToFileを使って音声ファイルを作成し、それをMediaPlayerで再生させる形で同時読み上げっぽい挙動を実装しました。
コードをシンプルにするために読み上げる文字列は固定、読み上げのpitchなども固定にしています。またminSdk>=21です。

MainActivity.kt

Kotlin

1package 自分の開発環境に合わせて下さい 2 3import androidx.appcompat.app.AppCompatActivity 4import android.os.Bundle 5import android.speech.tts.TextToSpeech 6import android.speech.tts.UtteranceProgressListener 7import android.util.Log 8import android.widget.Button 9import android.widget.TextView 10import android.media.MediaPlayer 11import android.net.Uri 12import java.io.File 13 14private val TAG = MainActivity::class.java.simpleName 15 16class MainActivity : AppCompatActivity() { 17 companion object { 18 private const val TEXT1_ID = "TEXT1_ID" 19 private const val TEXT2_ID = "TEXT2_ID" 20 } 21 22 /** テキスト読み上げ */ 23 private lateinit var tts: TextToSpeech 24 lateinit var text1: TextView 25 lateinit var button1: Button 26 lateinit var text2: TextView 27 lateinit var button2: Button 28 29 private var mediaPlayer1: MediaPlayer? = null 30 private var mediaPlayer2: MediaPlayer? = null 31 32 override fun onCreate(savedInstanceState: Bundle?) { 33 super.onCreate(savedInstanceState) 34 setContentView(R.layout.activity_main) 35 36 text1 = findViewById(R.id.text1) 37 text2 = findViewById(R.id.text2) 38 button1 = findViewById(R.id.button1) 39 button2 = findViewById(R.id.button2) 40 41 // TTS初期化 42 tts = TextToSpeech(this, TextToSpeech.OnInitListener { status -> 43 if (TextToSpeech.SUCCESS != status) { 44 Log.e(TAG, "TextToSpeech init error status=$status") 45 } 46 }).apply { 47 setSpeechRate(2.0f) 48 setPitch(1.0f) 49 } 50 51 val file1 = File(cacheDir, TEXT1_ID) 52 val file2 = File(cacheDir, TEXT2_ID) 53 tts.setOnUtteranceProgressListener(object : UtteranceProgressListener() { 54 override fun onDone(utteranceId: String?) { 55 // TextToSpeech.synthesizeToFile完了時もspeak時と同様にこのコールバックが実行される 56 Log.d(TAG, "onDone") 57 58 when (utteranceId) { 59 TEXT1_ID -> { 60 // synthesizeToFileによって生成されたファイルでMediaPlayerを生成し再生する 61 mediaPlayer1 = MediaPlayer.create(this@MainActivity, (Uri.fromFile(file1))) 62 63 // 再生後の後始末 64 mediaPlayer1!!.setOnCompletionListener { 65 Log.d(TAG, "end of audio mediaPlayer1") 66 releaseMediaPlayer(mediaPlayer1) 67 mediaPlayer1 = null 68 } 69 70 mediaPlayer1!!.start() 71 } 72 TEXT2_ID -> { 73 mediaPlayer2 = MediaPlayer.create(this@MainActivity, (Uri.fromFile(file2))) 74 75 mediaPlayer2!!.setOnCompletionListener { 76 Log.d(TAG, "end of audio mediaPlayer2") 77 releaseMediaPlayer(mediaPlayer2) 78 mediaPlayer2 = null 79 } 80 81 mediaPlayer2!!.start() 82 } 83 } 84 } 85 86 override fun onError(utteranceId: String?) { 87 Log.w(TAG, "onError") 88 } 89 90 override fun onStart(utteranceId: String?) { 91 // NOP 92 } 93 }) 94 95 button1.setOnClickListener { 96 releaseMediaPlayer(mediaPlayer1) 97 val param = Bundle().apply { 98 putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, 1.0f) 99 } 100 101 // tts.speak()させずにファイルに書き出す 102 // ref: http://www.dre.vanderbilt.edu/~schmidt/android/android-4.0/out/target/common/docs/doc-comment-check/resources/articles/tts.html 103 tts.synthesizeToFile(text1.text.toString(), param, file1, TEXT1_ID) 104 105 } 106 107 button2.setOnClickListener { 108 releaseMediaPlayer(mediaPlayer2) 109 val param = Bundle().apply { 110 putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, 1.0f) 111 } 112 113 tts.synthesizeToFile(text2.text.toString(), param, file2, TEXT2_ID) 114 } 115 } 116 117 // ref: https://developer.android.com/guide/topics/media/mediaplayer?hl=ja#releaseplayer 118 override fun onStop() { 119 super.onStop() 120 releaseMediaPlayer(mediaPlayer1) 121 mediaPlayer1 = null 122 releaseMediaPlayer(mediaPlayer2) 123 mediaPlayer2 = null 124 } 125 126 override fun onDestroy() { 127 super.onDestroy() 128 tts.shutdown() 129 } 130 131 private fun releaseMediaPlayer(mediaPlayer: MediaPlayer?) { 132 if (mediaPlayer?.isPlaying == true) { 133 mediaPlayer.stop() 134 } 135 mediaPlayer?.reset() 136 mediaPlayer?.release() 137 } 138} 139

activity_main.xml

xml

1<?xml version="1.0" encoding="utf-8"?> 2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context=".MainActivity"> 8 9 <TextView 10 android:id="@+id/text1" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="1111" 14 android:textSize="16sp" 15 app:layout_constraintStart_toStartOf="parent" 16 app:layout_constraintTop_toTopOf="parent" /> 17 18 <Button 19 android:id="@+id/button1" 20 android:layout_width="wrap_content" 21 android:layout_height="wrap_content" 22 android:layout_marginTop="8dp" 23 android:background="@color/colorPrimary" 24 android:text="button1" 25 app:layout_constraintStart_toStartOf="parent" 26 app:layout_constraintTop_toBottomOf="@+id/text1" /> 27 28 <TextView 29 android:id="@+id/text2" 30 android:layout_width="wrap_content" 31 android:layout_height="wrap_content" 32 android:layout_marginTop="20dp" 33 android:text="2222" 34 android:textSize="16sp" 35 app:layout_constraintStart_toStartOf="parent" 36 app:layout_constraintTop_toBottomOf="@+id/button1" /> 37 38 <Button 39 android:id="@+id/button2" 40 android:layout_width="wrap_content" 41 android:layout_height="wrap_content" 42 android:layout_marginTop="8dp" 43 android:background="@color/colorPrimary" 44 android:text="button2" 45 app:layout_constraintStart_toStartOf="parent" 46 app:layout_constraintTop_toBottomOf="@+id/text2" /> 47 48 49</androidx.constraintlayout.widget.ConstraintLayout>

投稿2020/09/05 20:41

編集2020/09/05 20:48
ichan

総合スコア7

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問