【问题标题】:naudio SineWaveProvider32 gives clicks when changing Amplitude更改幅度时,naudio SineWaveProvider32 会发出咔嗒声
【发布时间】:2016-09-02 19:26:44
【问题描述】:

我直接从http://mark-dot-net.blogspot.com/2009/10/playback-of-sine-wave-in-naudio.html 使用带有 SineWaveProvider32 代码的 naudio 来生成 正弦波音调。 SineWaveProvider32类中的相关代码:

public override int Read(float[] buffer, int offset, int sampleCount)
        {
            int sampleRate = WaveFormat.SampleRate;
            for (int n = 0; n < sampleCount; n++)
            {
                buffer[n + offset] =
                    (float)(Amplitude * Math.Sin((2 * Math.PI * sample * Frequency) / sampleRate));
                sample++;
                if (sample >= sampleRate) sample = 0;
            }
            return sampleCount;
        }

我每秒钟都有点击次数/节拍,所以我改变了

if (sample >= sampleRate) sample = 0;

if (sample >= (int)(sampleRate / Frequency)) sample = 0;

这固定了每秒的点击次数(因此“样本”始终与过零相关,而不是采样率)。

但是,每当我设置 Amplitude 变量时,我都会得到一次点击。我尝试仅在缓冲区 [] 处于过零时设置它, 认为幅度的突然跳跃可能会导致问题。那并没有解决问题。我将振幅设置为之间的值 0.25 和 0.0

我尝试按照NAudio change volume in runtime 中的建议调整延迟和缓冲区数量,但是 也没有效果。

我的改变振幅的代码:

public async void play(int durationMS, float amplitude = .25f)
        {
        PitchPlayer pPlayer = new PitchPlayer(this.frequency, amplitude);
            pPlayer.play();
            await Task.Delay(durationMS/2);
            pPlayer.provider.Amplitude = .15f;
            await Task.Delay(durationMS /2);
            pPlayer.stop();
    }

【问题讨论】:

    标签: naudio amplitude


    【解决方案1】:

    咔嗒声是由波形的不连续性引起的。这在这样的课程中很难解决,因为理想情况下,您会慢慢地将音量从一个值增加到另一个值。这可以通过修改代码以具有目标幅度来完成,然后如果当前幅度不等于目标幅度,那么您将朝着它移动每次通过循环计算的一个小的增量量。所以在 10 毫秒的时间里,你从旧的幅度移动到新的幅度。但不幸的是,您需要自己编写。

    对于频率逐渐变化而不是幅度变化的类似概念,请查看我在 portamento in NAudio 上的博客文章。

    【讨论】:

      【解决方案2】:

      角速度

      用角速度来思考比频率更容易。为每个样本增加多少 sin() 函数的角度参数。

      当使用弧度表示角度时,完成一整圈的一个周期是 2*pi,因此一赫兹的角速度是 (2*pi)/T = (2*pi)/1/ f = f*2*pi = 1*2*pi [rad/s]

      采样率以 [每秒样本数] 为单位,角速度以 [弧度每秒] 为单位,因此要获得 [每个样本的角度],您只需将 角速度 除以 样本rate 得到 [弧度/秒]/[样本/秒] = [弧度/样本]。

      这是为每个样本连续增加 sin() 函数角度的数字 - 不需要乘法。

      要从一个频率扫描到另一个频率,您只需在多个样本上以小步长从一个角度增量移动到另一个角度增量。

      通过在频率之间进行扫描,将有一个连续的相邻样本链,并且瞬态会随着时间的推移平滑地散布。

      从一个幅度移动到另一个幅度也可以分布在多个样本上以避免急剧的瞬变。

      在声音的开始和结束处逐步调整幅度的淡入和淡出比在一个样本中将输出从一个电平步进到另一个电平更优雅。

      尖锐的台阶会在水面上产生环,然后传播到世界。

      关于 sin() 计算

      为了快速计算,最好旋转一个幅度长度的向量并仅在角速度变化时计算 sn=sin(delta), cs=cos(delta):

      Wikipedia Link to theory

      其中幅值^2 = x^2 + y^2,每个新样本可以计算为:

      px = x * cs - y * sn; 
      py = x * sn + y * cs;
      

      要增加幅度,您只需将 px 和 py 乘以一个因子,例如 1.01。要制作下一个示例,您设置 x=px, y=py 并再次使用 cs 和 sn 再次运行 px,py 计算。

      py 或 px 可用作信号输出,相位相差 90 度。

      在第一个样本上,您可以设置 x=amplitude 和 y=0。

      【讨论】:

        猜你喜欢
        • 2016-11-16
        • 2011-06-17
        • 2016-05-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-26
        • 1970-01-01
        相关资源
        最近更新 更多