You need to enable JavaScript to run this app.
导航
【C】非流式节拍检测
最近更新时间:2023.03.16 11:40:14首次发布时间:2023.03.16 11:40:14
完整例子
#include "sami_core.h"

// help function
std::vector<uint8_t> loadModelAsBinary(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 {};
}

SAMICoreFeatureArray* findWantedFeature(SAMICoreFeatureSet* f_set, SAMICorePropertyId feature_id) {
    for(int i = 0; i < f_set->numFeatureTypes; ++i) {
        if(f_set->set[i].featureID == feature_id) { return &(f_set->set[i]); }
    }
    return NULL;
}

// step 1, create handle
SAMICoreHandle handle;
SAMICoreExtractorCreateParam param;
param.sampleRate = sample_rate;
param.numChannel = num_channels;

int ret = SAMICoreCreateHandleByIdentify(&handle, 
            SAMICoreIdentify_Extractor_BeatTrackingOffline, &param);
assert(ret == SAMI_OK);

// step 2, loading model
const std::string model_path = "/path/to/beat_tracking_offline.model";
std::vector<uint_8> model_buf = loadModelAsBinary(model_path);
assert(model_buf.size() > 0);

SAMICoreProperty coreProperty;
coreProperty.id = SAMICorePropertyId_LoadModelBinary;
coreProperty.data = model_data.data();
coreProperty.dataLen = model_data.size();
coreProperty.type = SAMICoreDataType_ModelBin;
ret = SAMICoreSetProperty(handle, SAMICorePropertyId_LoadModelBinary, &coreProperty);
assert(ret == SAMI_OK);

// step 3, create input  audio block
SAMICoreAudioBuffer in_audio_buffer;
in_audio_buffer.numberChannels = num_channels;
in_audio_buffer.numberSamples = 0;
in_audio_buffer.isInterleave = 0;
in_audio_buffer.data = new float*[num_channels];

SAMICoreBlock in_block;
in_block.dataType = SAMICoreDataType_AudioBuffer;
in_block.numberAudioData = 1;
in_block.audioData = &in_audio_buffer;

// step 4, process all data at once
in_audio_buffer.numSamples = total_num_samples;
in_audio_buffer.data[0] = audio_data;
ret = SAMICoreProcess(handle, &in_block, NULL);
assert(ret == SAMI_OK);

// step 4.1 get beat tracking results
SAMICoreProperty overall_features;
SAMICoreGetPropertyById(handle, 
                        SAMICorePropertyID_OverallFeatures, 
                        &overall_features);
SAMICoreFeatureSet* feature_set = (SAMICoreFeatureSet*)(overall_features.data);
if(feature_set != NULL) 
{
    SAMICoreFeatureArray* bt_results =findWantedFeature(feature_set, 
                SAMICorePropertyID_OverallFeature_TRACKING_OFFLINE_OVERALL);

    if(bt_results != NULL) 
    {
        for(size_t i = 0; i < bt_results->numFeatures; ++i) 
        {
            float timestamp = bt_results->array[i].time;
            float beat = bt_results->array[i].values[0];

            cout << "time at " << timestamp << ", got beat " << beat << endl;
        }
    }
}
SAMICoreDestroyProperty(&overall_features);

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

delete[] in_buffer.data;
使用步骤

一、创建算法句柄

传入采样率和声道数,通过 SAMICoreCreateHandleByIdentify 创建 handle。

SAMICoreHandle handle;
SAMICoreExtractorCreateParam param;
param.sampleRate = sample_rate;
param.numChannel = num_channels;

int ret = SAMICoreCreateHandleByIdentify(
        &handle, 
        SAMICoreIdentify_Extractor_BeatTrackingOffline, 
        &param);

二、导入模型

首先读取模型文件到内存,例子中loadModelAsBinary仅供参考;接着,设置模型的信息,并通过
SAMICoreSetProperty导入模型

SAMICoreProperty coreProperty;
coreProperty.id = SAMICorePropertyId_LoadModelBinary;
coreProperty.data = model_data.data();
coreProperty.dataLen = model_data.size();
coreProperty.type = SAMICoreDataType_ModelBin;
ret = SAMICoreSetProperty(
        handle, 
        SAMICorePropertyId_LoadModelBinary, 
        &coreProperty);

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

SAMICoreAudioBuffer,用于存放音频数据;SAMICoreBlock,用于存放需要处理的数据。需要注意的是,
beat tracking 只处理单声道数据。

SAMICoreAudioBuffer in_buffer;
in_buffer.isInterleave = 0;
in_buffer.numberSamples = 0;
in_buffer.numberChannels = 1;
in_buffer.data = new float*[1];

SAMICoreBlock in_block;
in_block.dataType = SAMICoreDataType_AudioBuffer;
in_block.numberAudioData = 1;
in_block.audioData = &in_buffer;

四、处理音频,并获取结果

一次性处理整个音频数据,更新音频数据指针和音频长度,通过 SAMICoreProcess 进行处理

in_audio_buffer.numSamples = total_num_samples;
in_audio_buffer.data[0] = audio_data;

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

与流式 beat tracking 不同,非流式一次获取所有节奏信息:

SAMICoreProperty overall_features;
SAMICoreGetPropertyById(handle, 
                        SAMICorePropertyID_OverallFeatures, 
                        &overall_features);
SAMICoreFeatureSet* feature_set = (SAMICoreFeatureSet*)(overall_features.data);
if(feature_set != NULL) 
{
    SAMICoreFeatureArray* bt_results =findWantedFeature(feature_set, 
                SAMICorePropertyID_OverallFeature_TRACKING_OFFLINE_OVERALL);

    if(bt_results != NULL) 
    {
        for(size_t i = 0; i < bt_results->numFeatures; ++i) 
        {
            float timestamp = bt_results->array[i].time;
            float beat = bt_results->array[i].values[0];

            cout << "time at " << timestamp << ", got beat " << beat << endl;
        }
    }
}
SAMICoreDestroyProperty(&overall_features);

其中:

  • 2行,通过SAMICoreGetPropertyById 函数并指定id为SAMICorePropertyID_OverallFeatures,可获取所有算法计算的结果(注:算法可能输出多种类型的特征)
  • 8 ~ 9 行,通过findWantedFeature 辅助函数找到特征id为SAMICorePropertyID_FrameFeature_BEAT_TRACKING的结果
  • 11~20行,遍历结果,获取 beat 的时间戳信息,和节奏信息
  • 22 行,记得调用 SAMICoreDestroyProperty 来释放资源

五、释放资源

释放 handle

ret = SAMICoreDestroyHandle(handle);

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

delete[] in_buffer.data;