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

【C】自动增益

最近更新时间2023.07.07 11:16:17

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

完整例子
#include "sami_core.h"


// step 1, create handle
SAMICoreHandle handle;
SAMICore3ACreateParameter createParameter;
createParameter.channels = input_file.num_channels;
createParameter.sampleRate = input_file.sample_rate;
int ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify_AGC, &createParameter);
if(ret != SAMI_OK) {
    printfE("create agc handle failed");
    exit(-1);
}

// set target level
float target_level = 20;
SAMICoreProperty target_property;
memset(&target_property, 0, sizeof(SAMICoreProperty));
target_property.id = SAMICorePropertyID_AGC_SetTargetLevel;
target_property.type = SAMICoreDataType_Float;
target_property.data = &target_level;
ret = SAMICoreSetProperty(handle, SAMICorePropertyID_AGC, &target_property);
if(ret != SAMI_OK) {
    std::cerr << "set gain fail, ret" << ret;
    exit(-1);
}

// set Gain
float gain = 20;
SAMICoreProperty gain_property;
memset(&gain_property, 0, sizeof(SAMICoreProperty));
gain_property.id = SAMICorePropertyID_AGC_SetGain;
gain_property.type = SAMICoreDataType_Float;
gain_property.data = &gain;
ret = SAMICoreSetProperty(handle, SAMICorePropertyID_AGC, &gain_property);
if(ret != SAMI_OK) {
    std::cerr << "set gain fail, ret" << ret;
    exit(-1);
}

//set enable limiter
float enable_limiter = 1;
SAMICoreProperty limiter_property;
memset(&limiter_property, 0, sizeof(SAMICoreProperty));
limiter_property.id = SAMICorePropertyID_AGC_SetEnableLimiter;
limiter_property.type = SAMICoreDataType_Float;
limiter_property.data = &gain;
ret = SAMICoreSetProperty(handle, SAMICorePropertyID_AGC, &gain_property);
if(ret != SAMI_OK) {
    std::cerr << "set gain fail, ret" << ret;
    exit(-1);
}

// step 2, create input and output audio block 
int block_size = 512;
SAMICoreAudioBuffer in_audio_buffer;
in_audio_buffer.numberChannels = num_channels;
in_audio_buffer.numberSamples = block_size;
in_audio_buffer.data = new float*[num_channels];
in_audio_buffer.isInterleave = 0;

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

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

SAMICoreBlock in_block;
memset(&in_block, 0, sizeof(SAMICoreBlock));
in_block.numberAudioData = 1;
in_block.dataType = SAMICoreDataType::SAMICoreDataType_AudioBuffer;
in_block.audioData = &in_audio_buffer;

SAMICoreBlock out_block;
memset(&out_block, 0, sizeof(SAMICoreBlock));
out_block.numberAudioData = 1;
out_block.dataType = SAMICoreDataType::SAMICoreDataType_AudioBuffer;
out_block.audioData = &out_audio_buffer;


// step 3, process block by block
for(;hasAudioSamples();
{
    copySamplesToInputBuffer(in_audio_buffer); //拷贝数据或者修改数据指针in_audio_buffer的指向
    int ret = SAMICoreProcess(handle, &in_block, &out_block);
    assert(ret == SAMI_OK);

    // do something after process
    doSomethingAfterProcess(out_block);  //业务从out_block拷贝处理后的数据
}

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

for(int c = 0; c < int(num_channels); ++c) {
    delete[] in_audio_buffer.data[c];
    delete[] out_audio_buffer.data[c];
}

delete[] in_audio_buffer.data;
delete[] out_audio_buffer.data;
使用步骤

一、创建算法句柄

传入采样率和 maxBlockSize,通过 SAMICoreCreateHandleByIdentify 创建 handle。

SAMICore3ACreateParameter createParameter;
createParameter.channels = input_file.num_channels;
createParameter.sampleRate = input_file.sample_rate;
int ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify_AGC, &createParameter);
if(ret != SAMI_OK) {
    printfE("create agc handle failed");
    exit(-1);
}

以下情况会导致创建失败:

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

二、设置参数

AGC有三种可调节参数,根据需要进行调整。

ID含义取值范围默认值
SAMICorePropertyID_AGC_SetTargetLevel设置最大的音量界限,改变增益不会超过这个值,单位是dbfs,比如默认值为3,即最大音量是-3dbfs[0,100]3
SAMICorePropertyID_AGC_SetGain设置音频的增益,单位是dbfs,比如默认值为9,即+9dbfs[0, 100]9
SAMICorePropertyID_AGC_SetEnableLimiter设置是否开启限制器0/11
float target_level = 20;
SAMICoreProperty target_property;
memset(&target_property, 0, sizeof(SAMICoreProperty));
target_property.id = SAMICorePropertyID_AGC_SetTargetLevel;
target_property.type = SAMICoreDataType_Float;
target_property.data = &target_level;
ret = SAMICoreSetProperty(handle, SAMICorePropertyID_AGC, &target_property);
if(ret != SAMI_OK) {
    std::cerr << "set gain fail, ret" << ret;
    exit(-1);
}

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

SAMICoreAudioBuffer,用于存放音频数据,它支持 Planar-Float 。SAMICoreBlock,用于存放需要处理的数据。
注:AGC以block_size为单位进行处理,不同block_size处理结果不同

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

SAMICoreBlock in_block;
memset(&in_block, 0, sizeof(SAMICoreBlock));
in_block.numberAudioData = 1;
in_block.dataType = SAMICoreDataType::SAMICoreDataType_AudioBuffer;
in_block.audioData = &in_audio_buffer;

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

SAMICoreBlock out_block;
memset(&out_block, 0, sizeof(SAMICoreBlock));
out_block.numberAudioData = 1;
out_block.dataType = SAMICoreDataType::SAMICoreDataType_AudioBuffer;
out_block.audioData = &out_audio_buffer;

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

四、处理音频

拷贝数据进行处理

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

for(;hasAudioSamples();)
{
    copySamplesToInputBuffer(in_audio_buffer);
    int ret = SAMICoreProcess(handle, &in_block, &out_block);
    assert(ret == SAMI_OK);

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

In-Place 进行处理

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

for(;hasAudioSamples();)
{
    updateInputBuffer(in_audio_buffer);
    updateOutputBuffer(out_audio_buffer);

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

    doSomethingAfterProcess(out_block);
}

甚至你可以将 input 和 output 的内存指向同一处,这样处理后的结果将以 overwrite 的形式立即生效。

for(;hasAudioSamples();)
{
    updateBuffer(in_audio_buffer);

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

    doSomethingAfterProcess(in_block);
}

有几种情况导致处理失败:

  1. 无效的 handle。handle 创建失败了,但仍然拿错误的 handle 进行 process
  2. SAMICoreAudioBuffer 和 SAMICoreBlock 设置错误。

需要注意的是:当 block size 较小的情况下,前几帧会由于数据量不足无法处理而返回静音数据,这种情况下 ret 仍然为 SAMI_OK

五、释放资源

释放 handle

ret = SAMICoreDestroyHandle(handle);

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

for(int c = 0; c < int(num_channels); ++c) {
    delete[] in_audio_buffer.data[c];
    delete[] out_audio_buffer.data[c];
}

delete[] in_audio_buffer.data;
delete[] out_audio_buffer.data;
handle = nullptr;