java SourceDataLine синусоидальные клики
Я хочу генерировать простые синусоиды, используя 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 ответ
Вы испытываете щелчок, потому что когда freq
изменения, вся синусоида смещена. Как пример с более легкой для рисования треугольной волной:
1 Hz
/\ /\ /
/ \ / \ /
/ \/ \/
.5 Hz_
/ \
/ \ /
/ \_/
Если вы переключаетесь между ними в произвольное время:
/\ |\
/ \ | \ /
/ \| \_/
есть разрыв, который вы слышите как щелчок.
Это в основном потому, что вы вызываете внезапный переход от греха (freq*alpha) к греху (.5*freq*(alpha+step_alpha)). Мало того, что производная от input для 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
,
Возвращаясь к примеру с треугольником, это будет выглядеть так:
_
/\ / \
/ \ / \
/ \/ \