【问题标题】:How do you attach a reverb effect to AudioRecord/PCM data and save it to a file?如何将混响效果附加到 AudioRecord/PCM 数据并将其保存到文件中?
【发布时间】:2017-06-12 12:33:44
【问题描述】:

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

到目前为止,我已经能够使用 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 传送到某个外部服务/库,或者使用任何混响算法修改缓冲区。

【问题讨论】:

    标签: java android pcm android-audiorecord


    【解决方案1】:

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

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

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

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

    效果:回声、镶边、门限、混响、rool、whoosh、3 频段均衡器、双二阶 IIR 滤波器(低通、高通、带通、高架、低-货架,参数,缺口)

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

    一切顺利!


    添加有关如何使用 superpoweredSDK 完成此操作的更多详细信息。 superpowered 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);
    

    【讨论】:

    • 感谢您的回复。我已经尝试过 Superpowered,但极少有教程和使用指南。所以我完全迷失了试图实现任何东西。我的 JNI 经验非常有限。你能指出我使用混响的 Superpowered 实现吗?
    • JNI 代码是github.com/CayaQi/SuperpoweredDemo/blob/master/app/src/main/jni/…,并且 android 代码也可以在 repo 中找到。
    • 该示例对于仅听到混响效果很有用,但它没有显示如何保存带有效果的文件,只是如何在播放音频文件时应用效果
    • 已编辑答案,检查是否对您有帮助
    • 另外那个例子也有录音的样子。见 SuperpoweredRecorder *recorder = new SuperpoweredRecorder(pathTemp,44100,1);更多详情superpowered.com/docs/class_superpowered_recorder.html
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-03
    相关资源
    最近更新 更多