从byte []实时调整音量?

时间:2013-06-06 11:24:01

标签: java

我正在尝试编写一个简单的应用程序,它可以播放声音,并可以在播放过程中随时改变声音的音量。我这样做是通过将声音的字节数组中的每对字节转换为int,然后将该int乘以体积的增加或减少,然后将它们写回两个字节(即1个样本)。但是,这会导致声音的极端失真。有可能我的位移错了吗?我的声音格式是:

.wav 44100.0hz, 16bit, little-endian

此时,我通过adjustVolume方法的字节数组表示音频数据的十分之一秒。即sampleRate / 10

我在这里遗失的是什么导致它扭曲而不能正确缩放音量?我有没有写回字节和堡垒错误?

private byte[] adjustVolume(byte[] audioSamples, double volume) {
        byte[] array = new byte[audioSamples.length];
        for (int i = 0; i < array.length; i += 2) {
            // convert byte pair to int
            int audioSample = (int) (((audioSamples[i + 1] & 0xff) << 8) | (audioSamples[i] & 0xff));


            audioSample = (int) (audioSample * volume);


            // convert back
            array[i] = (byte) audioSample;
            array[i + 1] = (byte) (audioSample >> 16);

        }
        return array;
    }

此代码基于:Audio: Change Volume of samples in byte array,其中提问者正在尝试做同样的事情。但是,使用了他的问题中的代码(我认为他得到答案后没有更新),我无法让它工作,我不确定它在做什么。

1 个答案:

答案 0 :(得分:1)

我建议你将字节数组包装在ByteBuffer中(不要忘记将其.order()设置为小端),读取short,操作它,再次写入。

示例代码:

// Necessary in order to convert negative shorts!
private static final int USHORT_MASK = (1 << 16) - 1;

final ByteBuffer buf = ByteBuffer.wrap(audioSamples)
    .order(ByteOrder.LITTLE_ENDIAN);
final ByteBuffer newBuf = ByteBuffer.allocate(audioSamples.length)
    .order(ByteOrder.LITTLE_ENDIAN);

int sample;

while (buf.hasRemaining()) {
    sample = (int) buf.getShort() & USHORT_MASK;
    sample *= volume;
    newBuf.putShort((short) (sample & USHORT_MASK));
}

return newBuf.array();