naudio SineWaveProvider32在改变振幅时发出咔哒声

naudio SineWaveProvider32在改变振幅时发出咔哒声,naudio,amplitude,Naudio,Amplitude,我使用naudio和SineWaveProvider32代码直接从生成 正弦波音调。SineWaveProvider32类中的相关代码: public override int Read(float[] buffer, int offset, int sampleCount) { int sampleRate = WaveFormat.SampleRate; for (int n = 0; n < sampleCount; n

我使用naudio和SineWaveProvider32代码直接从生成 正弦波音调。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;
        }

这固定了每秒的点击次数(因此“采样”总是相对于零交叉,而不是采样率)

但是,每当我设置振幅变量时,我都会听到咔嗒声。我只在缓冲区[]处于过零位置时才尝试设置它, 认为振幅突然跳变可能是导致问题的原因。这并没有解决问题。我将振幅设置为介于 0.25和0.0

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

更改振幅的代码:

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

咔哒声是由波形的不连续性引起的。在这样的类中很难解决这一问题,因为理想情况下,您将缓慢地将体积从一个值渐变到另一个值。这可以通过修改代码使其具有目标振幅来实现,然后如果当前振幅不等于目标振幅,则通过循环每次计算的少量增量向其移动。所以在10毫秒的时间里,你会从旧的振幅移动到新的振幅。但不幸的是,你需要自己写这封信


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

咔哒声是由波形的不连续性引起的。在这样的类中很难解决这一问题,因为理想情况下,您将缓慢地将体积从一个值渐变到另一个值。这可以通过修改代码使其具有目标振幅来实现,然后如果当前振幅不等于目标振幅,则通过循环每次计算的少量增量向其移动。所以在10毫秒的时间里,你会从旧的振幅移动到新的振幅。但不幸的是,你需要自己写这封信


对于频率逐渐改变而不是振幅的类似概念,请查看我在上的博客。

角速度

用角速度来代替频率更容易思考。为每个示例增加sin()函数的角度参数的量

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

采样率以[samples per second]为单位,角速度以[radians per second]为单位,因此要得到[angle per sample],只需将角速度除以采样率即可得到[radians/second]/[samples/second]=[radians/sample]

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

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

通过在频率之间扫频,将有一个连续的相邻样本链,瞬态随时间平稳展开

从一个振幅到另一个振幅的移动也可以分散到多个样本上,以避免急剧瞬变

渐次调整声音开始和结束时的振幅比在一个样本中将输出从一个级别逐步调整到另一个级别更优雅

锐利的台阶在水面上形成环,环在世界上传播

关于sin()计算

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

当振幅^2=x^2+y^2时,每个新样本可计算为:

px = x * cs - y * sn; 
py = x * sn + y * cs;
要增加振幅,只需将px和py乘以一个系数,比如1.01。要生成下一个样本,请设置x=px,y=py,并再次运行px,py计算,cs和sn始终相同

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


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

角速度

用角速度来代替频率更容易思考。为每个示例增加sin()函数的角度参数的量

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

采样率以[samples per second]为单位,角速度以[radians per second]为单位,因此要得到[angle per sample],只需将角速度除以采样率即可得到[radians/second]/[samples/second]=[radians/sample]

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

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

通过在频率之间扫频,将有一个连续的相邻样本链,瞬态随时间平稳展开

从一个振幅到另一个振幅的移动也可以分散到多个样本上,以避免急剧瞬变

渐次调整声音开始和结束时的振幅比在一个样本中将输出从一个级别逐步调整到另一个级别更优雅

锐利的台阶在水面上形成环,环在世界上传播

关于sin()计算

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

当振幅^2=x^2+y^2时,每个新样本可计算为:

px = x * cs - y * sn; 
py = x * sn + y * cs;
要增加振幅,只需将px和py乘以一个系数,比如1.01。要制作下一个样本,设置x=px,y=
px = x * cs - y * sn; 
py = x * sn + y * cs;