我想录制来自麦克风的输入,附加混响效果,并将结果保存到文件中。我的用例是一款应用程序,可让您在录制后唱歌并选择不同的预设混响选项,然后保存您的演奏并将其存储在后端服务器上。我发送给服务器的文件需要应用一个混响效果。
到目前为止,我已经能够使用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
而不是AudioTrack
上会很高兴,但是当我这样做时,我会得到:
java.lang.RuntimeException: Cannot initialize effect engine for type: 47382d60-ddd8-11db-bf3a-0002a5d5c51b Error: -3
所以现在我认为我需要将PCM数据从AudioRecord
传输到某个外部服务/库,或者使用任何混响算法来修改缓冲区。
答案 0 :(得分:5)
根据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滤波器(低通,高通,带通,高架,低-shelf,参数,缺口)
您还可以考虑https://github.com/ClearVolume/ClearAudio。您可以使用此文件应用混响效果https://github.com/ClearVolume/ClearAudio/blob/master/src/java/clearaudio/synthesizer/filters/ReverbFilter.java
一切顺利!
使用superpoweredSDK添加更多有关如何完成此操作的详细信息。超级SDK有一个名为SuperpoweredReverb的过滤器。其工作方式如下:
让我们通过一些代码看到这一点:
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);
让我尽力解释这里发生的事情:
创建过滤器
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
有输入音频样本,numberOfSamples
是样本数。 floatBuffer
将包含浮点转换缓冲区
SuperpoweredShortIntToFloat(intBuffer, floatBuffer, numberOfSamples);
调用过程以应用混响效果。此方法将应用混响效果并将输出再次复制到floatBuffer
bool res = reverb->process(floatBuffer, floatBuffer, numberOfSamples);
要将其转换回Int,请使用以下方法
SuperpoweredFloatToShortInt(floatBuffer, intBuffer, numberOfSamples);
然后你可以将这个混响应用的音频样本存储在你想要的任何地方,无论是在文件中还是播放
来自superpoweredSDK的更多发现,它还具有录制功能。见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);