Неправильные блики в пользовательском TextToSpeechService - PullRequest
0 голосов
/ 11 марта 2020

Я расширил TextToSpeechService из Android API, чтобы создать собственную службу TTS. Сервис TTS получает информацию с сервера TTS. Сервер предоставляет мне аудио буфер с несколькими списками, которые содержат начальные позиции основных моментов и время для них. Проблема в том, что мои основные моменты помещены слишком рано после следующего слова, которое собирается сказать двигатель TTS. Я не могу найти причину этого. Я думаю, что audioPositionMillis может быть неправильным, но, насколько я знаю, расчет правильный. Я думаю, что audioPositionMillis составляет около 700 миллисекунд слишком быстро. Я пропускаю что-то маленькое

   @Override
    protected synchronized void onSynthesizeText(SynthesisRequest request, SynthesisCallback callback) {

        // Note that we call onLoadLanguage here since there is no guarantee
        // that there was a prior call to this function.
        int load = onLoadLanguage(request.getLanguage(), request.getCountry(), request.getVariant());

        // We might get requests for a language we don't support - in which case
        // we error out early before wasting too much time.
        if (load == TextToSpeech.LANG_NOT_SUPPORTED) {
            callback.error();
            return;
        }

        String ttsText = request.getCharSequenceText().toString();
        final int speechRate = mapSpeechRate(request.getSpeechRate());
        TtsParams ttsParams = new TtsParams(ttsText, currentVoice, speechRate, VOLUME,
                TIME_BETWEEN_SENTENCES_MILLIS, BIT_RATE, TtsParams.Format.WAV);

        try {
            TtsInfo data = null;
            Response<TtsInfo> response = serviceManager.getTtsInfo(ttsParams); //Synchronous call because methods executed on the synthesisCallback need to be called on the synth thread.
            if(response != null){
                data = response.body();
            }

            if(data == null){
                callback.error();
                return;
            }

            //Response does not make any sense to me, we modify its data
            List<Integer> wordPositionsMs = data.getAudioPos();
            List<Integer> wordStartPositions = data.getCharPos();
            List<Integer> wordLengths = data.getCharCount();

            wordStartPositions.add(0, 0);
            wordStartPositions.remove(wordStartPositions.size() - 1);

            wordPositionsMs.add(0, 102); //First word always starts at 102ms according to the docs
            wordPositionsMs.remove(wordStartPositions.size() - 1);

            callback.start(SAMPLING_RATE_HZ, AudioFormat.ENCODING_PCM_16BIT, CHANNEL_COUNT);
            int maxBufferSize = callback.getMaxBufferSize();
            byte[] audioBuffer = Base64.decode(data.getByteArray(), Base64.DEFAULT);
            int offset = 0;
            while (offset < audioBuffer.length) {
                int bytesToWrite = Math.min(maxBufferSize, audioBuffer.length - offset);
                if(callback.audioAvailable(audioBuffer, offset, bytesToWrite) != TextToSpeech.SUCCESS){
                    callback.error();
                    return;
                }

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    long audioPositionMillis = Math.round(offset / ((SAMPLING_RATE_HZ/1000D) * CHANNEL_COUNT * (BIT_DEPTH/8D)));
                    int wordIndex = -1;
                    for (int i = 0; i < wordPositionsMs.size(); i++) {
                        if (audioPositionMillis > wordPositionsMs.get(i)) {
                            wordIndex++;
                        } else {
                            break;
                        }
                    }

                    if (wordIndex > -1) {
                        int wordStart = wordStartPositions.get(wordIndex);
                        int wordLength = wordLengths.get(wordIndex);
                        callback.rangeStart(-1, wordStart, wordStart + wordLength);
                    }
                }

                offset += bytesToWrite;
            }
            callback.done();
        } catch (IOException | NoNetworkException e) {
            e.printStackTrace();
            callback.error();
        }
    }

1 Ответ

0 голосов
/ 12 марта 2020

Я передал -1 в качестве параметра markerInFrames в метод обратного вызова rangeStart, который вызвал это.

Решение:

callback.rangeStart((int)(offset/(BIT_DEPTH/8D)), wordStart, wordStart + wordLength);
...