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

【C】预置音效

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

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

完整例子
//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,&param);
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;
使用步骤

一、创建句柄

创建句柄有两种形式

  • 使用文件系统(win平台使用下文二进制方式)
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,&param);
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, &param);
if (ret != SAMI_OK) {
    cout << "sami_core handler create fail " << ret << endl;
    return 0;
}

二、Prepare

说明:在使用功能之前,需要进行一系列准备工作,需要输入音频采样率和 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);

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

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用于原声的切换

  • 文件形式(win平台使用下文字节流形式)
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;
}

六、Seek操作

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;