I want to apply gain to my recordings(PCM 16bit). For this I have the following code:
for (int i=0; i<buffer.length/2; i++)
{ // 16bit sample size
short curSample = getShort(buffer[i*2], buffer[i*2+1]);
if(rGain != 1){
//apply gain
curSample *= rGain;
//convert back from short sample that was "gained" to byte data
byte[] a = getByteFromShort(curSample);
buffer[i*2] = a[0];
buffer[i*2 + 1] = a[1];
}
If applied like this(multiplying each sample with the fraction number), I get discontinues when playback(hearing like an old walkie-talkie). Is there some formula to vary my gain factor on each sample? I assume there is some maxValue and minValue for the range of samples (I guess [-32768, +32767]) and using these values in some formula I can get a variated gain factor to apply to the current sample.
//EDIT: added
if (curSample>32767) {curSample=32767;}
if (curSample<-32768) {curSample=-32768;}
full method
aRecorder.read(buffer, 0, buffer.length);
for (int i=0; i<buffer.length/2; i++)
{ // 16bit sample size
short curSample = getShort(buffer[i*2], buffer[i*2+1]);
if(rGain != 1){
//apply gain
curSample *= rGain;
if (curSample>32767) {curSample=32767;}
if (curSample<-32768) {curSample=-32768;}
//convert back from short sample that was "gained" to byte data
byte[] a = getByteFromShort(curSample);
buffer[i*2] = a[0];
buffer[i*2 + 1] = a[1];
}
But still hears odd(noise + discontinues like an old walkie-talkie).
Any help would be appreciated,
Thanks.
Here is the final results...The algorithm is intersected with a VU-metering measuring... Disregard that part...
When changing gain you need to do this smoothly over a period of typically around 10 ms, otherwise you will get audible discontinuities (i.e. clicks). The simplest transition is linear, e.g. ramp from old gain to new gain linearly over 10 ms, but for high quality audio you should use something like a raised cosine transition:
where t0, t1 are the begin, end times for the transition.
You have another bug in your source. The following line creates sample values from -32768..32767 which is the full range of s short variable:
As you now apply a gain factor grater than 1 you "overflow" the
short
format:This produces nasty cracks in the smooth signal, as e.g. 32767 * 1.5 is not 49150 as expected, but due to the "overflow" is interpreted as -16386 because you assign the result to a
short
variable again.Thus the two lines
wouldn't change anything as curSample is never greater than 32767 or smaller than -32768.
To avoid this you have to use a temporary
int
variable: