如何使用NAudio播放MP3文件

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

这会抛出一个异常:

当调用 waveOutOpen 时,WaveBadFormat

Nadudio 中的编码类型是 "MpegLayer3"。

我该如何使用 NAudio 播放 mp3 文件?

3个回答

55

对于NAudio 1.6及以上版本的用户,请不要使用原始已接受答案中的代码。您不需要添加 WaveFormatConversionStreamBlockAlignReductionStream,并且应避免在使用函数回调时使用 WaveOut(如果您不在WinForms或WPF应用程序中,则最好使用 WaveOutEvent)。此外,除非您想要阻塞播放,否则通常不会等到音频完成才休眠。只需订阅WaveOutPlaybackStopped 事件即可。

以下代码将很好地播放 NAudio 中的 MP3:

var reader = new Mp3FileReader("test.mp3");
var waveOut = new WaveOut(); // or WaveOutEvent()
waveOut.Init(reader); 
waveOut.Play();

嘿,马克,谢谢你的回答。根据你的回答,我想知道“test.mp3”文件应该放在哪里? - Eido95
1
哇,这个回答得票率很高,代码与原帖完全一样,或者说有什么区别?我看不出来。 - Thomas Weller
WaveOut是一次性的,但在您的代码中永远不会被处理。如果您处理它,音频将停止播放。如果您不处理它,则它可能只会播放到垃圾收集器将其收集为止。 - Thomas Weller
3
@ThomasWeller 你说得对,问题和答案的代码是一样的。不同之处在于日期。当最初提出这个问题时,Mp3FileReader没有从其Read方法中发出PCM,因此代码无法工作。原始的被接受的答案现在不是解决问题的推荐方式。 - Mark Heath
4
@MarkHeath - 最近我决定开展一个个人MP3播放器项目,因为WMP一直损坏我的播放列表。在偶然发现NAudio后,在不到一天的时间里,通过使用你的库,我很容易地创建了一个尊重播放列表的WMP克隆。我认为你在这里发表回答有些讽刺意味,因为事实上你就是NAudio的作者。你的库已经与Windows 10上的.NET 4.7+集成得非常好,只用了几个小时就可以完全实现。距离您最初的回复已经过去6年了,代码仍然像当初编写的那样有效。谢谢。 - BJS3D
显示剩余2条评论

10

试试这样:

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

编辑此代码已经过时(涉及到NAudio 1.3)。不建议在更新的版本中使用。请参考替代答案。


1
这个不起作用。"调用acmStreamPrepareHeader时出现InvalidParameter"。 - Rookian
我刚刚下载了最新版本的NAudio(http://www.codeplex.com/naudio),并在我的电脑上使用mp3测试了这段代码。对我来说它有效。 - Darin Dimitrov
你有64位环境吗?我已经重新编译了解决方案,使用x64、发布模式,并将.NET平台从.NET 2.0更改为3.5...也许是因为这个原因导致了错误? - Rookian
1
是的,我正在运行Win7 64位操作系统,为了使其正常工作,我必须在项目属性中选择x86。选择“任何CPU”会导致“NAudio.dll”出现“BadImageFormatException”的错误。 - Darin Dimitrov
谢谢!现在它可以工作了 :) 我在任何地方都看到过,应该将NAudio重新编译为x64... - Rookian
1
x64支持在NAudio中很快就会到来。请查看最近的提交- http://naudio.codeplex.com/SourceControl/list/changesets - Mark Heath

0

我在使用NAudio播放MP3文件时,更喜欢采用以下方式。我倾向于阻塞播放线程,直到通过事件监听器停止播放。此外,为了获得最佳兼容性,我使用MP3Sharp加载MP3文件,然后将其传递给NAudio,因为NAudio没有附带MP3编解码器。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接