Używam System.Speech.Synthesis.SpeechSynthesizer do konwersji tekstu na mowę. I z powodu anemicznej dokumentacji Microsoftu (zobacz mój link, nie ma uwag ani przykładów kodu) Mam problem z rozróżnieniem dwóch metod:TTS do strumieniowego z SpeechAudioFormatInfo przy użyciu SpeechSynthesizer
SetOutputToAudioStream i SetOutputToWaveStream.
Oto co mam wydedukować:
SetOutputToAudioStream zajmuje strumień oraz instancję SpeechAudioFormatInfo, który określa format pliku wave (próbek na sekundę, bitów na sekundę, kanały audio, etc.) i pisze tekst strumień.
SetOutputToWaveStream pobiera tylko strumień i zapisuje 16-bitowy, mono, 22kHz, plik wave PCM do strumienia. Nie ma sposobu, aby przekazać w SpeechAudioFormatInfo.
Mój problem to SetOutputToAudioStream nie zapisuje prawidłowego pliku wave do strumienia. Na przykład otrzymuję wyjątek InvalidOperationException ("Nagłówek fali jest uszkodzony") podczas przesyłania strumienia do System.Media.SoundPlayer. Jeśli napiszę strumień na dysk i spróbuję go odtworzyć przy pomocy WMP, otrzymam komunikat "Windows Media Player nie może odtwarzać pliku ...", ale strumień napisany przez SetOutputToWaveStream będzie poprawnie odtwarzany w obu. Moja teoria mówi, że SetOutputToAudioStream nie pisze (poprawnego) nagłówka.
Co dziwne konwencje nazewnictwa SetOutputTo * Blah * są niespójne. SetOutputToWaveFile pobiera SpeechAudioFormatInfo, gdy SetOutputToWaveStream nie.
Potrzebuję móc napisać plik fali mono 8kHz, 16-bitowy, do strumienia, coś, co ani SetOutputToAudioStream ani SetOutputToWaveStream nie pozwalają mi zrobić. Czy ktokolwiek ma wgląd w SpeechSynthesizer i te dwie metody?
Dla porównania, oto niektóre kod:
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);
}
Rozwiązanie:
Wiele dzięki @Hans Passant, tu jest sedno tego, co używam teraz:
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;
W moim surowym testowaniu działa świetnie, chociaż użycie refleksji jest trochę niefortunne, lepsze to niż zapisanie pliku na dysk i otwarcie strumienia.
Chodźmy o tym myśleć, ostatni argument prawdopodobnie powinien być fałszywy, aby nie zamykać strumienia. Nie ma znaczenia dla MemoryStream. –
Masz rację, synth.Speak() był w użyciu w moim kodzie. Edytowałem fragment kodu. Daję twojemu kodowi strzał, wygląda na to, że spełni to, o co proszę. Zgadzam się, że wygląda na niedopatrzenie. Dzięki! – AceJordin