1

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

.wav 44100.0hz, 16bit, little-endian

目前,我传递给 adjustVolume 方法的字节数组代表了十分之一秒的音频数据。即采样率/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;
    }

此代码基于:音频:更改请求者尝试执行相同操作的字节数组中的样本量。但是,使用了他问题中的代码(我认为在他得到他的答案后没有更新)我无法让它工作,我也不完全确定它在做什么。

4

1 回答 1

1

我建议您将字节数组包装在 a 中ByteBuffer(不要忘记将其设置.order()为小端),读取 a 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();
于 2013-06-06T11:30:27.580 回答