You need to enable JavaScript to run this app.
导航

【C】回声消除-V2

最近更新时间2023.03.16 11:40:12

首次发布时间2023.03.16 11:40:12

完整例子
#include "sami_core.h"

// help function
std::vector<uint8_t> loadModelAsBinary(const std::string& path) {
    std::ifstream file(path, std::ios::binary | std::ios::ate);
    std::streamsize size = file.tellg();
    file.seekg(0, std::ios::beg);

    std::vector<uint8_t> buffer(size);
    if(file.read((char*)buffer.data(), size)) { return buffer; }

    return {};
}

// step 0, load model
const std::string model_path = "/path/to/aec.model";
std::vector<uint_8> model_buffer = loadModelAsBinary(model_path);
assert(model_buffer.size() > 0);

// step 1, create aec handle
const int sample_rate = 44100; // 44100 needs aec44k.model, 16000 needs aec.model
const int num_channels = 2;
const int block_size = 512;
SAMICoreHandle handle = nullptr;
SAMICoreExecutorContextCreateParameter create_param;
memset(&create_param,0,sizeof(create_param));
create_param.sampleRate = sample_rate;
create_param.numChannel = num_channels;
create_param.maxBlockSize = block_size;
create_param.modelBuffer = (const char*)(model_buffer.data());
create_param.modelLen = model_buffer.size();
int ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify::SAMICoreIdentify_RNNAEC, & create_param);
assert(ret == SAMI_OK);

// step 2, create input and output audio block 
SAMICoreAudioBuffer in_mic_buffer;
SAMICoreAudioBuffer in_ref_buffer;
SAMICoreAudioBuffer out_buffer;

in_mic_buffer.numberChannels = num_channels;
in_mic_buffer.numberSamples = block_size;
in_mic_buffer.data = new float*[num_channels];
in_mic_buffer.isInterleave = 0;

in_ref_buffer.numberChannels = num_channels;
in_ref_buffer.numberSamples = block_size;
in_ref_buffer.data = new float*[num_channels];
in_ref_buffer.isInterleave = 0;

out_buffer.numberChannels = num_channels;
out_buffer.numberSamples = block_size;
out_buffer.data = new float*[num_channels];
out_buffer.isInterleave = 0;

for(int c = 0; c < int(num_channels); ++c){
    in_mic_buffer.data[c] = new float[block_size];
    in_ref_buffer.data[c] = new float[block_size];
    out_buffer.data[c] = new float[block_size];
}

SAMICoreAecInput aec_input;
aec_input.mic = &in_mic_buffer;
aec_input.ref = &in_ref_buffer;

SAMICoreBlock in_block;
SAMICoreBlock out_block;

in_block.numberAudioData = 1;
in_block.dataType = SAMICoreDataType_AecInput;
in_block.audioData = &aec_input;

out_block.numberAudioData = 1;
out_block.dataType = SAMICoreDataType_AudioBuffer;
out_block.audioData = &out_buffer;

// step 3, process block by block
for(;hasAudioSamples();)
{
    copyMicSamplesToInputBuffer(in_mic_buffer);
    copyRefSamplesToInputBuffer(in_ref_buffer);

    int ret = SAMICoreProcess(handle, &in_block, &out_block);
    assert(ret == SAMI_OK);

    // do something after process
    doSomethingAfterProcess(out_buffer);
}

// step 4, remember release resource
ret = SAMICoreDestroyHandle(handle);
assert(ret == SAMI_OK);

for(int c = 0; c < int(num_channels); ++c) {
    delete[] in_mic_buffer.data[c];
    delete[] in_ref_buffer.data[c];
    delete[] out_buffer.data[c];
}

delete[] in_mic_buffer.data;
delete[] in_ref_buffer.data;
delete[] out_buffer.data;
使用步骤

〇、从文件中读取模型

即读取整个模型文件到内存,实现方法自由发挥,例子中loadModelAsBinary仅供参考。算法模型详见回声消除介绍小节。

一、创建算法句柄

  1. 使用nn aec

传入模型内存地址、模型大小、采样率和 maxBlockSize,通过 SAMICoreCreateHandleByIdentify 创建 handle。

const int sample_rate = 44100; // 44100 needs aec44k.model, 16000 needs aec.model
const int num_channels = 2;
const int block_size = 512;
SAMICoreHandle handle = nullptr;
SAMICoreExecutorContextCreateParameter create_param;
create_param.sampleRate = sample_rate;
create_param.numChannel = num_channels;
create_param.maxBlockSize = block_size;
create_param.modelBuffer = (const char*)(model_buffer.data());
create_param.modelLen = model_buffer.size();
int ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify::SAMICoreIdentify_RNNAEC, & create_param);
assert(ret == SAMI_OK);
  1. 使用dsp aec
SAMICore3ACreateParameter createParameter;
createParameter.channels = num_channels;
createParameter.sampleRate = sample_rate;
int ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify::SAMICoreIdentify_AEC, &createParameter);
assert(ret == SAMI_OK);

有几种情况会导致创建失败:

  1. 模型数据不正确,例如模型数据损坏或者大小不对。

  2. 采样率不支持。目前 AEC 只支持 16000 和 44100 采样率,需要注意一下,采样率必须要与模型对应。16k 对应模型 aec.model,44.1k 对应 aec44k.model

二、创建 SAMICoreBlock 用于存放输入和输出

SAMICoreAudioBuffer,用于存放音频数据,AEC 目前仅 Planar-Float 。更多关于音频数据格式请参看名词****解释部分。SAMICoreBlock,用于存放需要处理的数据。

SAMICoreAudioBuffer in_mic_buffer;
SAMICoreAudioBuffer in_ref_buffer;
SAMICoreAudioBuffer out_buffer;

in_mic_buffer.numberChannels = num_channels;
in_mic_buffer.numberSamples = block_size;
in_mic_buffer.data = new float*[num_channels];
in_mic_buffer.isInterleave = 0;

in_ref_buffer.numberChannels = num_channels;
in_ref_buffer.numberSamples = block_size;
in_ref_buffer.data = new float*[num_channels];
in_ref_buffer.isInterleave = 0;

out_buffer.numberChannels = num_channels;
out_buffer.numberSamples = block_size;
out_buffer.data = new float*[num_channels];
out_buffer.isInterleave = 0;

for(int c = 0; c < int(num_channels); ++c){
    in_mic_buffer.data[c] = new float[block_size];
    in_ref_buffer.data[c] = new float[block_size];
    out_buffer.data[c] = new float[block_size];
}

SAMICoreAecInput aec_input;
aec_input.mic = &in_mic_buffer;
aec_input.ref = &in_ref_buffer;

SAMICoreBlock in_block;
SAMICoreBlock out_block;

in_block.numberAudioData = 1;
in_block.dataType = SAMICoreDataType_AecInput;
in_block.audioData = &aec_input;

out_block.numberAudioData = 1;
out_block.dataType = SAMICoreDataType_AudioBuffer;
out_block.audioData = &out_buffer;

三、处理音频

拷贝数据进行处理

将待处理的音频数据拷贝到 in_mic_bufferin_ref_buffer,经过 SAMICoreProcess 处理后,结果将拷贝至 output 中。示例中采用这种方法。

for(;hasAudioSamples();)
{
    copyMicSamplesToInputBuffer(in_mic_buffer);
    copyRefSamplesToInputBuffer(in_ref_buffer);

    int ret = SAMICoreProcess(handle, &in_block, &out_block);
    assert(ret == SAMI_OK);

    // do something after process
    doSomethingAfterProcess(out_buffer);
}

In-Place 进行处理

更新音频数据的指针,指向正确的内存即可,这样可以避免内存数据的拷贝。

for(;hasAudioSamples();)
{
    updateMicInputBuffer(in_mic_buffer);
    updateRefInputBuffer(in_ref_buffer);
    updateOutputBuffer(out_buffer);

    int ret = SAMICoreProcess(handle, &in_block, &out_block);
    assert(ret == SAMI_OK);

    doSomethingAfterProcess(out_buffer);
}

四、释放资源

释放 handle

ret = SAMICoreDestroyHandle(handle);

此外,还要注意音频数据数据的内存释放(如果有)。例如:

for(int c = 0; c < int(num_channels); ++c) {
    delete[] in_mic_buffer.data[c];
    delete[] in_ref_buffer.data[c];
    delete[] out_buffer.data[c];
}

delete[] in_mic_buffer.data;
delete[] in_ref_buffer.data;
delete[] out_buffer.data;