Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using NAudio with SpeechSynthesizer

I would like to use NAudio together with SpeechSynthesizer, but I cannot make it work without writing a .wav file to disk first.

I cannot figure out why, I tried both RAW wave data and wave with headers, see the following examples...

Example 1 - this works, but saves a .wav file

  using (var synth = new SpeechSynthesizer())
  {
    synth.SetOutputToWaveFile(@".\Test.wav");
    synth.Speak("This is sample text-to-speech output.");
    synth.SetOutputToNull();

    var reader = new WaveFileReader(@".\Test.wav");
    var waveOut = new WaveOut();
    waveOut.Init(reader);
    waveOut.Play();
  }

Example 2 - this also works, but still uses a file

  using (var synth = new SpeechSynthesizer())
  using (var stream = new MemoryStream())
  {
    synth.SetOutputToWaveStream(stream);
    synth.Speak("This is sample text-to-speech output.");

    using (var fileStream = File.Create(@".\Test.wav"))
    {
      stream.Seek(0, SeekOrigin.Begin);
      stream.CopyTo(fileStream);
    }

    var reader = new WaveFileReader(@".\Test.wav");
    var waveOut = new WaveOut();
    waveOut.Init(reader);
    waveOut.Play();
  }

Example 3 - this don´t work, it just play a fraction of a second and stops

It´s on purpose that I use SetOutputToWaveStream to keep the RIFF header, to avoid setting wave format.

    using (var synth = new SpeechSynthesizer())
    using (var stream = new MemoryStream())
    {
      synth.SetOutputToWaveStream(stream);
      synth.Speak("This is sample text-to-speech output.");

      stream.Seek(0, SeekOrigin.Begin);
      var reader = new WaveFileReader(stream);
      var waveOut = new WaveOut();
      waveOut.Init(reader);
      waveOut.Play();
    }

Example 4 - same result as example 3

This uses raw data and is a bit bulky.

  using (var synth = new SpeechSynthesizer())
  using (var stream = new MemoryStream())
  {
    synth.SetOutputToAudioStream(stream, new SpeechAudioFormatInfo(44100, AudioBitsPerSample.Sixteen, AudioChannel.Mono));
    synth.Speak("This is sample text-to-speech output.");

    stream.Seek(0, SeekOrigin.Begin);
    IWaveProvider provider = new RawSourceWaveStream(stream, new WaveFormat(44100, 16, 1));
    var waveOut = new WaveOut();
    waveOut.Init(provider);
    waveOut.Play();
  }

I also tried using WasapiOut, but that was even worse.

like image 576
E. Malmqvist Avatar asked Nov 01 '22 00:11

E. Malmqvist


1 Answers

You are just about there with Example 3. Call Flush on your memory stream before repositioning to the start. Also, Play only starts playing, so you need to either wait for playback to finish or move your WaveOut instance to be outside the using block. Otherwise it's just going to get garbage collected before it can get very far into playback.

like image 174
Mark Heath Avatar answered Nov 15 '22 05:11

Mark Heath