Increase volume output of recorded audio

13,215

Solution 1

You obviously have the AudioRecord stuff running, so I skip the decision for sampleRate and inputSource. The main point is that you need to appropriately manipulate each sample of your recorded data in your recording loop to increase the volume. Like so:

    int minRecBufBytes = AudioRecord.getMinBufferSize( sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT );
    // ...
    audioRecord = new AudioRecord( inputSource, sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, minRecBufBytes );

    // Setup the recording buffer, size, and pointer (in this case quadruple buffering)
    int recBufferByteSize = minRecBufBytes*2;
    byte[] recBuffer = new byte[recBufferByteSize];
    int frameByteSize = minRecBufBytes/2;
    int sampleBytes = frameByteSize;
    int recBufferBytePtr = 0;

    audioRecord.startRecording();

    // Do the following in the loop you prefer, e.g.
    while ( continueRecording ) {
        int reallySampledBytes = audioRecord.read( recBuffer, recBufferBytePtr, sampleBytes );

        int i = 0;
        while ( i < reallySampledBytes ) {
            float sample = (float)( recBuffer[recBufferBytePtr+i  ] & 0xFF
                                  | recBuffer[recBufferBytePtr+i+1] << 8 );

            // THIS is the point were the work is done:
            // Increase level by about 6dB:
            sample *= 2;
            // Or increase level by 20dB:
            // sample *= 10;
            // Or if you prefer any dB value, then calculate the gain factor outside the loop
            // float gainFactor = (float)Math.pow( 10., dB / 20. );    // dB to gain factor
            // sample *= gainFactor;

            // Avoid 16-bit-integer overflow when writing back the manipulated data:
            if ( sample >= 32767f ) {
                recBuffer[recBufferBytePtr+i  ] = (byte)0xFF;
                recBuffer[recBufferBytePtr+i+1] =       0x7F;
            } else if ( sample <= -32768f ) {
                recBuffer[recBufferBytePtr+i  ] =       0x00;
                recBuffer[recBufferBytePtr+i+1] = (byte)0x80;
            } else {
                int s = (int)( 0.5f + sample );  // Here, dithering would be more appropriate
                recBuffer[recBufferBytePtr+i  ] = (byte)(s & 0xFF);
                recBuffer[recBufferBytePtr+i+1] = (byte)(s >> 8 & 0xFF);
            }
            i += 2;
        }

        // Do other stuff like saving the part of buffer to a file
        // if ( reallySampledBytes > 0 ) { ... save recBuffer+recBufferBytePtr, length: reallySampledBytes

        // Then move the recording pointer to the next position in the recording buffer
        recBufferBytePtr += reallySampledBytes;

        // Wrap around at the end of the recording buffer, e.g. like so:
        if ( recBufferBytePtr >= recBufferByteSize ) {
            recBufferBytePtr = 0;
            sampleBytes = frameByteSize;
        } else {
            sampleBytes = recBufferByteSize - recBufferBytePtr;
            if ( sampleBytes > frameByteSize )
                sampleBytes = frameByteSize;
        }
    }

Solution 2

Thanks to Hartmut and beworker for the solution. Hartmut's code did worked at near 12-14 dB. I did merged the code from the sonic library too to increase volume, but that increase too much noise and distortion, so I kept the volume at 1.5-2.0 and instead tried to increase gain. I got decent sound volume which doesn't sound too loud in phone, but when listened on a PC sounds loud enough. Looks like that's the farthest I could go.

I am posting my final code to increase the loudness. Be aware that using increasing mVolume increases too much noise. Try to increase gain instead.

private AudioRecord.OnRecordPositionUpdateListener updateListener = new AudioRecord.OnRecordPositionUpdateListener() {
        @Override
        public void onPeriodicNotification(AudioRecord recorder) {
            aRecorder.read(bBuffer, bBuffer.capacity()); // Fill buffer
            if (getState() != State.RECORDING)
                return;
            try {
                if (bSamples == 16) {
                    shBuffer.rewind();
                    int bLength = shBuffer.capacity(); // Faster than accessing buffer.capacity each time
                    for (int i = 0; i < bLength; i++) { // 16bit sample size
                        short curSample = (short) (shBuffer.get(i) * gain);
                        if (curSample > cAmplitude) { // Check amplitude
                            cAmplitude = curSample;
                        }
                        if(mVolume != 1.0f) {
                            // Adjust output volume.
                            int fixedPointVolume = (int)(mVolume*4096.0f);
                            int value = (curSample*fixedPointVolume) >> 12;
                            if(value > 32767) {
                                value = 32767;
                            } else if(value < -32767) {
                                value = -32767;
                            }
                            curSample = (short)value;
                            /*scaleSamples(outputBuffer, originalNumOutputSamples, numOutputSamples - originalNumOutputSamples,
                                    mVolume, nChannels);*/
                        }
                        shBuffer.put(curSample);
                    }
                } else { // 8bit sample size
                    int bLength = bBuffer.capacity(); // Faster than accessing buffer.capacity each time
                    bBuffer.rewind();
                    for (int i = 0; i < bLength; i++) {
                        byte curSample = (byte) (bBuffer.get(i) * gain);
                        if (curSample > cAmplitude) { // Check amplitude
                            cAmplitude = curSample;
                        }
                        bBuffer.put(curSample);
                    }
                }
                bBuffer.rewind();
                fChannel.write(bBuffer); // Write buffer to file
                payloadSize += bBuffer.capacity();
            } catch (IOException e) {
                e.printStackTrace();
                Log.e(NoobAudioRecorder.class.getName(), "Error occured in updateListener, recording is aborted");
                stop();
            }
        }

        @Override
        public void onMarkerReached(AudioRecord recorder) {
            // NOT USED
        }
    };

Solution 3

simple use MPEG_4 format

To increase the call recording volume use AudioManager as follows:

int deviceCallVol;
AudioManager audioManager;

Start Recording:

   audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
//get the current volume set
deviceCallVol = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
//set volume to maximum
        audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL), 0);

   recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
   recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
   recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
   recorder.setAudioEncodingBitRate(32);
   recorder.setAudioSamplingRate(44100);

Stop Recording:

//revert volume to initial state

 audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, deviceCallVol, 0);

Solution 4

In my app I use an open source sonic library. Its main purpose is to speed up / slow down speech, but besides this it allows to increase loudness too. I apply it to playback, but it must work for recording similarly. Just pass your samples through it before compressing them. It has a Java interface too. Hope this helps.

Share:
13,215
0xC0DED00D
Author by

0xC0DED00D

Updated on June 05, 2022

Comments

  • 0xC0DED00D
    0xC0DED00D almost 2 years

    I am trying to make a call recording app in Android. I am using loudspeaker to record both uplink and downlink audio. The only problem I am facing is the volume is too low. I've increased the volume of device using AudioManager to max and it can't go beyond that.

    I've first used MediaRecorder, but since it had limited functions and provides compressed audio, I've tried with AudioRecorder. Still I havn't figured out how to increase the audio. I've checked on projects on Github too, but it's of no use. I've searched on stackoverflow for last two weeks, but couldn't find anything at all.

    I am quite sure that it's possible, since many other apps are doing it. For instance Automatic Call recorder does that.

    I understand that I have to do something with the audio buffer, but I am not quite sure what needs to be done on that. Can you guide me on that.

    Update:-
    I am sorry that I forgot to mention that I am already using Gain. My code is almost similar to RehearsalAssistant (in fact I derived it from there). The gain doesn't work for more than 10dB and that doesn't increase the audio volume too much. What I wanted is I should be able to listen to the audio without putting my ear on the speaker which is what lacking in my code.

    I've asked a similar question on functioning of the volume/loudness at SoundDesign SE here. It mentions that the Gain and loudness is related but it doesn't set the actual loudness level. I am not sure how things work, but I am determined to get the loud volume output.

  • 0xC0DED00D
    0xC0DED00D over 9 years
    Thanks for the answer. I've already tried various formats. MediaRecorder definitely doesn't solve my purpose(Except if there's a hack or work around). I am sort of expecting some kind of algorithm which can be applied to audio buffer to improve loudness.
  • 0xC0DED00D
    0xC0DED00D over 9 years
    Actually I am already using the Gain, but it doesn't work for more than 10dB increase. I am using code from this URL - sourceforge.net/p/rehearsalassist/code/HEAD/tree/android/…
  • Hartmut Pfitzinger
    Hartmut Pfitzinger over 9 years
    You say it doesn't work for more than 10dB? What exactly do you observe at say 12 or 20dB?
  • 0xC0DED00D
    0xC0DED00D over 9 years
    The sound gets distorted at more than 10dB gain. It starts to get a lot of noise and at 20 dB you can not identify the sound at all.
  • Hartmut Pfitzinger
    Hartmut Pfitzinger over 9 years
    Then, my code will definitely help you because it produces much less distortion. 18dB should be perfectly possible, of course you increase the background noise by the same amount, but since the speech is very loud then, it masks the background noise and should be perfectly understandably. Of course, you can further increase it, but then it becomes really tricky.
  • 0xC0DED00D
    0xC0DED00D over 9 years
    Thanks, I will check it.
  • 0xC0DED00D
    0xC0DED00D over 9 years
    Thanks, it did worked at near 12-14 dB. I did merged the code from the sonic library too to increase volume, but that increase too much noise and distortion, so I kept the volume at 1.5-2.0 and instead tried to increase gain. I got decent sound volume which doesn't sound too loud in phone, but when listened on a PC sounds loud enough. Looks like that's the farthest I could go.
  • Ali
    Ali over 6 years
    @Hartmut Pfitzinger How to apply gain in Stereo recording mode i.e. AudioFormat.CHANNEL_IN_STEREO?
  • Hartmut Pfitzinger
    Hartmut Pfitzinger over 6 years
    @Ali Simply do that twice, separately for the data of each channel but with the same gain value.
  • tpaczesny
    tpaczesny over 6 years
    Thanks for this answer. I had similar issues, and changing MPEG_4/AAC from 3GPP/AMR_NB improved quality and volume noticeably.
  • Vikash
    Vikash over 5 years
    I am using the above code, but the file which I am creating using this is not playable. I am getting E/MediaPlayer: Error (1,-2147483648) any suggestion why I might be getting this.
  • suv
    suv over 4 years
    What if i want to store the audio in the file? I am not getting whether to store the samplebytes or recbuffer in the file. Please help.
  • Wiktor Kalinowski
    Wiktor Kalinowski almost 3 years
    Hi, what is mVolume how did you get this value?