0

I'm using C#, WPF, and NAudio to play a wav file.

I have sound_1.wav in the Resources folder and included in project. Once compiled, it exports the exe and resources to a folder and plays the wav from a path on the hard drive.

string sound1 = "Resources\\sound_1.wav";

NAudio.Wave.WaveFileReader wav = new NAudio.Wave.WaveFileReader(sound1);
WaveOutEvent output = new WaveOutEvent();
output.Init(wav);
output.Play();

But I would like to embed the wav file in the exe and use something like:

UnmanagedMemoryStream sound1 = Properties.Resources.sound_1; //embedded resource
NAudio.Wave.WaveFileReader wav = new NAudio.Wave.WaveFileReader(sound1);

Embedded Resources

How can I get that to play through WaveFileReader? It only accepts string path.


Solutions

This works, but the sound plays in slow motion and sounds like reverb.

UnmanagedMemoryStream sound1 = Properties.Resources.sound_1;

WaveIn wavin = new WaveIn();
NAudio.Wave.RawSourceWaveStream wav = new NAudio.Wave.RawSourceWaveStream(sound1, wavin.WaveFormat);         
WaveOutEvent output = new WaveOutEvent();
output.Init(wav);
output.Play();

This works with loud pop at the end of sound.

Convert Stream to Byte Array
https://stackoverflow.com/a/1080445/6806643

byte[] b = ReadToEnd(sound1);

WaveStream wav = new RawSourceWaveStream(new MemoryStream(b), new WaveFormat(44100, 16, 2));
WaveOutEvent output = new WaveOutEvent();
output.Init(wav);
output.Play();
Matt McManis
  • 4,475
  • 5
  • 38
  • 93
  • 3
    Have you tried [extracting the embedded resource to a byte array](https://stackoverflow.com/questions/10412401/how-to-read-an-embedded-resource-as-array-of-bytes-without-writing-it-to-disk) & then [creating a WaveFileReader using a MemoryStream](https://stackoverflow.com/questions/33954614/playing-byte-using-naudio) – PaulF Mar 08 '18 at 16:53
  • @PaulF It still seems to require a string path. – Matt McManis Mar 08 '18 at 17:18
  • I am not sure what you mean - WaveFileReader accepts a Stream as a constructor - this can be a MemoryStream created from a byte array. You create the byte array by extracting the embedded resource. – PaulF Mar 08 '18 at 17:23
  • @PaulF They use `String filename`. When I change it to `UnmanagedMemoryStream filename` to extract the embedded resource it still requires `String` for `a.GetManifestResourceStream(filename)`. – Matt McManis Mar 08 '18 at 17:30
  • @MattMcManis: doesn't it work to pass sound1 to GetManifestResourceStream like in the first link PaulF (accepted answer by Rotem) has provided? – oliver Mar 08 '18 at 17:39
  • Have you tried accessing the embedded file through Properties.Resources.sound_1 --- _"NAudio.Wave.WaveFileReader wav = new NAudio.Wave.WaveFileReader(new MemoryStream(Properties.Resources.sound_1), true);"_ – PaulF Mar 08 '18 at 17:42
  • @PaulF Error: `cannot convert from System.IO.UnmanagedMemoryStream to init` – Matt McManis Mar 08 '18 at 17:45
  • @PaulF I updated my post, at the bottom is some code that almost works. – Matt McManis Mar 08 '18 at 17:52
  • What do you mean by "almost works"? – PaulF Mar 09 '18 at 10:24
  • @PaulF It had some audio popping and artifacts. I managed to figure it out, but it has really high RAM usage. https://stackoverflow.com/q/49186932/6806643 – Matt McManis Mar 09 '18 at 10:29
  • @PaulF Here is the solution I came up with, still with problems. https://stackoverflow.com/a/49191890/6806643 – Matt McManis Mar 09 '18 at 10:40

1 Answers1

1

I figured out how to make it work.

The problem with this solution is high memory usage.

WAV

// embedded resource sound.wav

UnmanagedMemoryStream sound = Properties.Resources.sound;

MemoryStream ms = new MemoryStream(StreamToBytes(sound));

WaveStream ws = new WaveFileReader(ms);

WaveOutEvent output = new WaveOutEvent();

output.PlaybackStopped += new EventHandler<StoppedEventArgs>(Media_Ended);
output.Init(ws);
output.Play();

MP3

// embedded resource sound.mp3

MemoryStream sound = new MemoryStream(Properties.Resources.sound);

MemoryStream ms = new MemoryStream(StreamToBytes(sound));

WaveStream ws = new Mp3FileReader(ms);

WaveOutEvent output = new WaveOutEvent();

output.PlaybackStopped += new EventHandler<StoppedEventArgs>(Media_Ended);
output.Init(ws);
output.Play();

Stream to Byte Array

https://stackoverflow.com/a/1080445/6806643

I used this to convert MemoryStream to byte[], or else it will crash if 2 sounds play at the same time with Exception "Not a WAVE file - no RIFF header".


Dispose

Doesn't seem to have any affect on reducing RAM.

public static void Media_Ended(object sender, EventArgs e)
{
    if (output.PlaybackState == PlaybackState.Stopped)
    {
        if (ms != null)
        {
            ms.Close();
            ms.Flush();
        }
        if (ws != null)
        {
            ws.Close();
        }
        if (output != null)
        {
            output.Dispose();
        }
    }
}
Community
  • 1
  • 1
Matt McManis
  • 4,475
  • 5
  • 38
  • 93