#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, ¶m); 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, ¶m);
首先读取模型文件到内存,例子中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);
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);
其中:
SAMICoreGetPropertyById
函数并指定id为SAMICorePropertyID_OverallFeatures
,可获取所有算法计算的结果(注:算法可能输出多种类型的特征)SAMICorePropertyID_FrameFeature_BEAT_TRACKING
的结果释放 handle
ret = SAMICoreDestroyHandle(handle);
此外,还要注意音频数据数据的内存释放(如果有)。例如:
delete[] in_buffer.data;