在语音进行时突出显示文本

Aja*_*jja 4 java android highlight text-to-speech

我正在开发一个应用程序,其中我的 textview 由字符串和两个按钮组成。当我单击说话按钮时,文本会转换为语音。但是我想在语音运行时突出显示这个词

请查看以下链接中的“我的应用”屏幕截图。 在此处输入图片说明

这是我的文本到语音初始化:

textToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {

        @Override
        public void onInit(int status) {

            if (status == TextToSpeech.SUCCESS) {
                result = textToSpeech.setLanguage(Locale.ENGLISH);
                textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
                    @Override
                    public void onStart(String utteranceId) {
                        Log.d(utteranceId, "TTS start");}

                    @Override
                    public void onDone(String utteranceId) {
                        Log.d(utteranceId, "TTS done");}

                    @Override
                    public void onError(String utteranceId) {
             });
            } else {
                Toast.makeText(getApplicationContext(), "Feature is not Available", Toast.LENGTH_SHORT).show();
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

和其他代码:

private void speak() {
 if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
        Toast.makeText(getApplicationContext(), "Feature is not Available", Toast.LENGTH_SHORT).show();
    } else {
        textToSpeech.setPitch(1f);
        textToSpeech.setSpeechRate(0.8f);
        HashMap<String, String> params = new HashMap<>();
        params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "utteranceId");
        textToSpeech.speak(getString(R.string.storytxt), TextToSpeech.QUEUE_FLUSH, params);

    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (textToSpeech != null) {
        textToSpeech.shutdown();
    }
}
Run Code Online (Sandbox Code Playgroud)

到这里我没有遇到任何问题。现在我想突出显示文本。我不知道该怎么做。我到处搜索仍然没有这方面的线索。

我将字符串存储在 String.xml 中。

Boo*_*unz 5

对于 Android API 26 及更高版本以及支持 onRangeStart 的 TTS 引擎(在本例中为 Google TTS):

public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {

    TextToSpeech tts;

    String sentence = "The Quick Brown Fox Jumps Over The Lazy Dog.";

    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);
        textView.setText(sentence);
        tts = new TextToSpeech(this, this);

    }

    // TextToSpeech.OnInitListener (for our purposes, the "main method" of this activity)
    public void onInit(int status) {

        tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {

            @Override
            public void onStart(String utteranceId) {
                Log.i("XXX", "utterance started");
            }

            @Override
            public void onDone(String utteranceId) {
                Log.i("XXX", "utterance done");
            }

            @Override
            public void onError(String utteranceId) {
                Log.i("XXX", "utterance error");
            }

            @Override
            public void onRangeStart(String utteranceId,
                                     final int start,
                                     final int end,
                                     int frame) {
                Log.i("XXX", "onRangeStart() ... utteranceId: " + utteranceId + ", start: " + start
                        + ", end: " + end + ", frame: " + frame);

                // onRangeStart (and all UtteranceProgressListener callbacks) do not run on main thread
                // ... so we explicitly manipulate views on the main thread:
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {

                        Spannable textWithHighlights = new SpannableString(sentence);
                        textWithHighlights.setSpan(new ForegroundColorSpan(Color.YELLOW), start, end, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
                        textView.setText(textWithHighlights);

                    }
                });

            }

        });

    }

    public void startClicked(View ignored) {

        tts.speak(sentence, TextToSpeech.QUEUE_FLUSH, null, "doesn't matter yet");

    }

}
Run Code Online (Sandbox Code Playgroud)

// ------------------------------------------------ -------------------

Android API 25 及以下:

理论上,最直观的方法是:

1)把绳子掰成几段

2) 检测每件作品何时被/正在被说出来

3) 相应地突出显示该部分

然而,不幸的是,当使用实时生成语音输出的 Android TextToSpeech 类时,您能够精确检测(使用 UtteranceProgressListener)进度的最小语音单位是一个话语(您决定发送的任何字符串)到 TTS)——不一定是一个词。

没有任何机制可以让您简单地将多字串作为话语发送,然后以某种方式准确检测每个单词何时被说出。

因此,为了(轻松)按顺序突出显示每个单词,您必须:

A) 将每个单词作为单个话语单独发送到 TTS(但这会导致发音不连贯),或

B) 而是逐句突出显示,将每个句子作为一个话语发送(最简单的方法,但不是您想要的行为)。

如果你真的坚持要实现逐字高亮效果,我能想到的唯一方法(使用 Android TextToSpeech)是使用句子大小的话语,但不是使用 speak(),而是使用 synthesizeToFile()...和然后使用某种媒体播放器或声音播放器播放语音……以某种方式根据第 n 个单词相对于总音频文件长度的位置来近似高光的时间。因此,例如,如果句子长度为 10 个单词,并且文件已完成 30%,那么您将突出显示第 4 个单词。这将是困难和不准确的,但在理论上是可能的。

显然已经有一些应用程序和游戏可以做到这一点……像说唱歌手帕拉帕这样的游戏,或者卡拉 OK 应用程序,但我认为他们这样做的方式是预先录制/静态音频文件,并在准确的时间编码标记触发亮点。如果您的文本内容总是相同的,并且只有一种语言,那么您也可以这样做。

但是,如果语音文本是用户输入的或在运行时之前未知,需要 TTS,那么我不知道任何直接的解决方案。

如果您决定采用这些更狭窄的方法之一,那么我建议相应地发布一个新问题。