Я использую 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;
Для моего грубого тестирования он отлично работает, хотя использование отражения немного неприятно, оно лучше, чем запись файла на диск и открытие потока.