TTS для потоковой передачи с SpeechAudioFormatInfo с использованием SpeechSynthesizer

Я использую System.Speech.Synthesis.SpeechSynthesizer для преобразования текста в речь. И из-за анемичной документации Microsoft (см. Мою ссылку, здесь нет замечаний или примеров кода) у меня возникли проблемы с определением разницы между двумя методами:

SetOutputToAudioStream и SetOutputToWaveStream.

Вот что я сделал:

SetOutputToAudioStream принимает поток и экземпляр SpeechAudioFormatInfo, который определяет формат волнового файла (выборок в секунду, бит в секунду, аудиоканалы и т. д.) и записывает текст в поток.

SetOutputToWaveStream берет только поток и записывает в поток 16-битный, моно, 22 кГц, файл PCM wave. Нет возможности передать SpeechAudioFormatInfo.

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

Как ни странно, соглашения об именах для SetOutputTo * Blah * несовместимы. SetOutputToWaveFile принимает SpeechAudioFormatInfo, а SetOutputToWaveStream - нет.

Мне нужно иметь возможность записывать в поток 16-битный монофонический волновой файл с частотой 8 кГц, чего мне не позволяют ни SetOutputToAudioStream, ни SetOutputToWaveStream. Кто-нибудь знает о SpeechSynthesizer и этих двух методах?

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

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;

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

8
задан AceJordin 6 October 2010 в 20:23
поделиться