Increase volume output of recorded audio

馋奶兔 提交于 2019-11-30 02:25:04

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;
        }
    }

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);

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
        }
    };

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!