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 nullptr; } // step 1, create handle const int sample_rate = 48000 ; const int num_channels = 2; SAMICoreHandle handle; SAMICoreExtractorCreateParam param; param.sampleRate = sample_rate; param.numChannel = num_channels; int ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify::SAMICoreIdentify_Extractor_Loudness, &createParameter); // step 2, create input 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; for(int c = 0; c < int(num_channels); ++c){ in_audio_buffer.data[c] = new float[block_size]; } SAMICoreBlock in_block; in_block.dataType = SAMICoreDataType::SAMICoreDataType_AudioBuffer; in_block.numberAudioData = 1; in_block.audioData = &in_audio_buffer; // step 3, process block by block for(;hasAudioSamples();) { copySamplesToInputBuffer(in_audio_buffer); int ret = SAMICoreProcess(handle, &in_block, NULL); assert(ret == SAMI_OK); //step 4,get SHORTTERM_LOUDNESS SAMICoreProperty frame_features; SAMICoreGetPropertyById(handle, SAMICorePropertyID_FrameFeatures, &frame_features); auto frame_feature_set = (SAMICoreFeatureSet*)(frame_features.data); { SAMICoreFeatureArray* feature = findWantedFeature(frame_feature_set, SAMICorePropertyID_FrameFeature_SHORTTERM_LOUDNESS); if(feature != nullptr) { auto time = feature->array[0].time; for(auto i = 0u; i < feature->array[0].numValues; ++i) { cout << "SHORTTERM_LOUDNESS:" << " time:" << time << " values:" << feature->array[0].values[i] << endl; } } } { SAMICoreFeatureArray* feature = findWantedFeature(frame_feature_set, SAMICorePropertyID_FrameFeature_MOMENTARY_LOUDNESS); if(feature != nullptr) { auto time = feature->array[0].time; for(auto i = 0u; i < feature->array[0].numValues; ++i) { cout << "MOMENTARY_LOUDNESS:" << " time:" << time << " values:" << feature->array[0].values[i] << endl; } } } SAMICoreDestroyProperty(&frame_features); } // step 5, get source global loudness and peak SAMICoreProperty overall_features; SAMICoreGetPropertyById(handle, SAMICorePropertyID_OverallFeatures, &overall_features); SAMICoreFeatureSet* feature_set = (SAMICoreFeatureSet*)(overall_features.data); if(feature_set != NULL) { SAMICoreFeatureArray* loudness_results =findWantedFeature(feature_set, SAMICorePropertyID_OverallFeature_GLOBAL_LOUDNESS); if(loudness_results != NULL){ for(size_t i = 0; i < loudness_results->numFeatures; ++i) { float source_lufs = loudness_results->array[i].values[0]; cout << "source_lufs:" << source_lufs << endl; } } SAMICoreFeatureArray* peak_results =findWantedFeature(feature_set, SAMICorePropertyID_OverallFeature_GLOBAL_PEAK); if(peak_results != NULL){ for(size_t i = 0; i < peak_results->numFeatures; ++i) { float peak = peak_results->array[i].values[0]; cout << "peak:" << peak << endl; } } } SAMICoreDestroyProperty(&overall_features); // step 5, release resource ret = SAMICoreDestroyHandle(handle); assert(ret == SAMI_OK); for(int c = 0; c < int(num_channels); ++c){ delete [] in_audio_buffer.data[c]; } delete [] in_audio_buffer.data;
传入采样率、声道数和 maxBlockSize(每次处理的最大采样点),通过 创建 handle。
const int sample_rate = 48000 ; const int num_channels = 2; SAMICoreHandle handle; SAMICoreExtractorCreateParam param; param.sampleRate = sample_rate; param.numChannel = num_channels; int ret = SAMICoreCreateHandleByIdentify(&handle, SAMICoreIdentify::SAMICoreIdentify_Extractor_Loudness, &createParameter);
SAMICoreAudioBuffer,用于存放音频数据。
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; for(int c = 0; c < int(num_channels); ++c){ in_audio_buffer.data[c] = new float[block_size]; } SAMICoreBlock in_block; in_block.dataType = SAMICoreDataType::SAMICoreDataType_AudioBuffer; in_block.numberAudioData = 1; in_block.audioData = &in_audio_buffer;
将待处理的音频数据拷贝到 in_audio_buffer
中,再经 SAMICoreProcess
处理
for(;hasAudioSamples();) { copySamplesToInputBuffer(in_audio_buffer); int ret = SAMICoreProcess(handle, &in_block, NULL); assert(ret == SAMI_OK); }
更新音频数据的指针,指向正确的内存即可,这样可以避免内存数据的拷贝。
for(;hasAudioSamples();) { updateInpuBuffer(in_audio_buffer); int ret = SAMICoreProcess(handle, &in_block, NULL); assert(ret == SAMI_OK); }
SHORTTERM_LOUDNESS 是获取最近3s的响度
MOMENTARY_LOUDNESS 是获取最近400ms的响度
SAMICoreProperty frame_features; SAMICoreGetPropertyById(handle, SAMICorePropertyID_FrameFeatures, &frame_features); auto frame_feature_set = (SAMICoreFeatureSet*)(frame_features.data); { SAMICoreFeatureArray* feature = findWantedFeature(frame_feature_set, SAMICorePropertyID_FrameFeature_SHORTTERM_LOUDNESS); if(feature != nullptr) { auto time = feature->array[0].time; for(auto i = 0u; i < feature->array[0].numValues; ++i) { cout << "SHORTTERM_LOUDNESS:" << " time:" << time << " values:" << feature->array[0].values[i] << endl; } } } { SAMICoreFeatureArray* feature = findWantedFeature(frame_feature_set, SAMICorePropertyID_FrameFeature_MOMENTARY_LOUDNESS); if(feature != nullptr) { auto time = feature->array[0].time; for(auto i = 0u; i < feature->array[0].numValues; ++i) { cout << "MOMENTARY_LOUDNESS:" << " time:" << time << " values:" << feature->array[0].values[i] << endl; } } } SAMICoreDestroyProperty(&frame_features);
待处理完整个音频,通过 SAMICoreGetPropertyById
获取整体响度和峰值
SAMICoreProperty overall_features; SAMICoreGetPropertyById(handle, SAMICorePropertyID_OverallFeatures, &overall_features); SAMICoreFeatureSet* feature_set = (SAMICoreFeatureSet*)(overall_features.data); if(feature_set != NULL) { SAMICoreFeatureArray* loudness_results =findWantedFeature(feature_set, SAMICorePropertyID_OverallFeature_GLOBAL_LOUDNESS); if(loudness_results != NULL){ for(size_t i = 0; i < loudness_results->numFeatures; ++i) { float source_lufs = loudness_results->array[i].values[0]; cout << "source_lufs:" << source_lufs << endl; } } SAMICoreFeatureArray* peak_results =findWantedFeature(feature_set, SAMICorePropertyID_OverallFeature_GLOBAL_PEAK); if(peak_results != NULL){ for(size_t i = 0; i < peak_results->numFeatures; ++i) { float source_peak = peak_results->array[i].values[0]; cout << "source_peak:" << source_peak << endl; } } } SAMICoreDestroyProperty(&overall_features);
ret = SAMICoreDestroyHandle(handle);
此外,还要注意音频数据数据的内存释放(如果有)。例如:
for(int c = 0; c < int(num_channels); ++c){ delete [] in_audio_buffer.data[c]; } delete [] in_audio_buffer.data;