1

javax.sound.sampled.SourceDataLine を使用して単純な正弦波を生成したいと考えています。1 つの一定の周波数の場合は問題なく動作しますが、周波数を変更すると、常に一種のクリック ノイズが発生します。私は何を間違っていますか、それを避けるために何ができますか?

            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 に答える