How to play WAV file from Embedded Resources with NAudio? - c#

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);
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();

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();
}
}
}

Related

MemoryStream into MagicImage

I am trying to store MemoryStream into MagicImage, but when I am trying to upload file with heic format it still uploading with heic format, but it should upload it with jpeg format. So I kind of do not understand where I am doing wrong. So could someone help me? I am trying it open in Frame in web, but it does not open bc it is not converting it to jpeg.
using (MemoryStream ms = new MemoryStream())
{
create.PostedFile.InputStream.CopyTo(ms);
var data = ms.ToArray();
byte[] data1 = null;
using (var image = new MagickImage(data))
{
// Sets the output format to jpeg
image.Format = MagickFormat.Jpeg;
// Create byte array that contains a jpeg file
data1 = image.ToByteArray();
}
var file = new ClientFile
{
Data = data1, // here where it should store it in jpeg
};
While I have never used your way of writing the image, this is what I use in my implementations and it always works:
var image = new MagickImage(sourceStream);
var format = MagickFormat.Jpg;
var stream = new MemoryStream();
image.Write(stream, format);
stream.Position = 0;
EDIT
If you don't add:
stream.Position = 0
sending the stream will not work as it will start saving from the current position which is at the end of the stream.

Mix two or more mp3 files into one, keeping high performance

I have a problem mixing two mp3 files into one. Actually, I've found some test code to do that using NAudio library, but it is too slow for me. I am new to "audio programming" so I need your help, advice how to make an algorithm solving this problem faster than the code below.
The code mixes two files into one in 8+seconds which is much much too slow. Actually, I checked and ConvertWavToMp3() lasts 8 seconds. Files 1.mp3 and 2.mp3 are like 3+ minutes long.
static void Main(string[] args)
{
var watch = Stopwatch.StartNew();
watch.Start();
var path = #"C:\Users\gutek\Desktop\";
// read mp3 files from disk
Mp3FileReader mpbacground = new Mp3FileReader(path + "1.mp3");
Mp3FileReader mpMessage = new Mp3FileReader(path + "2.mp3");
//convert them into wave stream or decode the mp3 file
WaveStream background = WaveFormatConversionStream.CreatePcmStream(mpbacground);
WaveStream message = WaveFormatConversionStream.CreatePcmStream(mpMessage);
var mixer = new WaveMixerStream32();
mixer.AutoStop = true;
var messageOffset = background.TotalTime;
var messageOffsetted = new WaveOffsetStream(
message, TimeSpan.FromSeconds(10), TimeSpan.Zero, message.TotalTime.Subtract(TimeSpan.FromSeconds(30)));
var background32 = new WaveChannel32(background);
background32.PadWithZeroes = false;
// set the volume of background file
background32.Volume = 0.4f;
//add stream into the mixer
mixer.AddInputStream(background32);
var message32 = new WaveChannel32(messageOffsetted);
message32.PadWithZeroes = false;
// set the volume of 2nd mp3 song
message32.Volume = 0.6f;
mixer.AddInputStream(message32);
var wave32 = new Wave32To16Stream(mixer);
//encode the wave stream into mp3
var mp3Stream = ConvertWavToMp3(wave32);
// write mp3 on the disk
File.WriteAllBytes(path + "output.mp3", mp3Stream.ToArray());
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
Console.ReadKey();
}
public static MemoryStream ConvertWavToMp3(Wave32To16Stream wavFile)
{
using (var retMs = new MemoryStream())
using (var wtr = new LameMP3FileWriter(retMs, wavFile.WaveFormat, 128))
{
wavFile.CopyTo(wtr);
return retMs;
}
}

Unable to download audio with MediaLibraryExtensions.SaveSong in windows phone 8

I am trying to download an audio and saving to isolated storage and saving to emulator.
I tried with the following code.
WebClient m_webClient = new WebClient();
m_webClient.OpenReadAsync(fileUri);
m_webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_ImageOpenReadCompleted);
m_webClient.AllowReadStreamBuffering = true;
private static void webClient_ImageOpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
var isolatedfile = IsolatedStorageFile.GetUserStoreForApplication();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(_fileName, System.IO.FileMode.Create, isolatedfile))
{
byte[] buffer = new byte[e.Result.Length];
while (e.Result.Read(buffer, 0, buffer.Length) > 0)
{
stream.Write(buffer, 0, buffer.Length);
}
}
SaveFileMP3(_fileName);
}
private static void SaveFileMP3(string _fileName)
{
MediaLibrary lib = new MediaLibrary();
Uri songUri = new Uri(_fileName, UriKind.RelativeOrAbsolute);
MediaLibraryExtensions.SaveSong(lib, songUri, null, SaveSongOperation.CopyToLibrary);
}
The problem I am facing is, the audio getting saved to the emulator but not with the extension. Suppose the file name "test.MP3", it is saved as "test" and the duration is always 0:0:00 irrespective to the original duration.
I have added Audio capability too in the manifest file.
Following is the screenshot while saving the song, which has many exceptions in it.
Please correct if something is wrong with code. Thanks in advance.
By adding the line of lib.savesong worked perfectly instead of using mediaLibraryExtensions.
private static void SaveFileMP3(string _fileName)
{
MediaLibrary lib = new MediaLibrary();
Uri songUri = new Uri(_fileName, UriKind.RelativeOrAbsolute);
lib.SaveSong(songUri, null, SaveSongOperation.CopyToLibrary);
//MediaLibraryExtensions.SaveSong(lib, songUri, null, SaveSongOperation.CopyToLibrary);
}

Play from a memory stream(which doesn't contain wav headers) in WPF

I try to concatenate some data in different durations but same sample rate.
I concatenate the data with MemoryStream.CopyTo(memoryStream) method.
Is there any way to play a data from a memory stream which don't have a wav header in the start?
And if not, is there any way to append a wav headers to to start after the stream was appended?
(I want to avoid generating a file in the disk..)
To do this with NAudio, just use a RawSourceWaveStream and pass in the MemoryStream containing the raw concatenated audio to its constructor. You'll also need to explicitly specify that the WaveFormat is.
memoryStream = ... // construct your audio
memoryStream.Position = 0; // rewind to beginning
var rs = new RawSourceWaveStream(memoryStream, new WaveFormat(sampleRate, 16, 1));
You can write header to your stream, then play the WAV with SoundPlayer.
//your wav streams
MemoryStream wavNoHeader1=new MemoryStream();
MemoryStream wavNoHeader2 = new MemoryStream();
//result WAV stream
MemoryStream wav=new MemoryStream();
//create & write header
ushort numchannels = 1;
ushort samplelength = 1; // in bytes
uint samplerate = 22050;
int wavsize = (int) ((wavNoHeader1.Length + wavNoHeader2.Length)/(numchannels*samplelength));
BinaryWriter wr = new BinaryWriter(wav);
wr.Write(Encoding.ASCII.GetBytes("RIFF"));
wr.Write(36 + wavsize);
wr.Write(Encoding.ASCII.GetBytes("WAVEfmt "));
wr.Write(16);
wr.Write((ushort)1);
wr.Write(numchannels);
wr.Write(samplerate);
wr.Write(samplerate * samplelength * numchannels);
wr.Write(samplelength * numchannels);
wr.Write((ushort)(8 * samplelength));
wr.Write(Encoding.ASCII.GetBytes("data"));
wr.Write(numsamples * samplelength);
//append data from raw streams
wavNoHeader1.CopyTo(wav);
wavNoHeader2.CopyTo(wav);
//play
wav.Position = 0;
SoundPlayer sp=new SoundPlayer(wav);
sp.Play();

c#: Overlay mp3 file to another

I have merged 3 mp3 files into one mp3 file simply using the following code
using (var fs = File.OpenWrite(Path.Combine(txtOutputFile.Text, "new.mp3")))
{
var buffer = File.ReadAllBytes(Path.Combine(txtIntroLoc.Text, fileName1));
fs.Write(buffer, 0, buffer.Length);
buffer = File.ReadAllBytes(Path.Combine(txtOutroloc.Text, fileName2));
fs.Write(buffer, 0, buffer.Length);
buffer = File.ReadAllBytes(Path.Combine(txtFileThree.Text, fileName3));
fs.Write(buffer, 0, buffer.Length);
fs.Flush();
}
What i want is to overlay another mp3 file which will play in the background of this newly created mp3 file. I know its possible but not getting right way to go to acheive this. Any help will be great.
thanks
On the question of "overlaying":
There is no way of doing this without decoding the original to PCM, mixing in your overlay, and then re-encoding the whole thing to MP3.
On your existing code:
You can just about get away with concatenating MP3 files like this. Usually though I would at recommend ditching the ID3 tags, and just making one file that has the MP3 frames from each file. If you are using NAudio, then you can use the ReadNextFrame() method on Mp3FileReader to get each MP3 frame and write its RawBytes out to the file.
For best results, you'd want all the MP3 files to use the same sample rate and channel count. Also, if these are VBR, you'll be invalidating the information in the XING or VBRI headers, so it might even be best to ditch those as well.
Finally i found a solution. Using NAudio we can mix the wav stream so first converting the mp3 to wav and then mixing the wav files and then re convert the resulted wav file to mp3 using the lame.exe.
Convert MP3 to WAV can be performed using the following piece of code using NAudio library thanks to Mark Heath.
string file = "new.mp3";
Mp3FileReader readers = new Mp3FileReader(file);
WaveFormat targetFormat = new WaveFormat();
WaveStream convertedStream = new WaveFormatConversionStream(targetFormat, readers);
WaveFileWriter.CreateWaveFile("firstwav.wav", convertedStream);
Now mixing it with another wav file can be performed using this code consuming the NAudio classes.
string[] inputFiles = new string[2];
Stream output = new MemoryStream();
inputFiles[0] = "firstwav.wav";
inputFiles[1] = "secondwav.wav";
mixWAVFiles(inputFiles);
The mixWAVFiles Method
public void mixWAVFiles(string[] inputFiles)
{
int count = inputFiles.GetLength(0);
WaveMixerStream32 mixer = new WaveMixerStream32();
WaveFileReader[] reader = new WaveFileReader[count];
WaveChannel32[] channelSteam = new WaveChannel32[count];
mixer.AutoStop = true;
for (int i = 0; i < count; i++)
{
reader[i] = new WaveFileReader(inputFiles[i]);
channelSteam[i] = new WaveChannel32(reader[i]);
mixer.AddInputStream(channelSteam[i]);
}
mixer.Position = 0;
WaveFileWriter.CreateWaveFile("mixedWavFile.wav", mixer);
}
And now finally converting the finalwav file to mp3 using lame.exe found here
public void convertWAVtoMP3(string wavfile)
{
//string lameEXE = #"C:\Users\Jibran\Desktop\MP3 Merger\bin\Debug\lame.exe";
string lameEXE = Path.GetDirectoryName(Application.ExecutablePath) +"/lame.exe";
string lameArgs = "-V2";
string wavFile = wavfile;
string mp3File = "mixed.mp3";
Process process = new Process();
process.StartInfo = new ProcessStartInfo();
process.StartInfo.FileName = lameEXE;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.Arguments = string.Format(
"{0} {1} {2}",
lameArgs,
wavFile,
mp3File);
process.Start();
process.WaitForExit();
int exitCode = process.ExitCode;
}

Categories