//help function std::vector<uint8_t> loadFileAsBinary(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 1 : create handle const string res_path = "res.dat"; SAMICoreBinaryContextCreateParameter param; //资源文件路径创建 param.type = SAMICoreBinaryType::binaryTypeFile; param.data = (void*)res_path.c_str(); param.len = res_path.lenght(); //二进制数据创建 //std::vector<uint_8> content_res = loadFileAsBinary(res_path); //param.type = SAMICoreBinaryType::binaryTypeData; //param.data = (void*)content_res.data(); //param.dataLen = int(content_res.size()); //创建句柄 SAMICoreHandle handle; int ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify_Processor_ContextWithBinaryRes,¶m); if (ret != SAMI_OK) { cout << "sami_core handler create fail " << ret << endl; return 0; } //step 2: Prepare const int block_size = 512; const int sample_rate = 48000; const int num_channels = 2; SAMICoreProcessorPrepareParameter parameter; parameter.blockSize = block_size; parameter.sampleRate = sample_rate; SAMICoreProperty property; property.data = &(parameter); property.id = SAMICorePropertyId::SAMICorePropertyID_Processor_ContextPrepare; property.dataLen = sizeof(SAMICoreProcessorPrepareParameter); ret = SAMICoreSetProperty(handle, SAMICorePropertyId::SAMICorePropertyID_Processor_ContextPrepare, &property); //step 3:create input and output audio block 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; in_block.dataType = SAMICoreDataType_AudioBuffer; in_block.numberAudioData = 1; in_block.audioData = &in_audio_buffer; SAMICoreBlock out_block; out_block.dataType = SAMICoreDataType_AudioBuffer; out_block.numberAudioData = 1; out_block.audioData = &out_audio_buffer; //step 4: process buffer for(hasAudioData){ copySamplesToInputBuffer(in_audio_buffer); //处理一帧数据 ret = SAMICoreProcess(handle, &in_block, &out_block); if(ret != SAMI_OK) { std::cerr << "ret: " << ret << std::endl; } doSomethingAfterProcess(out_block); //业务从out_block拷贝处理后的数据 } //step 4: release handle and buffer ret = SAMICoreDestroyHandle(handle); assert(ret == SAMI_OK); handle = nullptr; 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;
创建句柄有两种形式
SAMICoreBinaryContextCreateParameter param; param.type = SAMICoreBinaryType::binaryTypeFile; param.data = (void*)res_path.c_str(); param.len = res_path.s SAMICoreHandle handle; int ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify_Processor_ContextWithBinaryRes,¶m); if (ret != SAMI_OK) { cout << "sami_core handler create fail " << ret << endl; return 0; }
SAMICoreBinaryContextCreateParameter param; param.type = SAMICoreBinaryType::binaryTypeData; param.data = (void*)content_res.data(); param.dataLen = int(content_res.size()); SAMICoreHandle handle; int ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify_Processor_ContextWithBinaryRes, ¶m); if (ret != SAMI_OK) { cout << "sami_core handler create fail " << ret << endl; return 0; }
说明:在使用功能之前,需要进行一系列准备工作,需要输入音频采样率和 blockSize,其中blockSize 实际上表示 max block size, 表示整个处理过程中可能出现的最大音频块大小,内部会进行一些初始化。通常这个值由设备或者使用者提供。
参数介绍:
property.data
指定SAMICoreProcessorPrepareParameter
的实例
property.dataLen
指定SAMICoreProcessorPrepareParameter
结构体的长度
property.id
指定SAMICorePropertyID_Processor_ContextPrepare
返回值:
成功返回0,其他返回值参考错误码
SAMICoreProcessorPrepareParameter parameter; parameter.blockSize = block_size; parameter.sampleRate = sample_rate; SAMICoreProperty property; property.data = &(parameter); property.id = SAMICorePropertyId::SAMICorePropertyID_Processor_ContextPrepare; property.dataLen = sizeof(SAMICoreProcessorPrepareParameter); int ret = SAMICoreSetProperty(handle, SAMICorePropertyId::SAMICorePropertyID_Processor_ContextPrepare, &property); assert(ret == SAMI_OK);
SAMICoreAudioBuffer,用于存放音频数据,它仅支持 Planar-Float 类型数据。
更多关于音频数据格式请参看名词解释部分。
SAMICoreBlock,用于存放需要处理的数据。
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; in_block.dataType = SAMICoreDataType_AudioBuffer; in_block.numberAudioData = 1; in_block.audioData = &in_audio_buffer; SAMICoreBlock out_block; out_block.dataType = SAMICoreDataType_AudioBuffer; out_block.numberAudioData = 1; out_block.audioData = &out_audio_buffer;
for(hasAudioData){ copySamplesToInputBuffer(in_audio_buffer); //处理一帧数据 ret = SAMICoreProcess(handle, &in_block, &out_block); if(ret != SAMI_OK) { std::cerr << "ret: " << ret << std::endl; } doSomethingAfterProcess(out_block); //业务从out_block拷贝处理后的数据 }
SAMICoreProcess函数 (对音频进行处理)
参数:
handle:处理的句柄
SAMICoreBlock:包含音频数据的结构体,除数据外还有数据大小和数据类型。
返回值:
返回0,其他返回值参考错误码
使用预置音效的时候,一个很常见的使用场景就是一个线程处理,通过ui触发切换变声效果,所以我们要提供一个支持热切换的功能,sdk提供了一个hotswap的接口,另外提供了bypass.dat用于原声的切换
SAMICoreBinaryContextUpdateParameter updateParameter; updateParameter.type = SAMICoreBinaryType::binaryTypeFile; const string new_res_path = "../../../res/tob/preset/robot.dat"; updateParameter.data = (void*)new_res_path.c_str(); updateParameter.dataLen = new_res_path.size(); SAMICoreProperty update_property; update_property.data = &updateParameter; update_property.dataLen = sizeof(updateParameter); update_property.type = SAMICoreDataType_ResourceParameter; ret = SAMICoreSetProperty(handle,SAMICorePropertyID_Processor_ContextUpdateFromBinaryFile, &update_property); if(ret != SAMI_OK) { cout << "sami_core update data error:" << ret << endl; return 0; }
const auto& new_dat_str = loadFileAsBinary(ifstream{new_res_path, ios::binary}); SAMICoreBinaryContextUpdateParameter updateParameter; updateParameter.type = SAMICoreBinaryType::binaryTypeData; updateParameter.data = (void*)new_dat_str.data(); updateParameter.dataLen = new_dat_str.size(); SAMICoreProperty update_property; update_property.data = &updateParameter; update_property.dataLen = sizeof(updateParameter); update_property.type = SAMICoreDataType_ResourceParameter; ret = SAMICoreSetProperty(handle,SAMICorePropertyID_Processor_ContextUpdateFromBinaryRes, &update_property); if(ret != SAMI_OK) { cout << "sami_core update data error:" << ret << endl; return 0; }
double seekPosInSec = 2.0; SAMICoreProperty property; property.type = SAMICoreDataType_Double; property.data = &seekPosInSec; property.id = SAMICorePropertyID_Processor_ContextSeek; property.dataLen = sizeof(seekPosInSec); int ret = SAMICoreSetProperty(handle,SAMICorePropertyID_Processor_ContextSeek,&property); if(ret != SAMI_OK) { printfE("SAMICoreSetProperty error"); exit(-1); }
说明:功能不再使用时,需要销毁句柄,释放资源
ret = SAMICoreDestroyHandle(handle); assert(ret == SAMI_OK); handle = nullptr; 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;