每转一圈用 NAudio 播放波形

Posted

技术标签:

【中文标题】每转一圈用 NAudio 播放波形【英文标题】:Playing waveform with NAudio lower for each turn 【发布时间】:2021-01-14 20:26:06 【问题描述】:

我正在尝试使用 NAudio 播放字节缓冲区。我为该任务创建了一个 winforms 应用程序。

但是当我随后播放声音(使用 Math.sin 创建)时,每次播放的音量都会越来越低。为什么?

using System;
using System.Windows.Forms;
using NAudio.Wave;

namespace beeper

    public partial class Form1 : Form
    
        byte[] bytes;
        const int sampling_freq = 44100;

        public Form1()
        
            InitializeComponent();

            double freq = 1000;
            var seconds = 0.5;
            
            var length = (int)(seconds * sampling_freq);
            bytes = new byte[length];

            for (var i = 0; i < length; i++)
            
                var offset = 80 * Math.Sin(i * freq / sampling_freq * Math.PI * 2);

                bytes[i] = (byte)(128 + offset);
            
        

        private void btnBeep_Click(object sender, EventArgs e)
        
            var format = new WaveFormat(sampling_freq, 8, 1);
            var provider = new BufferedWaveProvider(format);
            provider.AddSamples(bytes, 0, bytes.Length);

            var wo = new WaveOut();
            wo.Init(provider);
            wo.Play();
        
    

大胆录音

难怪在查看这个以某种奇怪方式偏移和失真的波形时听起来会像这样。我搜索一种模式,但我真的找不到。

https://github.com/naudio/NAudio/issues/729

【问题讨论】:

您的问题是否可能是您正在创建一个新的wo 而不是using 以确保旧的wo 得到妥善处理?请注意,在有足够的时间完成声音之前,您无法处理 wo... 【参考方案1】:

每次单击播放按钮时,您都会添加一个全新的播放频道。如果您不关闭这些通道,那么它们将继续播放静音,因此您最终会得到多个静音通道与一个活动声音混合,从而为您提供您所看到的结果。按下按钮的次数越多,输出就越安静。

您需要在提示音结束后关闭频道(使用计时器或类似工具),或者创建一个频道并重复使用:

    private BufferedWaveProvider provider;
    private WaveOut waveOut;
    
    private void btnBeep_Click(object sender, EventArgs e)
    
        if (waveOut == null)
        
            var format = new WaveFormat(sampling_freq, 8, 1);
            provider = new BufferedWaveProvider(format);
            waveOut = new WaveOut();
            waveOut.Init(provider);
            waveOut.Play();
        
        
        provider.ClearBuffer();
        provider.AddSamples(bytes, 0, bytes.Length);
    

调用ClearBuffer 会删除任何剩余的缓冲样本,因此重复点击按钮不会只是将整个输出堆栈排入队列。如果你想播放多个重叠的音调,你需要做多个通道或自己处理混音。

如果您确实想要重叠,我建议您查看MixingWaveProvider32。就目前而言,它有点受限制,但您应该能够按原样使用它(使用适当的转换示例提供程序)。

【讨论】:

那么waveOut.Play() 将在provider 用完样本后继续播放? @NetMage WaveOut 将在提供程序用完数据时暂停。但是BufferedWaveProvider 默认设置会无限产生数据。如果您将ReadFully 设置为 false,它会在缓冲数据用完时停止。【参考方案2】:

usingWaveOutbutton1_Click 事件正确地更改为Dispose,然后等到声音结束似乎可以正常工作。否则我认为您需要使用一个全局WaveOut

public Form1()

    InitializeComponent();
    double freq = 1000;

    var length = (int)(seconds * sampling_freq);
    bytes = new byte[length];

    for (var i = 0; i < length; i++)
    
        var offset = 80 * Math.Sin(i * freq / sampling_freq * Math.PI * 2);

        bytes[i] = (byte)(128 + offset);
    


private void btnBeep_Click(object sender, EventArgs e)

    var format = new WaveFormat(sampling_freq, 8, 1);
    var provider = new BufferedWaveProvider(format);
    provider.AddSamples(bytes, 0, bytes.Length);

    using var wo = new WaveOut();
    wo.Init(provider);
    wo.Play();
    Thread.Sleep((int)Math.Ceiling(1000*seconds) + 100);

【讨论】:

它可以工作,但它会阻塞 UI 线程。而且每次点击它仍然会创建一个新的WaveOut,这似乎有点不必要。 @Corey 关于 NAudio 的 WaveOut 之类的内容是否有更好的文档? 文档参差不齐。当我遇到我不确定的东西时,我通常只是去寻找源头。这是我喜欢开源代码的原因之一 :)

以上是关于每转一圈用 NAudio 播放波形的主要内容,如果未能解决你的问题,请参考以下文章

NAudio WaveFileWriter 不会将文件大小写入波形文件

使用 NAudio 无法正确生成方波

NAudio 获取音频样本

使用naudio在播放期间调整字节流

从 NAudio 访问 WPF MediaElement 声音流

无法使用 NAudio 获取音频的波形图像