我想使用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;
}
}
}
答案 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
控制的速率增加。
回到三角形示例,它将如下所示:
_
/\ / \
/ \ / \
/ \/ \