E. Malmqvist
E. Malmqvist

Reputation: 310

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.

Upvotes: 5

Views: 2508

Answers (2)

Pierre-Olivier Pignon
Pierre-Olivier Pignon

Reputation: 747

this code works for me, if can help (for solution 3).

        IWaveProvider provider = null;
        var stream = new MemoryStream();
        using (var synth = new SpeechSynthesizer())
        {

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

            stream.Seek(0, SeekOrigin.Begin);
            provider = new RawSourceWaveStream(stream, new WaveFormat(44100, 16, 1));

        }
        var waveOut = new WaveOut();
        waveOut.Init(provider);
        waveOut.Play();

Upvotes: 1

Mark Heath
Mark Heath

Reputation: 49482

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.

Upvotes: 2

Related Questions