如何使用 C# NAudio 操作字节?

Posted

技术标签:

【中文标题】如何使用 C# NAudio 操作字节?【英文标题】:How to manipulate bytes with C# NAudio? 【发布时间】:2019-03-11 07:44:54 【问题描述】: 我目前能够:记录来自音频输入的数据,在磁盘上使用该数据生成 wav 文件,从磁盘播放 wav。 我想要完成的工作:获取通过 NAudio 读取的原始字节,将 wav、特定字节转换为 mp3,播放 mp3(无需在磁盘上写入任何内容)。

使用的代码:

    public WaveIn waveSource = null;
    public WaveFileWriter waveFile = null;
    public List<byte> soundBytesList = new List<byte>();

    private void waveSource_DataAvailable(object sender, WaveInEventArgs e)
    
        if (waveFile != null)
            for (int i = 0; i < e.BytesRecorded; ++i)
                soundBytesList.Add(e.Buffer[i]);
            waveFile.Write(e.Buffer, 0, e.BytesRecorded);
            waveFile.Flush();
    

    public void waveSource_RecordingStopped(object sender, StoppedEventArgs e)
    
        if (waveSource != null)
        
            waveSource.Dispose();
            waveSource = null;
        
        if (waveFile != null)
        
            waveFile.Dispose();
            waveFile = null;
        
    

    private void RecordButton_MouseDown(object sender, EventArgs e)
    
        waveSource = new WaveIn();
        waveSource.WaveFormat = new WaveFormat(44100, 1);

        waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
        waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);

        waveFile = new WaveFileWriter("test.wav", waveSource.WaveFormat);

        waveSource.StartRecording();
    

    private void RecordButton_MouseUp(object sender, EventArgs e)
    
        waveSource.StopRecording();

        byte[] soundBytesArrayWAV = soundBytesList.ToArray();          
        byte[] outB = ConvertWavToMp3(soundBytesArrayWAV );
        File.WriteAllBytes("test.mp3", outB);
    

        public byte[] ConvertWavToMp3(byte[] wavFile)
        
            using (var retMs = new MemoryStream())
            using (var ms = new MemoryStream(wavFile))
            using (var rdr = new WaveFileReader(ms))
            using (var wtr = new LameMP3FileWriter(retMs, rdr.WaveFormat, 128))
            
                rdr.CopyTo(wtr);
                wtr.Flush();
                return retMs.ToArray();
            
        

问题是我在 ConvertWavToMp3 方法上收到一个错误,它说提供的字节数组 (soundBytesArrayWAV) 没有 RIFF(特定于 wav 的标头)。我的猜测是我没有正确获取soundBytesList 中的所有字节,因为如果我将所有字节加载到内存中(从磁盘写入 wav),转换工作正常。 你能帮帮我吗?

【问题讨论】:

您只是在waveSource_DataAvailable 中向soundBytesList 添加字节。如果您不想编写文件,我不清楚为什么要创建带有文件名的WaveFileWriter - 为什么不为此使用MemoryStream,然后在ConvertWavToMp3 中设置它的位置MemoryStream 到 0 之前将其传递给 WaveFileReader 构造函数?基本上你想让WaveFileReader 看到WaveFileWriter 写的所有数据... 你是对的,乔恩!我想处理数据而不将其写入文件,就像我现在一样。这是我的初始代码,这就是为什么它是这样的。我现在想更新它。你的方法听起来像我需要的东西。您能否给我一些有关如何在我的代码中使用 MemoryStream 的更多信息?我是新手,抱歉。 好吧,你应该有一个MemoryStream 字段,而不是soundBytesList。您将在RecordButton_MouseDown 中创建流并将其传递给WaveFileWriter 构造函数。然后在RecordButton_MouseUp中使用,在“倒带”之后。 哦,成功了!没有考虑在 writer 构造函数中使用流。谢谢你,乔恩!您可以将您的建议作为答案发布,如果您愿意,我会对其进行验证。 恐怕我要花更长的时间来详细地写出来,而不是我现在有时间 - 但你总是可以自己这样做作为答案。 【参考方案1】:

根据@Jon Skeet 建议更新的功能代码如下:

    public WaveIn waveSource = null;
    public WaveFileWriter waveFile = null;
    public MemoryStream memStream = null;

    private void waveSource_DataAvailable(object sender, WaveInEventArgs e)
    
        if (waveFile != null)
        
            waveFile.Write(e.Buffer, 0, e.BytesRecorded);
            waveFile.Flush();
        
    

    public void waveSource_RecordingStopped(object sender, StoppedEventArgs e)
    
        if (waveSource != null)
        
            waveSource.Dispose();
            waveSource = null;
        
        if (waveFile != null)
        
            waveFile.Dispose();
            waveFile = null;
        
    

    private void RecordButton_MouseDown(object sender, EventArgs e)
    
        waveSource = new WaveIn();
        waveSource.WaveFormat = new WaveFormat(44100, 1);

        waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
        waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);

        memStream = new MemoryStream();
        waveFile = new WaveFileWriter(memStream, waveSource.WaveFormat);

        waveSource.StartRecording();
    

    private void RecordButton_MouseUp(object sender, EventArgs e)
    
        waveSource.StopRecording();

        byte[] outB = memStream.ToArray();
        File.WriteAllBytes("test.mp3", outB);
    

【讨论】:

这只会生成一个扩展名为 .MP3 的 WAV 文件,这可能不是您想要的 我忘记在文件写入之前添加转换为mp3的方法。该方法存在于描述中。然而,这不是重点。关键是能够从内存中获取字节。解决了的东西。 :)

以上是关于如何使用 C# NAudio 操作字节?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Naudio 和 c# 修剪 mp3 帧的标题和边信息

字节到 sbytes 并返回 - C# NAudio

C# NAudio 如何强制/硬编码音频设备(声卡)?

在 WPF C# 中使用 NAudio 录制音频

如何将 NAudio WaveStream 写入内存流?

NAudio中的WaveStream到字节数组?