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,

Возвращаясь к примеру с треугольником, это будет выглядеть так:

           _
  /\      / \
 /  \   /     \
/    \/         \
Другие вопросы по тегам