How to play a MP3 file using NAudio
Asked Answered
D

3

15
WaveStream waveStream = new Mp3FileReader(mp3FileToPlay);
var waveOut = new WaveOut();
waveOut.Init(waveStream); 
waveOut.Play();

This throws an exception:

WaveBadFormat calling waveOutOpen

The encoding type is "MpegLayer3" as NAudio.

How can I play a mp3 file with NAudio?

Deguzman answered 21/3, 2010 at 19:35 Comment(0)
E
10

Try like this:

class Program
{
    static void Main()
    {
        using (var ms = File.OpenRead("test.mp3"))
        using (var rdr = new Mp3FileReader(ms))
        using (var wavStream = WaveFormatConversionStream.CreatePcmStream(rdr))
        using (var baStream = new BlockAlignReductionStream(wavStream))
        using (var waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
        {
            waveOut.Init(baStream);
            waveOut.Play();
            while (waveOut.PlaybackState == PlaybackState.Playing)
            {
               Thread.Sleep(100);
            }
        }
    }
}

Edit this code is now out of date (relates to NAudio 1.3). Not recommended on newer versions of NAudio. Please see alternative answer.

Extricate answered 21/3, 2010 at 19:47 Comment(6)
This does not work. "InvalidParameter calling acmStreamPrepareHeader"Deguzman
I've just downloaded the latest version of NAudio (codeplex.com/naudio) and tested this code with an mp3 on my computer. It worked for me.Extricate
Do you have a 64bit environment? I have recompiled the solution using x64, release mode and changed the .net platform from .NET 2.0 to 3.5 ... maybe because of this I get the errors?Deguzman
Yes I am running on Win7 64bit, I had to target x86 in the project properties for this to work. Targeting Any CPU threw a BadImageFormatException for NAudio.dll.Extricate
thanks! Now it works :) I read anywhere that one shall recompile NAudio to x64 ...Deguzman
x64 support in NAudio is hopefully coming very soon. See recent checkins - naudio.codeplex.com/SourceControl/list/changesetsThrashing
T
57

For users of NAudio 1.6 and above, please do not use the code in the original accepted answer. You don't need to add a WaveFormatConversionStream, or a BlockAlignReductionStream, and you should avoid using WaveOut with function callbacks (WaveOutEvent is preferable if you are not in a WinForms or WPF application). Also, unless you want blocking playback, you would not normally sleep until audio finishes. Just subscribe to WaveOut's PlaybackStopped event.

The following code will work just fine to play an MP3 in NAudio:

var reader = new Mp3FileReader("test.mp3");
var waveOut = new WaveOut(); // or WaveOutEvent()
waveOut.Init(reader); 
waveOut.Play();
Thrashing answered 9/9, 2013 at 14:38 Comment(7)
Hey mark, thank you for your answer. I would like to know, according to your answer, where does the "test.mp3" file should be located at?Chante
Wow. Such a high voted answer with the exact code as written by OP - or where exactly is the difference? I can't spot one.Nephrectomy
WaveOut is disposable but never disposed in your code. If you dispose it, the audio stops playing. If you don't dispose it, it will likely only play until the garbage collector collects it.Nephrectomy
Also, the file remains in use, if the reader is not closed. This makes it impossible to e.g. move or rename the file in Explorer, even if playback has already stopped.Nephrectomy
@ThomasWeller that's because I'm assuming you're playing in a WinForms or WPF app. The code to dispose the Mp3FileReader and WaveOut device should happen when you've finished playing or are closing the form. See this tutorial for more detailsThrashing
@ThomasWeller you're right the question and answer have the same code. The difference is the date. When the original question asked, Mp3FileReader did not emit PCM from its Read method so the code didn't work. The original accepted answer is now not a recommended way to solve the problem.Thrashing
@MarkHeath - I recently stumbled upon NAudio after finally deciding that wmp's constant corruption of my playlists warranted a personal mp3 player project. In less than a day, with your library, I was able to easily create a wmp clone that respects playlists. I found your calling-out herein for your answer rather ironic, considering that you are, in fact, the author of NAudio. Your library has integrated so well into .NET 4.7+ on Windows 10 that it's only taken a few hours to fully implement. 6 years on from your initial reply, the code still performs as written. Thank you.Inclinable
E
10

Try like this:

class Program
{
    static void Main()
    {
        using (var ms = File.OpenRead("test.mp3"))
        using (var rdr = new Mp3FileReader(ms))
        using (var wavStream = WaveFormatConversionStream.CreatePcmStream(rdr))
        using (var baStream = new BlockAlignReductionStream(wavStream))
        using (var waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
        {
            waveOut.Init(baStream);
            waveOut.Play();
            while (waveOut.PlaybackState == PlaybackState.Playing)
            {
               Thread.Sleep(100);
            }
        }
    }
}

Edit this code is now out of date (relates to NAudio 1.3). Not recommended on newer versions of NAudio. Please see alternative answer.

Extricate answered 21/3, 2010 at 19:47 Comment(6)
This does not work. "InvalidParameter calling acmStreamPrepareHeader"Deguzman
I've just downloaded the latest version of NAudio (codeplex.com/naudio) and tested this code with an mp3 on my computer. It worked for me.Extricate
Do you have a 64bit environment? I have recompiled the solution using x64, release mode and changed the .net platform from .NET 2.0 to 3.5 ... maybe because of this I get the errors?Deguzman
Yes I am running on Win7 64bit, I had to target x86 in the project properties for this to work. Targeting Any CPU threw a BadImageFormatException for NAudio.dll.Extricate
thanks! Now it works :) I read anywhere that one shall recompile NAudio to x64 ...Deguzman
x64 support in NAudio is hopefully coming very soon. See recent checkins - naudio.codeplex.com/SourceControl/list/changesetsThrashing
M
0

my preferred way to play any MP3 files with NAudio is this. I prefer to block the playing thread until Playback stopped with event listeners. Also, for the best compatibility, I use MP3Sharp to load the MP3 file and then pass it to NAudio since NAudio did not come with MP3 codecs.

using System;
using NAudio.Wave;
using System.Threading;
using MP3Sharp;
using System.IO;

namespace jessielesbian.NAudioTest
{
    public static class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("loading and parsing MP3 file...");
            MP3Stream stream = new MP3Stream("c:\\workspaces\\Stunning!  Boeing's 737 MAX on Flying Display.mp3");
            WaveFormat waveFormat = new WaveFormat(stream.Frequency, stream.ChannelCount);
            Console.WriteLine("allocating playback cache...");
            FastWaveBuffer fastWaveBuffer = new FastWaveBuffer(waveFormat, (int) stream.Length);
            Console.WriteLine("populating playback cache...");
            stream.CopyTo(fastWaveBuffer);
            fastWaveBuffer.Seek(0, SeekOrigin.Begin);
            Console.WriteLine("unloading MP3 file...");
            stream.Dispose();
            Console.WriteLine("prepairing player...");
            WaveOutEvent waveOutEvent = new WaveOutEvent();
            waveOutEvent.Init(fastWaveBuffer);
            waveOutEvent.Volume = 1;
            Console.WriteLine("arming ManualResetEvent...");
            ManualResetEvent manualResetEvent = new ManualResetEvent(false);
            waveOutEvent.PlaybackStopped += (object sender, StoppedEventArgs e) => {
                manualResetEvent.Set();
            };
            Console.WriteLine("done!");
            waveOutEvent.Play();
            manualResetEvent.WaitOne();
        }
    }
    public sealed class FastWaveBuffer : MemoryStream, IWaveProvider
    {
        public FastWaveBuffer(WaveFormat waveFormat, byte[] bytes) : base(bytes)
        {
            WaveFormat = waveFormat;
        }
        public FastWaveBuffer(WaveFormat waveFormat, int size = 4096) : base()
        {
            WaveFormat = waveFormat;
            Capacity = size;
        }
        public WaveFormat WaveFormat
        {
            get;
        }
    }
}

Millepore answered 14/4, 2020 at 9:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.