Я использую System.Speech.Synthesis.SpeechSynthesizer для преобразования текста в речь. И из-за анемичной документации Microsoft (см. Мою ссылку, здесь нет замечаний или примеров кода), у меня возникают проблемы с пониманием различий между двумя методами:
SetOutputToAudioStream и SetOutputToWaveStream.
Вот что я вывел:
SetOutputToAudioStream принимает поток и экземпляр SpeechAudioFormatInfo, который определяет формат волнового файла (выборок в секунду, бит в секунду, аудиоканалов и т. Д.) И записывает текст в поток.
SetOutputToWaveStream берет только поток и записывает 16-битный моно, 22 кГц, волновой файл PCM в поток. Нет способа передать в 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;
Для моего грубого тестирования это прекрасно работает, хотя использование отражения немного странно, это лучше, чем записать файл на диск и открыть поток.