java SourceDataLine正弦波点击

时间:2014-10-30 11:50:51

标签: java noise javax.sound.sampled clicking

我想使用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;
        }
    }
}

1 个答案:

答案 0 :(得分: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控制的速率增加。

回到三角形示例,它将如下所示:

           _
  /\      / \
 /  \   /     \
/    \/         \