一、音符檢測的基本原理
本文基于 OpenHarmony 開源系統提供了一種音符檢測的原理方法,結合多首音樂,運用了 python 和 C++ 兩種編程環境實現了預期的檢出效果。旨在為振動馬達(vibrator)提供音樂節奏感的觸覺效果,代碼所在目錄 .basesensorssensorvibration_convert。
先從 python 實現說起,Librosa 關于音符檢測主要用到了兩個函數,一個是 onset_strength(),負責生成包含音符產生的頻率突變的包絡線,如藍色線條所示。另一個是 onset_detect(),主要運用峰點檢測找到每個音符的位置,如黃色線條所示。
圖 1 音符檢測包絡圖
包含有用的頻率突變的包絡線是音符檢測的核心所在。傅里葉變換能夠得到全部信號采樣的頻譜圖,即每個頻率的能量貢獻,如圖 2 所示。但是每個時刻頻譜圖卻得不到,于是將全部采樣分割成若干固定長度的窗口,每個窗口應用傅里葉變化,從而得到這一窗口的頻率分布,水平軸為時間,縱軸為頻率,顏色代表能量大小如圖 3 所示。
圖 2 整體頻率分布圖
圖 3 時頻圖
每種樂器在音符產生時,前后時間片段的頻率將會發生明顯變化,如圖 4 所示。于是將時頻圖相鄰列做差分,將明顯看到變化的頻率。為了便于分析,只取正值,具有相同的效果,所以負值填零。一個時刻變化的頻率有多個,如何取舍,有三種方法,平均數、中位數和聯合,目前常用到的是中位數和平均數。至此,將得到任意時刻發生明顯頻率變化的單一能量,如圖 1 藍色線條所示。
圖 4 時頻圖相鄰列差分前后變化
二、音符檢測的準確性
目前采用頻譜光通量(相鄰列差分)方法檢測是業界公認且較為準確的方法,音符檢出率僅為 70% 多。不準確的原因可能有樂器多且差異較大,信號衰減對性能的影響,顫音影響,峰點檢測時不同參數的影響,這些主要是針對音樂的研究。
三、音符檢測的程序流程
3.1 程序實現
音符檢測功能核心就是頻譜圖和梅爾濾波器,頻譜圖的核心就是短時傅里葉變換,C++ 代碼片段如下,參考鏈接 https://github.com/kooBH/STFT/blob/main/cpp/STFT.h
void STFT::stft(short*in,int length,double**out){ int i,j; /*** Shfit & Copy***/ for (j = 0; j < channels; j++) { for (i = 0; i < ol; i++) { buf[j][i] = buf[j][i + shift_size]; } } // EOF if(length!=shift_size*channels){ length = length/channels; for (i = 0; i < length; i++) { for (j = 0; j < channels; j++) buf[j][i + ol] = (double)(in[i * channels+ j]); } for (i = length; i < shift_size; i++) { for (j = 0; j < channels; j++) buf[j][i + ol] = 0; } //continue }else{ for (i = 0; i < shift_size; i++) { for (j = 0; j < channels; j++){ buf[j][i + ol] = (double)(in[i * channels+ j]); } } } /*** Copy input -?> hann_input buffer ***/ for (i = 0; i < channels; i++) memcpy(out[i], buf[i], sizeof(double) * frame_size); // scaling for precision if(opt_scale) for (i = 0; i < channels; i++) for (j = 0; j < frame_size; j++) out[i][j] /= MATLAB_scale; /*** Window ***/ hw-?>Process(out, channels); /*** FFT ***/ fft->FFT(out); } void STFT::stft(short*in,int length,double**out){ int i,j; /*** Shfit & Copy***/ for (j = 0; j < channels; j++) { for (i = 0; i < ol; i++) { buf[j][i] = buf[j][i + shift_size]; } } // EOF if(length!=shift_size*channels){ length = length/channels; for (i = 0; i < length; i++) { for (j = 0; j < channels; j++) buf[j][i + ol] = (double)(in[i * channels+ j]); } for (i = length; i < shift_size; i++) { for (j = 0; j < channels; j++) buf[j][i + ol] = 0; } //continue }else{ for (i = 0; i < shift_size; i++) { for (j = 0; j < channels; j++){ buf[j][i + ol] = (double)(in[i * channels+ j]); } } } /*** Copy input -?> hann_input buffer ***/ for (i = 0; i < channels; i++) memcpy(out[i], buf[i], sizeof(double) * frame_size); // scaling for precision if(opt_scale) for (i = 0; i < channels; i++) for (j = 0; j < frame_size; j++) out[i][j] /= MATLAB_scale; /*** Window ***/ hw-?>Process(out, channels); /*** FFT ***/ fft->FFT(out); }
Mel 濾波器構造代碼如下:
if fmax is None: fmax = float(sr) / 2 # Initialize the weights n_mels = int(n_mels) weights = np.zeros((n_mels, int(1 + n_fft // 2)), dtype=dtype) # Center freqs of each FFT bin fftfreqs = fft_frequencies(sr=sr, n_fft=n_fft) # 'Center freqs' of mel bands - uniformly spaced between limits mel_f = mel_frequencies(n_mels + 2, fmin=fmin, fmax=fmax, htk=htk) fdiff = np.diff(mel_f) ramps = np.subtract.outer(mel_f, fftfreqs) for i in range(n_mels): # lower and upper slopes for all bins lower = -ramps[i] / fdiff[i] upper = ramps[i + 2] / fdiff[i + 1] # .. then intersect them with each other and zero weights[i] = np.maximum(0, np.minimum(lower, upper)) if norm == "slaney": # Slaney-style mel is scaled to be approx constant energy per channel enorm = 2.0 / (mel_f[2 : n_mels + 2] - mel_f[:n_mels]) weights *= enorm[:, np.newaxis] else: weights = util.normalize(weights, norm=norm, axis=-1) # Only check weights if f_mel[0] is positive if not np.all((mel_f[:-2] == 0) | (weights.max(axis=1) > 0)): # This means we have an empty channel somewhere warnings.warn( "Empty filters detected in mel frequency basis. " "Some channels will produce empty responses. " "Try increasing your sampling rate (and fmax) or " "reducing n_mels.", stacklevel=2, ) return weights
3.2 功能流程圖
為了能讓大家更好的學習鴻蒙 (OpenHarmony) 開發技術,這邊特意整理了《鴻蒙 (OpenHarmony)開發學習手冊》,希望對大家有所幫助:
《鴻蒙(Harmony OS)開發學習手冊》
入門必看:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.應用開發導讀(ArKTS)
2.……
HarmonyOS概念:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.系統定義
2.技術框架
3.技術特性
4.系統安全
快速入門:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.基本概念
2.構建第一個ArkTS應用
3.……
開發基礎知識:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.應用基礎知識
2.配置文件
3.應用數據管理
4.應用安全管理
5.應用隱私保護
6.三方應用調用管控機制
7.資源分類與訪問
8.學習ArkTS
9…
基于ArkTS 開發:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.Ability開發
2.UI開發
3.公共事件與通知
4.窗口管理
5.媒體
6.安全
7.網絡與鏈接
8.電話服務
9.數據管理
10.后臺任務(Background Task)管理
11.設備管理
12.設備使用信息統計
13.DFX
14.國際化開發
15.折疊屏系列
16………
審核編輯 黃宇
-
鴻蒙
+關注
關注
57文章
2339瀏覽量
42816 -
HarmonyOS
+關注
關注
79文章
1973瀏覽量
30145 -
OpenHarmony
+關注
關注
25文章
3713瀏覽量
16256
發布評論請先 登錄
相關推薦
評論