0
votes

I'm attempting to apply a volume limit to some PCM samples.

However, whenever the volume I apply is anything but 1.0 heavy static/noise is produced (interestingly only for about 80% of the duration of the sound, the rest seems to play without distortion) and the volume doesn't even seem affected.

Like I said, if soundVolume is 1.0 in the code below, works great. If it's 0.1-0.9 it produces horrible noise and doesn't work at all. I'm out of ideas as to why.

The PCM samples are signed 16-bit.

// Get samples, apply volume, clamp, write back.
short s1 = (short)((pcmBytes[i] << 8) | (pcmBytes[i + 1]));

s1 = (short)(s1 * soundVolume);

pcmBytes[i] = (byte)((s1 >> 8) & 0xFF);
pcmBytes[i + 1] = (byte)(s1 & 0xFF);

Is there something wrong with this code? Tracing out s1 as it goes through the algorithm seems to show it being properly modified. Am I manipulating the bytes correctly?

Edit: This occurs even when the sound I'm modifying is pure silence. If soundVolume is anything other than 1.0 I get the static.


Solution: New code, I was incorrectly processing the bytes as big-endian when they were little-endian. Couple that with some missing masks 0xFF and this is the solution.

short s1 = (short)(((pcmBytes[i + 1] & 0xFF) << 8) | (pcmBytes[i] & 0xFF));

s1 = (short)(s1 * soundVolume);

pcmBytes[i + 1] = (byte)((s1 >> 8) & 0xFF);                                     
pcmBytes[i] = (byte)(s1 & 0xFF);
1

1 Answers

2
votes

Just from your description of the problem, I would guess that you are processing little-endian data as if it were big-endian data. Swapping the [i]s with the [i+1]s would fix that. Note that this would also happen if your array is one byte out of alignment with the sample stream.

Your code also has a bug when you say: | pcmBytes[i+1] The byte is converted to an int here, and if it's "negative" then it will be sign-extended with a bunch of 1s that will stomp on the high bits from pcmBytes[i].

The result would sound horrible all the time, even when your volume is 1.0. The reason it doesn't sound horrible is again probably because you have the byte order mixed up, so you're really only stomping on the low bits instead of the high bits.

So, when you fix the byte order, be sure to & the byte with 0xFF before or-ing it into the sample word.