Question

I work on an audio recorder (AudioRec on Google Play).

I have the option to adjust the gain with [-20dB, + 20dB] range.

It works pretty well on my phone, but an user using a professional microphone attached to his device had complained about the gain because when selecting -20dB, the output is distorted.

See below how I impl. gain function:

for(int frameIndex=0; frameIndex<numFrames; frameIndex++){
                for(int c=0; c<nChannels; c++){
                    if(rGain != 1){
                        // gain
                        long accumulator=0;
                        for(int b=0; b<bytesPerSample; b++){
                            accumulator+=((long)(source[byteIndex++]&0xFF))<<(b*8+emptySpace);
                        }
                        double sample = ((double)accumulator/(double)Long.MAX_VALUE);
                        sample *= rGain;                

                        int intValue = (int)((double)sample*(double)Integer.MAX_VALUE);             
                        for(int i=0; i<bytesPerSample; i++){
                            source[i+byteIndex2]=(byte)(intValue >>> ((i+2)*8) & 0xff);
                        }
                        byteIndex2 += bytesPerSample;   
                    }

                    }//end for(channel)
            }//end for(frameIndex)

Maybe I should apply some low/high filter after samle *= rGain; ? Something like if(sample < MINIMUM_VALUE || sample > MAXIMUM_VALUE) ? in this case, please let me know what are these min max values...

Was it helpful?

Solution

Simply clipping values above a threshold will most certainly cause distortion. If you can picture a pure sine wave, as you lop the top off it will begin to resemble a square wave.

That said, if you have an input signal and you are multiplying it by a value smaller than one, there is no way that you are introducing any (significant) distortion. You need to look further back in the signal path. Perhaps clipping is occurring at the input.

OTHER TIPS

I would try to simplify your logic. It appears you are using 32-bit wave form but the code is far more complex than needed. This will make it harder to work out how to avoid clipping.

IntBuffer ints = ByteBuffer.wrap(source).order(ByteBuffer.nativeOrder()).asIntBuffer();
for(int i = 0; i < ints.limit(); i++) {
    int signal = ints.get(i);
    double gained = signal * gain;
    if (gained > Integer.MAX_VALUE) {
       // do something.
    } else if (gained < Integer.MIN_VALUE) {
       // do something
    }
    ints.put(i, (int) gained);
}

A simple approach is to let the values overflow, but as you say this can result in an apparent distortion. Just clipping the data could lead to long period of effective silence.

What you may have to do is a FFT and produce a signal which increases the strength of audible frequencies as the cost of lower frequencies when the gain is too high. i.e. it is the low frequencies which result in the signal being too high or too low so you can't amplify these as much if you want to stay in bounds.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top