如何将混响效果附加到AudioRecord / PCM数据并将其保存到文件?

我想录制来自麦克风的输入,附加混响效果,并将结果保存到文件中。 我的用例是一款应用程序,可让您在录制后唱出歌曲并选择不同的预设混响选项,然后保存您的演奏并将其存储在后端服务器上。 我发送到服务器的文件需要应用混响效果。

到目前为止,我已经能够使用AudioRecord录制输入,并且我可以为AudioTrack添加混响效果以听到混响效果,但我仍然坚持找出如何在嵌入混响效果的情况下保存音频。 这是我到目前为止所拥有的:

 private void startRecording() { final int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT); mRecorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, bufferSize); if(NoiseSuppressor.isAvailable()) { NoiseSuppressor ns = NoiseSuppressor.create(mRecorder.getAudioSessionId()); ns.setEnabled(true); } if(AcousticEchoCanceler.isAvailable()) { AcousticEchoCanceler aec = AcousticEchoCanceler.create(mRecorder.getAudioSessionId()); aec.setEnabled(true); } mPlayer = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, AUDIO_FORMAT, bufferSize, AudioTrack.MODE_STREAM); PresetReverb reverb = new PresetReverb(1, mPlayer.getAudioSessionId()); reverb.setPreset(PresetReverb.PRESET_LARGEHALL); reverb.setEnabled(true); mPlayer.setAuxEffectSendLevel(1.f); mRecorder.startRecording(); mPlayer.play(); new RecordingThread(mRecorder, mPlayer, bufferSize) { @Override public void onReleased() { mRecorder = null; mPlayer = null; } }.start(); } public class RecordingThread extends Thread { private static final String TAG = RecordingThread.class.getSimpleName(); private final AudioRecord mRecorder; private final AudioTrack mPlayer; private final int mBufferSize; public RecordingThread(AudioRecord recorder, AudioTrack player, int bufferSize) { mRecorder = recorder; mPlayer = player; mBufferSize = bufferSize; } @Override public void run() { byte[] buffer = new byte[mBufferSize]; int read; while ((read = mRecorder.read(buffer, 0, buffer.length)) > 0) { mPlayer.write(buffer, 0, buffer.length); } mRecorder.release(); mPlayer.release(); onReleased(); Timber.tag(TAG); Timber.i("Exited with code %s", read); } public void onReleased() { } } 

理想情况下,能够将PresetReverb附加到AudioRecord而不是PresetReverb上会很好,但是当我这样做时,我得到:

 java.lang.RuntimeException: Cannot initialize effect engine for type: 47382d60-ddd8-11db-bf3a-0002a5d5c51b Error: -3 

所以现在我认为我需要将PCM数据从AudioRecord到某个外部服务/库,或者使用任何混响算法来修改缓冲区。

根据https://developer.android.com/reference/android/media/audiofx/PresetReverb.html

PresetReverb是输出混合辅助效果,应在音频会话0上创建。为了将MediaPlayer或AudioTrack提供给此效果,必须将它们明确地附加到它,并且必须指定发送级别。 使用getId()方法返回的效果ID在将其附加到MediaPlayer或AudioTrack时指定此特定效果。

由于这是为与audiotrack一起使用而设计的,因此不能将其附加到AudioRecord。 我想你有类似的结论。

我建议你使用这个SDK https://github.com/superpoweredSDK/Low-Latency-Android-Audio-iOS-Audio-Engine 。 它支持android和以下效果:

效果: 回声,镶边,门, 混响 ,rool,飞快移动,3频段均衡器,双二阶IIR滤波器(低通,高通,带通,高架,低架,参数,陷波)

您还可以考虑https://github.com/ClearVolume/ClearAudio 。 您可以使用此文件来应用混响效果https://github.com/ClearVolume/ClearAudio/blob/master/src/java/clearaudio/synthesizer/filters/ReverbFilter.java

祝一切顺利 !


使用superpoweredSDK添加更多有关如何完成此操作的详细信息。 超级SDK有一个名为SuperpoweredReverb的filter。 这种方式的工作方式如下:

在此处输入图像描述

让我们通过一些代码看到这个:

 reverb = new SuperpoweredReverb(samplerate); reverb->enable(true); reverb->setMix(floatValue); // Limited to >= 0.0f and <= 1.0f. reverb->setRoomSize(floatValue); // Limited to >= 0.0f and <= 1.0f. SuperpoweredShortIntToFloat(intBuffer, floatBuffer, numberOfSamples); bool res = reverb->process(floatBuffer, floatBuffer, numberOfSamples); SuperpoweredFloatToShortInt(floatBuffer, intBuffer, numberOfSamples); 

让我尽力解释这里发生的事情:

创建filter

 reverb = new SuperpoweredReverb(samplerate); reverb->enable(true); 

可选:对此filter应用其他选项,例如

 reverb->setMix(floatValue); // Limited to >= 0.0f and <= 1.0f. reverb->setRoomSize(floatValue); // Limited to >= 0.0f and <= 1.0f. 

获取源样本; 如果样本是在Integer中使用SuperpoweredShortIntToFloat进行转换。 这里intBuffer有输入音频样本, numberOfSamples是样本数。 floatBuffer将包含浮点转换缓冲区

 SuperpoweredShortIntToFloat(intBuffer, floatBuffer, numberOfSamples); 

调用过程以应用混响效果。 此方法将应用混响效果并再次将输出复制到floatBuffer

 bool res = reverb->process(floatBuffer, floatBuffer, numberOfSamples); 

要将其转换回Int,请使用以下方法

 SuperpoweredFloatToShortInt(floatBuffer, intBuffer, numberOfSamples); 

然后,您可以将此混响应用音频样本存储在您想要的任何位置,无论是在文件中还是播放它


来自superpoweredSDK的更多发现,它还具有录音function。 请参阅http://superpowered.com/docs/class_superpowered_recorder.html

一个例子:

 recorder = new SuperpoweredRecorder(temporaryPath, samplerate); recorder->start(destinationPath); // With input samples SuperpoweredShortIntToFloat(intBuffer, floatBuffer, numberOfSamples); bool res = recorder->process(floatBuffer, NULL, numberOfSamples); SuperpoweredFloatToShortInt(floatBuffer, intBuffer, numberOfSamples);