2009-04-11 61 views
5

次のコードを実行すると、背景にわずかなゆがみ(鳴っているような音)が発生します。その微妙な性質のため、バイトキャストで何らかのエイリアシングが起こっていると考えられます。Javaで正弦波を生成する際の背景ノイズ

のAudioFormat = PCM_SIGNED 44100.0ヘルツ、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); 
} 

答えて

7

あなたのコメントは、コードがビッグエンディアンを前提としていると言います。 - ときにさらに説明する:

技術的にはあなたがリトルエンディアンで出力実際している、しかし、あなたの最も重要なバイトは常に0

EDITあるのでラッキー癖によっては関係していないようです(0x00、0x7f)と書く必要がありますが、コードからの実際の出力は(0x7f、0x00)です。これは32512です。これは適切な付近にある16ビット最大値32767であるが、下位8ビットはすべて0である。最大値として常に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; 
     } 
    } 
} 
+0

ああ!今度はエラーを見てください。振幅部分を修正した後、エラーは非常に明白になりましたが、コードはより効率的です。ありがとう! – yxk

+0

よく行われた分析! –

2

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

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

完全な期間が終了して次の波が出力に書き込まれる前に波が「カットオフ」になると、奇妙なことが聞こえてきます。例えば

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

注意この波の部分の間の切断。それが鳴り響いているかもしれません。

+0

はい、それはその問題ではありません多くのサイクルを通して音が出るのに十分な大きさです。クリック音は考慮されますが、一定の鳴動音は考慮されません。 – yxk

+0

これは正しい答えではありません - コードは明らかにたくさんのサンプルを生成し、各サイクルの終わりには切り捨てがありません – Alnitak

+0

と私はチェックするコードをテストしました - それはバズを引き起こしている偶然8ビットの量子化エラーです。 – Alnitak

関連する問題