如何使用 NAudio 播放嵌入式资源中的 WAV 文件?

问题描述 投票:0回答:2

我正在使用 C#、WPF 和 NAudio 来播放

wav
文件。

我在资源文件夹中有

sound_1.wav
并包含在项目中。编译后,它将 exe 和资源导出到文件夹并从硬盘驱动器上的路径播放 wav。

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

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

但我想将

wav
文件嵌入到
exe
中并使用类似以下内容:

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

我怎样才能让它播放完

WaveFileReader
?它只接受
string
路径。


解决方案

这可行,但声音以慢动作播放,听起来像混响。

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

这适用于声音结束时发出响亮的爆音。

将流转换为字节数组
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();
c# naudio
2个回答
2
投票

我想出了如何让它发挥作用。

此解决方案的问题是内存使用率较高。

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

流到字节数组

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

我用它来将

MemoryStream
转换为
byte[]
,否则如果
Exception "Not a WAVE file - no RIFF header"
同时播放2个声音,它会崩溃。


丢弃

似乎对减少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();
        }
    }
}

0
投票

这是一个简单的解决方案,它也适用于 .aif 和 aiff 文件,并且不需要拆分 .mp3 和 .wav 文件。可以使用

AudioFileReader
类来完成,但该类不支持
Stream
,仅支持文件路径。但是,我们可以通过使用一些反射来创建带有
AudioFileReader
Stream
实例来跳过这个问题。只需将代码粘贴到代码中的某个位置即可:

namespace NAudio.Extensions
{
public static class Extensions
{
    public static AudioFileReader GetAudioFileReaderFromStream(Stream stream, string fileExt)
    {
        try
        {
            AudioFileReader reader = (AudioFileReader)FormatterServices.GetUninitializedObject(typeof(AudioFileReader));

            // this is how the constructor looks
            //lockObject = new object();
            //FileName = fileName;
            //CreateReaderStream(fileName);
            //sourceBytesPerSample = readerStream.WaveFormat.BitsPerSample / 8 * readerStream.WaveFormat.Channels;
            //sampleChannel = new SampleChannel(readerStream, forceStereo: false);
            //destBytesPerSample = 4 * sampleChannel.WaveFormat.Channels;
            //length = SourceToDest(readerStream.Length);

            Type type = reader.GetType();
            type.GetField("lockObject", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, new object());
            var readerStream = GetWaveStream(stream, fileExt);
            type.GetField("readerStream", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, readerStream);
            var sbps = readerStream.WaveFormat.BitsPerSample / 8 * readerStream.WaveFormat.Channels;
            type.GetField("sourceBytesPerSample", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, sbps);
            var sampleChannel = new SampleChannel(readerStream, forceStereo: false);
            type.GetField("sampleChannel", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, sampleChannel);
            var dbps = 4 * sampleChannel.WaveFormat.Channels;
            type.GetField("destBytesPerSample", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, dbps);
            var std = dbps * (readerStream.Length / sbps);
            type.GetField("length", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(reader, std);

            return reader;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
            return null;
        }
    }

    private static WaveStream GetWaveStream(Stream stream, string fileExt)
    {
        WaveStream readerStream = null;
        if (fileExt.Equals(".wav", StringComparison.OrdinalIgnoreCase))
        {
            readerStream = new WaveFileReader(stream);
            if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm && readerStream.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat)
            {
                readerStream = WaveFormatConversionStream.CreatePcmStream(readerStream);
                readerStream = new BlockAlignReductionStream(readerStream);
            }
        }
        else if (fileExt.Equals(".mp3", StringComparison.OrdinalIgnoreCase))
        {
            if (Environment.OSVersion.Version.Major < 6)
            {
                readerStream = new Mp3FileReader(stream);
            }
            else
            {
                readerStream = new StreamMediaFoundationReader(stream);
            }
        }
        else if (fileExt.Equals(".aiff", StringComparison.OrdinalIgnoreCase) || fileExt.Equals(".aif", StringComparison.OrdinalIgnoreCase))
        {
            readerStream = new AiffFileReader(stream);
        }
        else
        {
            readerStream = new StreamMediaFoundationReader(stream);
        }
        return readerStream;
    }
}
}

然后你就可以像这样使用它,只需指定文件类型(“.wav”,“.mp3”,“.aif”或“.aiff”):

AudioFileReader reader = NAudio.Extensions.Extensions.GetAudioFileReaderFromStream(myStream, ".wav");
© www.soinside.com 2019 - 2024. All rights reserved.