【问题标题】:Increase volume output of recorded audio增加录制音频的音量输出
【发布时间】:2014-11-23 04:03:06
【问题描述】:

我正在尝试在 Android 中制作通话录音应用。我正在使用扬声器来录制上行链路和下行链路音频。我面临的唯一问题是音量太低。我已将使用 AudioManager 的设备音量增加到最大,但不能超过。

我第一次使用MediaRecorder,但由于它功能有限且提供压缩音频,我尝试使用AudioRecorder。我还没有弄清楚如何增加音频。我也检查过 Github 上的项目,但它没有用。过去两周我在 stackoverflow 上进行了搜索,但根本找不到任何东西。

我很确定这是可能的,因为许多其他应用程序都在这样做。例如自动通话记录器就是这样做的。

我知道我必须对音频缓冲区做一些事情,但我不太确定需要做什么。你能指导我吗?

更新:-
很抱歉我忘了提及我已经在使用 Gain。我的代码几乎与RehearsalAssistant 相似(实际上我是从那里派生出来的)。增益不会超过 10dB,并且不会过多地增加音频音量。我想要的是我应该能够在不将耳朵放在扬声器上的情况下收听音频,这是我的代码中缺少的。

我在 SoundDesign SE here 上问过一个关于音量/响度功能的类似问题。它提到增益和响度是相关的,但它没有设置实际的响度级别。我不确定事情是如何运作的,但我决心获得大音量输出。

【问题讨论】:

    标签: android audio audio-recording android-audiorecord


    【解决方案1】:

    简单使用MPEG_4格式

    要增加通话录音音量,请按如下方式使用 AudioManager:

    int deviceCallVol;
    AudioManager audioManager;
    

    开始录制:

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

    停止录制:

    //将音量恢复到初始状态

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

    【讨论】:

    • 感谢您的回答。我已经尝试过各种格式。 MediaRecorder 绝对不能解决我的目的(除非有破解或解决方法)。我有点期待某种算法可以应用于音频缓冲区以提高响度。
    • 感谢您的回答。我遇到了类似的问题,将 MPEG_4/AAC 从 3GPP/AMR_NB 更改为显着提高了质量和音量。
    【解决方案2】:

    你显然有 AudioRecord 的东西在运行,所以我跳过了 sampleRateinputSource 的决定。要点是,您需要在录音循环中适当地操作记录数据的每个样本以增加音量。像这样:

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

    【讨论】:

    • 其实我已经在使用增益了,但是增加10dB以上就不行了。我正在使用此 URL 中的代码 - sourceforge.net/p/rehearsalassist/code/HEAD/tree/android/…
    • 你说超过10dB就不行了?在 12 或 20dB 时,您究竟观察到了什么?
    • 声音在增益超过 10dB 时失真。它开始产生大量噪音,在 20 dB 时您根本无法识别声音。
    • 那么,我的代码肯定会对您有所帮助,因为它产生的失真要少得多。 18dB 应该是完全有可能的,当然你会增加同样的背景噪音,但是由于当时的语音非常响亮,它掩盖了背景噪音,应该是完全可以理解的。当然,你可以进一步增加它,但它变得非常棘手。
    • 谢谢,它确实在 12-14 分贝附近工作。我也合并了 sonic 库中的代码以增加音量,但这会增加太多的噪音和失真,所以我将音量保持在 1.5-2.0,而是尝试增加增益。我得到了不错的音量,在电话中听起来不太响,但在 PC 上听时听起来足够响亮。看来这是我能走的最远了。
    【解决方案3】:

    在我的应用程序中,我使用开源 sonic library。它的主要目的是加快/减慢语音,但除此之外它还可以增加响度。我将它应用于播放,但它必须同样适用于录制。只需在压缩它们之前将您的样本通过它。它也有一个Java接口。希望这会有所帮助。

    【讨论】:

    • 谢谢,我会查的。
    【解决方案4】:

    感谢 Hartmut 和 beworker 的解决方案。 Hartmut 的代码确实在 12-14 dB 附近工作。我也合并了 sonic 库中的代码以增加音量,但这会增加太多的噪音和失真,所以我将音量保持在 1.5-2.0,而是尝试增加增益。我得到了不错的音量,在电话中听起来不太响,但在 PC 上听时听起来足够响亮。看来这是我能走的最远了。

    我正在发布我的最终代码以增加响度。请注意,使用增加 mVolume 会增加太多噪音。尝试增加增益。

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

    【讨论】:

    • 你好,mVolume 是什么,你是怎么得到这个值的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-18
    • 2017-01-16
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    相关资源
    最近更新 更多