1

サンプリングされたソースデータライン(Java Sound API)から取得したバイト配列を処理しようとしています。バイト配列に小数を掛けると、ストリームの再生中にノイズが発生します。

サウンドを再生する前に、ステレオwavファイルを彼の左右のチャンネルに分けます。これは正常に機能します。しかし、遅延係数に依存するゲインコントロールを使用してチャネルを処理したい場合、ノイズが発生します。

for(int i=0; i<bufferSize; i++) { array[i] = (byte) (array[i] * gain); }

誰かが問題を解決する方法を知っていますか?

//編集:

ビットシフトを使用して、2バイトを短い(2バイト)に変換しようとしました。例:

short leftMask = 0xff00;
short rightMask = 0x00ff;
short sValue = (array[i] + array[i+1] <<8) * gain;

array[i] = (sValue & leftMask) >> 8;
array[i+1] = (sValue & rightMask);

しかし、1バイトにゲイン値を掛けただけでも同じようになりました。

//編集

または、このように2つの配列値をshortに追加する必要がありますか?

short shortValue = array[i] + array[i+1];
shortValue *= gain;
array[i] = ??? 

しかし、サウンドを失うことなく、このショートを2つのシングルバイトに変換するにはどうすればよいですか?

//分離メソッドからいくつかのコードを編集します:

public static void channelManipulation(byte[] arrayComplete) {
        int i=2; 
        char channel='L';
        int j=0; 

        /** 
         * The stereo stream will be divided into his channels - the Left and the Right channel. 
         * Every 2 bytes the channel switches. 
         * While data is collected for the left channel the right channel will be set by 0. Vice versa.
         */
        while(j<arrayComplete.length) {
            //while we are in the left channel we are collecting 2 bytes into the arrayLeft


            while(channel=='L') {
                if(i==0) {
                    channel='R'; //switching to the right channel
                    i=2;
                    break;
                }
                arrayLeft[j] = (byte)(arrayComplete[j]);
                arrayRight[j] = 0;
                i--; j++;
            }

            //while we are in the right channel we are collecting 2 bytes into the arrayRight
            while(channel=='R') {
                if(i==0) {
                    channel='L'; //switching to the left channel
                    i=2;
                    break;
                }
                arrayRight[j] = (byte) (arrayComplete[j]);
                arrayLeft[j] = 0;
                i--; j++;
            }
        }

    }
4

5 に答える 5

3

オーディオ データはバイト配列の形式ですが、実際のオーディオは (私が推測するに) 短い (2 バイト) 整数の配列です。配列の個々のバイトにゲイン係数を掛けると、2 バイトのサンプル値が意味不明 (別名ノイズ) になります。私は Java プログラマーではありませんが、あなたの解決策は、バイト配列を 2 バイトの整数配列としてキャストし (ただし、Java ではそうします)、各 2 バイトの整数値にゲイン係数を掛けることです (そして、再生前にバイト配列にキャストし直したと思います)。

更新: C# では、オーディオ データのバイト配列がある場合 (たとえば、実際の形式が 2 バイト整数である WAV ファイルから抽出されたもの)、次のように BitConverter クラスと Array クラスを使用してゲインを適用します。

float gain = 0.5f;
for (int i = 0; i < audio.Length; i += 2)
{
    short val = BitConverter.ToInt16(audio, i);
    val = (short)((float)val * gain);
    Array.Copy(BitConverter.GetBytes(val), 0, audio, i, 2);
}

これはかなり不格好で、私が実際に行うことはありません。C# の世界では、私は常にオーディオを 16 ビットまたは 32 ビットの整数の配列として扱うか、32 ビットまたは 64 ビットの浮動小数点値として扱います。Javaオーディオがどのように機能するかはまったくわかりませんが、最初にオーディオを16ビット整数の配列として取得することは可能です(そしてはるかに簡単です)。その後、何もする必要はありませんこのような変な変換を使用して、ゲインを適用したり、他にやりたいことをしたりします。

更新 2 : また、元のオーディオ ソースが実際に 2 バイト整数のサンプル値で構成されているかどうかもわかりません。実際には、4 バイトの整数または (可能性が高い) 4 バイトの浮動小数点のサンプル値である可能性があります。この場合、サンプル コードは依然としてノイズを生成します。4 バイト float の場合、適切なコードは次のようになります。

float gain = 0.5f;
for (int i = 0; i < audio.Length; i += 4)
{
    float val = BitConverter.ToSingle(audio, i);
    val *= gain;
    Array.Copy(BitConverter.GetBytes(val), 0, audio, i, 4);
}
于 2009-09-03T12:52:27.873 に答える
1

クリッピングを適用する必要があります。値 100 のサンプルがあり、ゲイン 2 を適用するとします。乗算の結果は 200 になり、最終的に -73 に切り捨てられます。

試す:

array[i] = Math.min(Math.max(array[i] * gain, -128), 127);

これのテストとして - 効果的に「静かにする」ゲイン (たとえば 0.5) であるゲインを適用すると、現時点ではノイズが発生しないはずです。

編集:「生の」値が実際には 1 バイトでない場合は、最初にバイト配列からそれらの値に変換してから、ゲインを適用してから 1 バイトに戻す必要がありますそうしないと、実際に奇妙な結果が得られます...特にネイティブ形式が実際にバイトを符号なしの値として扱っている場合...

于 2009-09-03T12:22:11.020 に答える
1

動作しません。私はこのコードスニペットを持っています:

for(int c=0; c<Constants.getBufferlength()-4; c+=4) {
            arrayLeft[c] = (byte) Math.min(Math.max((arrayLeft[c]*leftGain), -128), 127);

            arrayRight[c] = (byte) Math.min(Math.max((arrayRight[c]*rightGain),-128),127);

    }

以前のようにノイズが発生しました。

于 2009-09-03T12:42:03.553 に答える
0

非常によく似たサウンドの問題が発生した後、この投稿を見つけました。FWIW私の問題は、次のようなコードに注意することで解決しました

short sValue = (array[i] + array[i+1] <<8) 

Java の符号付きバイトの影響を考慮していません。上位ビットが下位バイトに設定されている場合 (たとえば、array[i])、これは short には影響しませんが、short の 2 バイトを個別に計算するコードに影響を与えます。次の行に沿ったコードで簡単に修正できます

if(array[i] < 0)
    array[i+1] += 1;

これにより、short に 256 が追加されます。これは、下位バイトで欠落している 128 ビットと残りの 2 の補数を考慮したものです。バイト配列の処理方法によっては、これにいくつかのバリエーションが必要になる場合があります。

于 2009-11-07T19:36:11.673 に答える