我正在尝试编写一个简单的应用程序,它可以播放声音,并可以在播放过程中随时改变声音的音量。我这样做是通过将声音的字节数组中的每对字节转换为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,其中提问者正在尝试做同样的事情。但是,使用了他的问题中的代码(我认为他得到答案后没有更新),我无法让它工作,我不确定它在做什么。
答案 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();