Моя цель - использовать API преобразования текста в речь Android для воспроизведения предложения текста как речи, отслеживая текущее произнесенное слово.
Чтобы добиться плавного естественного воспроизведения, я использую:
tts.speak("This is the sentence", TextToSpeech.QUEUE_FLUSH, null, null)
но тогда я не могу уследить за произнесенным в данный момент словом.
Чтобы воспроизвести предложение, отслеживая произносимое в данный момент слово, я использую:
val words = "This is the sentence".split(" ")
words.forEachIndexed { index, element ->
tts.speak(element, TextToSpeech.QUEUE_ADD, null, index.toString())
}
в сочетании с UtteranceProgressListener, но тогда речь будет очень отрывистой и не будет считаться естественным предложением.
Есть ли способ получить одновременно произносимое естественным образом предложение и в то же время отслеживать произносимое в данный момент слово?
Если вы посмотрите последнюю версию документации Android, вы заметите новый метод, представленный в UtteranceProgressListener на уровне API 26, который называется onRangeStart ((String utteranceId, int start, int end, int frame)
Однако, как указано в документации:
"Вызывается, только если механизм предоставляет информацию о времени, вызывая rangeStart (int, int, int)"
Это реализовано в SynthesisCallback: https://developer.android.com/reference/android/speech/tts/SynthesisCallback.html#rangeStart(int,%20int,%20int)
Снова в документации говорится:
«Служба может вызвать этот метод, чтобы предоставить информацию о времени произнесенного текста».
К сожалению, это означает, что обратный вызов, предоставляющий необходимую информацию о времени, зависит от реализации.
На моем устройстве под управлением Android 8.0.0 и с использованием движка tts по умолчанию (com.google.android.tts) я не получил обратного вызова.
Для тестирования вам потребуется
Если ваша реализация поддерживает информацию о времени, вы сделаете обратный вызов, если нет, возможно, лучше всего найти другую реализацию движка или, возможно, реализовать свой собственный TextToSpeechService.
Для onRangeStart () я сталкиваюсь с проблемой, если текст, который я пытаюсь произнести, имеет такие знаки препинания, как точка, вопросительный знак и восклицательный знак. Проблема возникает, если текст представляет собой абзац с несколькими строками. onRangeStart () прекращает отправку данных начала, конца и кадра, как только он встречает любую из вышеупомянутых знаков препинания, поэтому обратные вызовы из метода onRangeStart () ненадежны.