Search code examples
c#asp.net-mvcnaudiosoundtouch

How to use NAudio/SoundTouch to stream MP3 in ASP.NET MVC 5?


I am completely new to working with audio. I eventually want to stream an MP3 to a web page and allow user to alter the tempo. I got a HTML5 audio element set up and it can stream a MP3 fine. I can import the MP3 into NAudio.AudioFileReader and stream that to the page and that also works fine using the following code:

string fn = Server.MapPath("~/Uploads/Music/" + filename);
AudioFileReader reader = new AudioFileReader(fn);
MemoryStream outputStream = new MemoryStream();

using (NAudio.Wave.WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, reader.WaveFormat))
{
    byte[] bytes = new byte[reader.Length];
    reader.Position = 0;
    reader.Read(bytes, 0, (int)reader.Length);
    waveFileWriter.Write(bytes, 0, bytes.Length);
    waveFileWriter.Flush();
}

return File(outputStream.ToArray(), "audio/mp3");

I'm not even sure if this is the proper way to do this, but I modified some code I found online and this does work. However, when looking at the NAudio Varispeed demo which integrates the SoundTouch library and trying to incorporate it, it no longer works.

I modified my code like this:

string fn = Server.MapPath("~/Uploads/Music/" + filename);
AudioFileReader reader = new AudioFileReader(fn);
bool useTempo = true;
VarispeedSampleProvider speedControl = new VarispeedSampleProvider(reader, 100, new SoundTouchProfile(useTempo, false));
MemoryStream outputStream = new MemoryStream();

using (NAudio.Wave.WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, reader.WaveFormat))
{
    byte[] bytes = new byte[reader.Length];
    speedControl.Read(bytes.Select(b => (float)Convert.ToDouble(b)).ToArray(), 0, (int)reader.Length);
    waveFileWriter.Write(bytes, 0, bytes.Length);
    waveFileWriter.Flush();
}

return File(outputStream.ToArray(), "audio/mp3");

It builds and appears like it's working but when I hit play, I get no audio. What am I doing wrong here? Is this not even a good way to accomplish what I want?


Solution

  • You are reading into a temporary array (created by ToArray), so the audio you read is lost.

    Instead, declare a float[], read into that, and then write the contents of that into the waveFileWriter.

    Also, it is very important to use the return value from Read which will indicate the number of samples actually written into the array.