1

我直接从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();
    }
4

2 回答 2

0

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

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

于 2016-09-08T21:38:31.667 回答
0

角速度

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

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

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

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

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

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

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

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

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

关于 sin() 计算

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

维基百科链接到理论

其中幅值​​^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。

于 2019-10-31T13:14:16.423 回答