5

次のコードを実行すると、バックグラウンドでわずかな歪み(ブーンという音)が発生します。その微妙な性質のために、バイトキャスティングで何らかのエイリアシングが起こっていると信じ込ませます。

AudioFormat = PCM_SIGNED 44100.0 Hz、16ビット、ステレオ、4バイト/フレーム、ビッグエンディアン

:コードは(今のところ)データがビッグエンディアンであることを前提としています。

public static void playFreq(AudioFormat audioFormat, double frequency, SourceDataLine sourceDataLine)
{
    System.out.println(audioFormat);
    double sampleRate = audioFormat.getSampleRate();
    int sampleSizeInBytes = audioFormat.getSampleSizeInBits() / 8;
    int channels = audioFormat.getChannels();

    byte audioBuffer[] = new byte[(int)Math.pow(2.0, 19.0) * channels * sampleSizeInBytes];

    for ( int i = 0; i < audioBuffer.length; i+=sampleSizeInBytes*channels )
    {
        int wave = (int) (127.0 * Math.sin( 2.0 * Math.PI * frequency * i / (sampleRate * sampleSizeInBytes * channels) )  );

        //wave = (wave > 0 ? 127 : -127);

        if ( channels == 1 )
        {
            if ( sampleSizeInBytes == 1 )
            {
                audioBuffer[i] = (byte) (wave);
            }

            else if ( sampleSizeInBytes == 2 )
            {
                audioBuffer[i] = (byte) (wave);
                audioBuffer[i+1] = (byte)(wave >>> 8);
            }
        }

        else if ( channels == 2 )
        {
            if ( sampleSizeInBytes == 1 )
            {
                audioBuffer[i] = (byte) (wave);
                audioBuffer[i+1] = (byte) (wave);
            }

            else if ( sampleSizeInBytes == 2 )
            {
                audioBuffer[i] = (byte) (wave);
                audioBuffer[i+1] = (byte)(wave >>> 8);

                audioBuffer[i+2] = (byte) (wave);
                audioBuffer[i+3] = (byte)(wave >>> 8);
            }
        }
    }

    sourceDataLine.write(audioBuffer, 0, audioBuffer.length);
}
4

2 に答える 2

7

あなたのコメントは、コードがビッグエンディアンを想定していると言っています。

技術的には、実際にはリトルエンディアンで出力していますが、幸運な癖によって最上位バイトは常に0であるため、問題ではないようです。

編集:それをさらに説明するために-あなたの値が127の最大値にあるとき、あなたは(0x00、0x7f)を書くべきです、しかしあなたのコードからの実際の出力は(0x7f、0x00)であり、32512です。これはたまたま近いです32767の適切な16ビットの最大値ですが、下位8ビットはすべてゼロです。常に最大値として32767を使用し、必要に応じて下位8ビットを破棄することをお勧めします。

これは、16ビットデータを出力している場合でも、実効解像度は8ビットのみであることを意味します。これは音質の欠如を説明しているようです。

生データをファイルにダンプするだけのバージョンのコードを作成しましたが、ビットシフト自体に問題があることはわかりません。符号の予期しない変更やビットの欠落はありませんが、8ビットのサンプル品質と一致する話題があります。

また、サンプル数に基づいて波動方程式を計算し、バイトオフセットについて個別に心配すると、計算の価値が簡単になります。

int samples = 2 << 19;
byte audioBuffer[] = new byte[samples * channels * sampleSizeInBytes];

for ( int i = 0, j = 0; i < samples; ++i )
{
    int wave = (int)(32767.0 * Math.sin(2.0 * Math.PI * frequency * i / sampleRate));
    byte msb = (byte)(wave >>> 8);
    byte lsb = (byte) wave;

    for (int c = 0; c < channels; ++c) {
        audioBuffer[j++] = msb;
        if (sampleSizeInBytes > 1) {
            audioBuffer[j++] = lsb;
        }
    }
 }
于 2009-04-11T19:45:50.117 に答える
2

長い音を出すためにこのコードを繰り返し呼び出していると思います。

生成しているウェーブが書き込まれる前に完全な期間を完了していない可能性はありますか?

波が全周期を完了する前に「カットオフ」し、次の波が出力に書き込まれると、確かに何か奇妙な音が聞こえます。これがブーンという音の原因である可能性があります。

例えば:

        /-------\              /-------\              /-------\
  -----/         \       -----/         \       -----/         \
                  \                      \                      \
                   \-----                 \-----                 \-----

この波の部分の間の切断に注意してください。それがブーンという音を引き起こしている可能性があります。

于 2009-04-11T19:22:07.427 に答える