#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); }
以下情况会导致创建失败:
AGC有三种可调节参数,根据需要进行调整。
ID | 含义 | 取值范围 | 默认值 |
---|---|---|---|
SAMICorePropertyID_AGC_SetTargetLevel | 设置最大的音量界限,改变增益不会超过这个值,单位是dbfs,比如默认值为3,即最大音量是-3dbfs | [0,100] | 3 |
SAMICorePropertyID_AGC_SetGain | 设置音频的增益,单位是dbfs,比如默认值为9,即+9dbfs | [0, 100] | 9 |
SAMICorePropertyID_AGC_SetEnableLimiter | 设置是否开启限制器 | 0/1 | 1 |
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); }
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); }
更新音频数据的指针,指向正确的内存即可,这样可以避免内存数据的拷贝。
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); }
有几种情况导致处理失败:
需要注意的是:当 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;