1

我想使用 javax.sound.sampled.SourceDataLine 生成纯正弦波。对于一个恒定的频率,它工作得很好,但是在改变频率时总是有一种咔哒声。我做错了什么,我能做些什么来避免这种情况?

            line.start();
            final byte[] toneBuffer = new byte[SAMPLE_CHUNK];

            while(run) {
                createSineWaveBuffer(frequency, toneBuffer);
                line.write(toneBuffer, 0, toneBuffer.length);
            }

            line.drain();
            line.close();

在哪里

private double alpha = 0.0;
private static final double step_alpha = (2.0*Math.PI)/SAMPLE_RATE;

private void createSineWaveBuffer(final double freq, final byte[] buffer) {
    for(int i = 0; i < buffer.length; ++i) {
        buffer[i] = (byte)(Math.sin(freq*alpha)*127.0);
        alpha += step_alpha;

        if(alpha >= 2.0*Math.PI) {
            alpha = 0.0;
        }
    }
}
4

1 回答 1

1

您会体验到点击,因为当freq改变时,整个正弦波都会移动。以更容易绘制的三角波为例:

1 Hz
  /\    /\    /
 /  \  /  \  /
/    \/    \/

.5 Hz_
    / \
  /     \     /
/         \_/

如果您在任意时间在这些之间切换:

  /\  |\
 /  \ |  \     /
/    \|    \_/

有不连续性,您会听到咔哒声。

这基本上是因为您导致从 sin(freq*alpha) 突然跳转到 sin(.5*freq*(alpha+step_alpha))。不仅 sin() 输入的导数不连续地变化(这是改变频率所需要的),值也在不连续地变化。

解决这个问题的方法是仅将输入的导数更改为 sin()。您可以通过保持一个根据频率递增的计数器来做到这一点:

private void createSineWaveBuffer(final double freq, final byte[] buffer) {

    for(int i = 0; i < buffer.length; ++i) {
        buffer[i] = (byte)(Math.sin(alpha)*127.0);
        alpha += freq*step_alpha;

        if(alpha >= 2.0*Math.PI) {
            alpha -= 2.0*Math.PI;
        }
    }

    return t;
}

在这里,我已将您更改alpha为以当前控制的速率增加freq

回到三角形的例子,这看起来像:

           _
  /\      / \
 /  \   /     \
/    \/         \
于 2014-10-30T12:35:49.413 回答