如何将混响效果附加到音频记录/ PCM数据并将其保存到文件中?

2022-09-04 23:02:02

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

到目前为止,我已经能够使用 录制输入,并且可以添加混响效果来收听混响效果,但是我一直不知道如何保存嵌入混响效果的音频。以下是我到目前为止所拥有的:AudioRecordAudioTrack

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() {
    }
}

因此,理想情况下,能够将 连接到 而不是 上会很好,但是当我这样做时,我会得到:PresetReverbAudioRecordAudioTrack

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

所以现在我想我需要将PCM数据从管道传输到某个外部服务/库,或者使用混响算法的外观来修改缓冲区。AudioRecord


答案 1

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

PresetReverb 是一种输出混音辅助效果,应在音频会话 0 上创建。为了将 MediaPlayer 或 AudioTrack 馈送到此效果中,必须将它们显式附加到该效果,并且必须指定发送级别。使用 getId() 方法返回的效果 ID 在将此特定效果附加到 MediaPlayer 或 AudioTrack 时指定此特定效果。

由于这是设计用于音频轨道的,因此无法将其附加到AudioRecord。我想你也有类似的结论。

我建议您使用此SDK https://github.com/superpoweredSDK/Low-Latency-Android-Audio-iOS-Audio-Engine。它支持安卓和以下效果:

效果:回声、镶边器、栅极、混响、rool、嘶嘶声、3 波段均衡器、双二阶 IIR 滤波器(低通、高通、带通、高架、低架、参数、陷波)

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

万事如意!


添加了有关如何使用超能力SDK完成此操作的更多详细信息。超能力SDK有一个名为SuperpoweredReverb的过滤器。其工作方式如下:

enter image description here

让我们通过一些代码来看看这一点:

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.

获取源样品 ;如果示例位于整数中,则使用进行转换。这里包含输入音频样本,是样本数。 将包含浮点转换缓冲区SuperpoweredShortIntToFloatintBuffernumberOfSamplesfloatBuffer

SuperpoweredShortIntToFloat(intBuffer, floatBuffer, numberOfSamples);

调用进程以应用混响效果。此方法将应用混响效果,并再次将输出复制到浮点缓冲器

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

答案 2

推荐