处理具有分数的字节数组后的Java Sound API噪声

时间:2009-09-03 12:17:58

标签: java api audio wav

我正在尝试处理我从采样的sourcedataline(Java Sound API)获得的字节数组。如果我将字节数组乘以分数,我会在播放流时产生噪音。

在播放声音之前,我将立体声wav文件分成左右声道。这很好用。但是如果我想用增益控制处理通道,这取决于延迟因子,我会得到噪声。

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

有谁知道如何解决问题?

//编辑:

我尝试将两个字节转换为带有位移的短(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);

但是当我将单个字节乘以增益值时,我得到了相同的结果。

// EDIT

或者我应该将这两个数组值添加到这样的短片中吗?

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++;
            }
        }

    }

5 个答案:

答案 0 :(得分: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 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);
}

答案 1 :(得分:1)

你需要应用一些剪辑。假设你有一个值为100的样本,并且你正在应用增益2.乘法的结果将是200,然后最终被截断为 -73

尝试:

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

作为对此的测试 - 如果你应用的增益实际上是一个“安静”的增益(例如0.5),那么你现在不应该得到噪音。

编辑:如果“原始”值实际上不是单个字节,则应首先从字节数组转换为这些值,然后然后应用增益,然后转换回单个字节。否则你肯定会得到一些奇怪的结果......特别是如果原生格式实际上将字节视为 unsigned 值......

答案 2 :(得分: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);

    }

我像以前一样得到了噪音。

答案 3 :(得分:0)

我发现这个帖子后发出非常相似的声音问题。 FWIW我的问题通过注意代码如

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

没有考虑Java签名字节的影响。如果高位设置在低字节(例如array [i])中,那么这对于短而效果代码没有影响,该代码分别与short的两个字节进行算术运算。通过代码轻松修复

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

在短路中增加256 - 计算低字节中缺失的128位和其余的两位补码。您可能需要对此进行一些修改,具体取决于您处理字节数组的方式。

答案 4 :(得分:0)

试试这个:

byte[] decodedBuffer = Base64.decode(message64, Base64.NO_WRAP);
       // byte[] newdata;
        for (int i=0; i<decodedBuffer.length; i++) {
            Byte b = decodedBuffer[i];
            if (b<=Byte.MIN_VALUE||b>=Byte.MAX_VALUE) decodedBuffer[i] = Byte.MIN_VALUE;
        }
        if (audioTrack != null)
            audioTrack.write(decodedBuffer, 0, decodedBuffer.length);