本功能是在单线程中使用,内部采用同步处理的策略即一帧输入处理后会返回一帧输出,不支持多线程调用
#include "me_audio_encoder.h" #include "sami_core.h" #include "demo_helper.h" #include <iostream> #include <string> int main(int argc, char* argv[]){ if(argc < 3) { std::cerr << "Usage: " << argv[0] << " input.wav output.wav\n"; return -1; } const std::string input = argv[1]; const std::string output = argv[2]; //解码输入文件 std::shared_ptr<FileSource> input_src = FileSource::create(input); if(!input_src) { std::cerr << "cannot open " << input << std::endl; return -1; } int total_samples = input_src->getNumFrames(); int num_channels = input_src->getNumChannel(); int sample_rate = input_src->getSampleRate(); int num_samples = sample_rate / 100; auto input_wav_data = loadWholeAudioFile(input_src); //create handle SAMICoreAudioCommonParameter parameter; parameter.sampleRate = sample_rate; parameter.channels = num_channels; SAMICoreHandle handle; ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify_Loudnorm, ¶meter); assert(ret == SAMI_OK); // set property SAMICoreLoudnormProperty loudnormProperty; loudnormProperty.target_lufs = -16; loudnormProperty.source_lufs = 0; loudnormProperty.source_peak = 99; SAMICoreProperty coreProperty; coreProperty.id = SAMICorePropertyID_Processor_Loudnorm; coreProperty.data = &loudnormProperty; coreProperty.writable = 0; coreProperty.dataLen = 1; coreProperty.type = SAMICoreDataType_LoudNorm; ret = SAMICoreSetProperty(handle, SAMICorePropertyID_Processor_Loudnorm, &coreProperty); assert(ret == (SAMI_OK)); SAMICoreAudioBuffer in_buffer; in_buffer.data = new float*[num_channels]; in_buffer.isInterleave = 0; in_buffer.numberChannels = num_channels; for(int i = 0; i < num_channels; i++) { in_buffer.data[i] = new float[num_samples]; } SAMICoreAudioBuffer out_buffer; out_buffer.data = new float*[num_channels]; out_buffer.isInterleave = 0; out_buffer.numberChannels = num_channels; for(int i = 0; i < num_channels; i++) { out_buffer.data[i] = new float[num_samples]; } SAMICoreBlock in_block; SAMICoreBlock out_block; in_block.numberAudioData = 1; in_block.dataType = SAMICoreDataType_AudioBuffer; in_block.audioData = &in_buffer; out_block.numberAudioData = 1; out_block.dataType = SAMICoreDataType_AudioBuffer; out_block.audioData = &out_buffer; int inx = 0; // process while(inx < total_samples - num_samples) { int actual_block_size = getNextBlockSize(inx, total_samples, num_samples); in_buffer.numberSamples = actual_block_size; out_buffer.numberSamples = actual_block_size; for(int i = 0; i < num_channels; i++) { memcpy(in_buffer.data[i], input_wav_data[i].data() + inx, actual_block_size * sizeof(float)); } ret = SAMICoreProcess(handle, &in_block, &out_block); auto* outBuffer = (SAMICoreAudioBuffer*)out_block.audioData; if(ret != SAMI_OK || outBuffer == nullptr) { std::cerr << "process error: " << ret; exit(-1); } // write output block to file writePlanarData(outBuffer->data, outBuffer->numberChannels, actual_block_size); inx += actual_block_size; } // destory for(int i = 0; i < num_channels; i++) { delete[] in_buffer.data[i]; delete[] out_buffer.data[i]; in_buffer.data[i] = nullptr; out_buffer.data[i] = nullptr; } SAMICoreDestroyHandle(handle); delete[] in_buffer.data; delete[] out_buffer.data; handle = nullptr; return 0; }
传入采样率、声道数和 maxBlockSize,通过 SAMICoreCreateHandleByIdentify
创建 handle。
// create handle SAMICoreAudioCommonParameter parameter; parameter.sampleRate = sample_rate; parameter.channels = num_channels; SAMICoreHandle handle; ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify_Loudnorm, ¶meter); assert(ret == SAMI_OK);
SAMICoreAudioBuffer,用于存放音频数据,更多关于音频数据格式请参看名词解释一节。SAMICoreBlock,用于存放需要处理的数据。
将 source_lufs(源文件响度) 、source_peak(源文件峰值) (参考响度检测和【C】响度检测)和 target_lufs(目标响度) 参数组成对象,通过 SAMICoreSetProperty 设置参数。
target_lufs(默认值-16dB),(-24到-12,建议实验值为-12,-16,-20)
source_lufs(默认值0dB),(-inf:输入为零数据时,-70 - 0:正常范围)
source_peak(默认值99),(0到1,部分歌曲可能大于1,截取到1)
SAMICoreLoudnormProperty loudnormProperty; loudnormProperty.target_lufs = -16; loudnormProperty.source_lufs = 0; loudnormProperty.source_peak = 99; SAMICoreProperty coreProperty; coreProperty.id = SAMICorePropertyID_Processor_Loudnorm; coreProperty.data = &loudnormProperty; coreProperty.writable = 0; coreProperty.dataLen = 1; coreProperty.type = SAMICoreDataType_LoudNorm; ret = SAMICoreSetProperty(handle, SAMICorePropertyID_Processor_Loudnorm, &coreProperty); assert(ret == (SAMI_OK));
由于此算法输入和输出的大小是对等的,所以为了提高效率输入和输出的内存空间都由用户提前分配好
SAMICoreAudioBuffer in_buffer; in_buffer.data = new float*[num_channels]; in_buffer.isInterleave = 0; in_buffer.numberChannels = num_channels; for(int i = 0; i < num_channels; i++) { in_buffer.data[i] = new float[num_samples]; } SAMICoreAudioBuffer out_buffer; out_buffer.data = new float*[num_channels]; out_buffer.isInterleave = 0; out_buffer.numberChannels = num_channels; for(int i = 0; i < num_channels; i++) { out_buffer.data[i] = new float[num_samples]; }
将待处理的音频数据拷贝到 in_buffer
中,经过 SAMICoreProcess
处理后,结果将拷贝至 out_buffer
中。
int inx = 0; while(inx < total_samples - num_samples) { int actual_block_size = getNextBlockSize(inx, total_samples, num_samples); in_buffer.numberSamples = actual_block_size; out_buffer.numberSamples = actual_block_size; for(int i = 0; i < num_channels; i++) { memcpy(in_buffer.data[i], input_wav_data[i].data() + inx, actual_block_size * sizeof(float)); } ret = SAMICoreProcess(handle, &in_block, &out_block); auto* outBuffer = (SAMICoreAudioBuffer*)out_block.audioData; if(ret != SAMI_OK || outBuffer == nullptr) { std::cerr << "process error: " << ret; exit(-1); } // write output block to file writePlanarData(outBuffer->data, outBuffer->numberChannels, actual_block_size); inx += actual_block_size; }
ret = SAMICoreDestroyHandle(handle);
此外,还要注意音频数据数据的内存释放(如果有)。例如:
for(int i = 0; i < num_channels; i++) { delete[] in_buffer.data[i]; delete[] out_buffer.data[i]; in_buffer.data[i] = nullptr; out_buffer.data[i] = nullptr; } delete[] in_buffer.data; delete[] out_buffer.data;