TTS для потока с помощью rephaudioformatinfo с использованием рецепсинтесизатора

StackOverflow https://stackoverflow.com/questions/3875778

Вопрос

я использую System.speech.synthesis.speechsynThesizer. Конвертировать текст в речь. И из-за анемической документации Microsoft (см. Мою ссылку, нет замечаний или примеров кода) У меня проблемы с возникновением головы или хвоста разницы между двумя методами:

EtoututtoaudioTream и setoutputtowavestream.

Вот что я выводил:

SetoutTtoToaudiOream принимает поток и экземпляр of rephaudioformatinfo, который определяет формат волнового файла (образцы в секунду, биты в секунду, аудиоканалы и т. Д.) И записывает текст на поток.

SetoutPutToWavestream принимает только поток и пишет 16 бит, моно, 22 кГц, PCM Wave для потока. Там нет способа пройти в Репозиоформатинфо.

Моя проблема - это setoutpttoaudiOream не пишет действительный волновой файл в поток. Например, я получаю InvalidOperationException («Заголовок волны поврежден») при прохождении потока в System.Media.SoundPlayer. Если я напишу поток на диск и попытаюсь воспроизвести его с WMP, я получаю сообщение «Windows Media Player не может воспроизводить файл ...», но поток, написанный SetoutPutToWavestream, правильно играет в обоих. Моя теория заключается в том, что setoutttoaudioStream не пишет (действительный) заголовок.

Чрезвычайно конвенции именования для сайтатует * бла * несовместимо. Setoutputtovavefile принимает repoaDioformatinfo, пока setoutputtowavestream не делает.

Мне нужно иметь возможность написать 8 кГц, 16-битную, моноволновую волновую волну к потоку, то, что ни на компьютере нет тотаудиострема, ни SetoutPutToWaveStream, не позволяют мне делать. У кого-нибудь есть понимание рехсинтесайзера и эти два метода?

Для справки, вот какой-то код:

Stream ret = new MemoryStream();
using (SpeechSynthesizer synth = new SpeechSynthesizer())
{
  synth.SelectVoice(voiceName);
  synth.SetOutputToWaveStream(ret);
  //synth.SetOutputToAudioStream(ret, new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Sixteen, AudioChannel.Mono));
  synth.Speak(textToSpeak);
}

Решение:

Большое спасибо @hans Passant, вот суть того, что я использую сейчас:

Stream ret = new MemoryStream();
using (SpeechSynthesizer synth = new SpeechSynthesizer())
{
  var mi = synth.GetType().GetMethod("SetOutputStream", BindingFlags.Instance | BindingFlags.NonPublic);
  var fmt = new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Sixteen, AudioChannel.Mono);
  mi.Invoke(synth, new object[] { ret, fmt, true, true });
  synth.SelectVoice(voiceName);
  synth.Speak(textToSpeak);
}
return ret;

Для моего грубого тестирования он отлично работает, хотя использование отражения немного ICKY лучше, чем писать файл на диск и открытие потока.

Это было полезно?

Решение

Ваш фрагмент кода Borked, вы используете синтезатор после того, как это расположено. Но это не реальная проблема, я уверен. SetoutPuttoaudiOream производит RAW PCM AUDIO, «Числа». Без формата файла контейнера (заголовки), как то, что используется в файле .wav. Да, это нельзя воспроизводить с обычной медиа-программой.

Отсутствует перегрузка для SetoutPutToWavestream, которая принимает rephaudiofmatinfo, странно. Это действительно похоже на надзор для меня, хотя это очень редко редко в .NET Framework. Там нет убедительных причин, почему она не должна работать, базовый интерфейс SAPI поддерживает его. Его можно взломать с отражением, чтобы позвонить в частном методе SetoutPuTStream. Это работало нормально, когда я проверял это, но я не могу поручиться за это:

using System.Reflection;
...
            using (Stream ret = new MemoryStream())
            using (SpeechSynthesizer synth = new SpeechSynthesizer()) {
                var mi = synth.GetType().GetMethod("SetOutputStream", BindingFlags.Instance | BindingFlags.NonPublic);
                var fmt = new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Eight, AudioChannel.Mono);
                mi.Invoke(synth, new object[] { ret, fmt, true, true });
                synth.Speak("Greetings from stack overflow");
                // Testing code:
                using (var fs = new FileStream(@"c:\temp\test.wav", FileMode.Create, FileAccess.Write, FileShare.None)) {
                    ret.Position = 0;
                    byte[] buffer = new byte[4096];
                    for (;;) {
                        int len = ret.Read(buffer, 0, buffer.Length);
                        if (len == 0) break;
                        fs.Write(buffer, 0, len);
                    }
                }
            }

Если вам неудобно с взлом, то используя path.gettempfilename (), чтобы временно поток его в файл, безусловно, будет работать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top