# 自動化生成音樂譜
> [AUTORHYTHM: A MUSIC GAME WITH AUTOMATIC HIT-TIME GENERATION AND
PERCUSSION IDENTIFICATION](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=7177487)
```graphviz
digraph G {
node [shape = box, style=rounded]
src [label="wav_file", shape = plain]
sep [label="sound separation"]
det [label="onset detection"]
det2 [label="onset detection"]
comb [label="result combination"]
near [label="Nearby onsets removal"]
grouping
result [label="Result\ntime | col_id | difficulty"]
src -> sep -> det -> comb -> near -> grouping -> result
sep -> det2 -> comb
}
```
## sound separation
> [Harmonic–Percussive Separation (HPS)](https://www.audiolabs-erlangen.de/resources/MIR/FMP/C8/C8S1_HPS.html)
> [Numpy 版本教學](https://medium.com/@ongzhixuan/exploring-the-short-time-fourier-transform-analyzing-time-varying-audio-signals-98157d1b9a12)
論文使用 Harmony/Percussive Source Separation (HPSS) 作為分離和諧音以及打擊音的手段
<img src="https://hackmd.io/_uploads/ByDeO9FmR.png" width=500>
音樂可分為和諧音 (harmonic sound) 與打擊音 (percussive)
和諧音聽起來就是和弦,如小提琴的琴聲,頻譜上對應到正弦波 (sinusoid),在聲譜圖 (spectrogram) 上對應的形狀為一橫線
打擊音聽起來有如衝擊般,可以理解為聲樂上的衝擊,聲譜圖上對應形狀為一直線
輸入訊號經過時頻分析 (利用短時距傅立葉轉換,STFT),可以得到一段時間內頻率分布變化圖
所謂的 STFT,其實就是一個函數乘上在固定時間不為零的窗函數 (window function,可用 `np.hamming` 實現),再進行一維的 FFT (可用 `np.fft.rfft` 實現)
現在有了時頻譜,要怎麼分離和諧音跟擊打音呢?
如果使用橫向濾波器,就能得到頻譜多為橫向的和諧音了
為了做到這個,我們使用中位數濾波器 (median filter)
求出過濾後的時頻譜後,我們不會直接使用其結果,而是用橫向直向的時頻譜構造出軟遮罩 (soft mask)
根據求得的橫向訊號成分 $y_h(n,k)$ 以及縱向 $y_p(n,k)$
可以設計以下遮罩:
$$
M_h(n,k)=\frac{y_h(n,k)+\epsilon/2}{y_h(n,k)+y_p(n,k)+\epsilon}
$$
$M_p(n,k)$ 同理,更換分子就行
注意到我們討論到以下參數:
- N: 視窗長度
- H: hop length
- l_p, l_p: filter length
強度頻譜 (magnitude spectrum)
<img src="https://hackmd.io/_uploads/rJYjw8_QC.png" width=300>
根據觀察,不同擊打音效在不同的頻率上,各會有不同的峰值和波形
論文定義「突出音」為具有前 15% 強度的頻率區間
<img src="https://hackmd.io/_uploads/Sk7BF8OXR.png" width=300>
onset detection: spectral-flux-based onset detection
輸出型態: 發生時間 | 欄位的 id | 困難度
偵測到人聲/打擊的發生次數,合併起來就是最終結果
## onset detection
為了減低背景音樂干擾,每一 frame 的強度頻譜都減去了其平均值,所以結果的frame magnitude 總和都是 0
論文中的 threshold 是源於使用者自行輸入的音檔
找出使用者給定的每種音效 (percussion sound) 突出音後,計算每一幀突出音的平均力度規模 (power magnitude)
另外,根據世界紀錄,連續兩個打擊音最小間隔約為 71.4 ms
## channel assignment
> [MFCC intro](https://haythamfayek.com/2016/04/21/speech-processing-for-machine-learning.html)
> [DCT 介紹與應用](https://medium.com/%E9%9B%BB%E8%85%A6%E8%A6%96%E8%A6%BA/%E9%9B%A2%E6%95%A3%E9%A4%98%E5%BC%A6%E8%BD%89%E6%8F%9B-discrete-cosine-transform-dct-%E7%B0%A1%E4%BB%8B-65e426018264)
為了將不同樂器的打擊音分配給不同音軌,對於 MFCC (Mel-frequency cepstral coefficient) 使用 k-means clustering
在過往文獻中, MFCC 被用來做為表示「音色」的特徵
從音訊擷取 MFCC 的過程如下圖,首先經過 FFT 獲取取 log 的功率頻譜 (power spectrum),並經由重新取樣為梅爾刻度 (mel scale) 後,再經由離散餘弦轉換 (discrete cosine transform, DCT,只涉及實部運算)
<img src="https://hackmd.io/_uploads/BkV1m42QC.png" width=500>
於是經由這兩種頻譜上的轉換後,可以得到 「頻譜的頻譜」(spectrum of spectrum)
可以回想自我相關函數 (autocorrelation),其作用為量化自身訊號,和不同時間差相較起來的相似程度。MFCC, 或者說 `DCT(abs(FT))` 與自我相關函數不同的是,前者較不易受基頻 (fundamental frequency) 移除的影響。當帶通濾波器 (bandpass filter) 用以過濾訊號時,就會有些基頻被移除
總的來說,MFCC 用來量化高頻訊號 (high-pass filtered signal) 的自我相似程度
一個前處理技巧是前強化 (pre-emphasis) 藉以加強高頻訊號的強度。通常高頻會比低頻的強度小,也可以改進 SNR,更能避免做 FFT 產生的數值問題
我們在音頻處理會傾向使用梅爾刻度 (Mel-scale) 取代赫茲,是為了模仿人耳非線性接收音頻的特性
$$
m=2595\log_{10}(1+\frac{f}{700})
$$
獲得時頻譜 (spectrogram) 後,會發現其中的濾波器組常數 (filter bank coefficient) 呈現高度相關,因此我們會對其進行離散餘弦轉換 (DCT),得到經壓縮的表示
轉換後的結果就是所謂的 MFCC
最後將 sinusoidal liftering 作用於 MFCC:
$\hat{MFCC_i}=w_iMFCC_i$
$$
w_i=1+\frac{D}{2}\sin(\frac{\pi i}{D})
$$
論文認為,這個濾波函數可以改進噪音之下,聲音辨識的能力。其給予較高常數更小的權重