2009年6月2日 星期二

Partial Tracking - centcent

20081118
主要是訂正 F0 frequency的精準度。
我們所得到的trajectory主要是由 F0 candidate 所產生出來的。

從Ircam的資料,我們可以明確的得知說每個frame 的 F0 candidate 是否有包含 Estimated F0。
可是從義崧的程式,只能得到上述兩個的Frequency,所以當初這部分的判斷和維城是用討論之後是用FFT bin來判斷。

不過因為義崧程式得到的 Estimated F0 的 bin 是經過權重之後的結果,會有小數,因此將這個bin 四捨五入之後在和F0 candidate的bin 做判斷,因此會有誤差存在。所以才會造成一直線的狀況發生

因為Estimated F0 的 bin經過四捨五入之後為20,包含於F0 candidate的bin,如下圖




解決辦法,如果一個frame的F0 candidate有包含 Estimated F0,這時就將F0 candidate其中的 frequency改成有包含Estimated F0的bin frequency。



投影片

comments:
1. 原先的 pruning 是判斷有無 estimated F0來移除 trajectory。
2. 如果我們沒有estimated F0的資訊,只有F0 candidate,想方法來判斷是否為 partial,移除掉其他非partial的部分,最後再利用找出來的partial來找出F0。
------------------------------------------------------------------------------------
20081125
這星期主要做的就是看能不能從義崧的程式找出更多的 candidate 出來。
改變設定上下限的變數即可找出多一點的 candidate ,不過低頻的地方看起來有很多非真正 candidate 的點。


另外發現如果有太多的 candidate,pruning 這動作好像無法找出真正的F0出來,這部分還要再仔細去看數據才知道哪裡出問題。

投影片

comments:
1. 會造成低頻有這麼多假的node,應該是因為是取最大公因數。要濾掉這些node,除了考慮這些點的weight之外,在去看看這些node有沒有能量存在
2. 如果F0沒有能量,這種例外的狀況,再想辦法來解決

------------------------------------------------------------------------------------
20081202
發現之前用當作 F0 candidate的資料是我找錯了,我找成義崧用來投票的,所以結果就不這麼好看。這次的結果看起來比較正常了。



是否可以試著透過義崧的演算法將已經找到的 partial 的資訊移除,然後再找另一個partial?
partial是經由投票所產生的,而每個bin都有提供各自的 weight,若將每個bin提供的weight記錄下來,每找完一個partial,每個bin就減掉之前提供的weight,再用來找下一個partial

投影片

comments:
1. 增加一些參數給HMM,例如能量以及partial之間的相關性
2. inharmonicity 的狀況:或許不一定要看基頻,而可以只看前一個或二個的partial
------------------------------------------------------------------------------------
20081209
1. 上週提到「是否可以試著透過義崧的演算法將已經找到的 partial 的資訊移除,然後再找另一個partial?」這部分實做的時候移除weight後沒有重算bin的能量。
2. 找到一篇paper提到說freq 和 amp 在顫音的時候,freq 上升,amp會下降。paper中提出可以把 d^2 = [(fi - fj)(ai-aj)]^2 當成 HMM 中transition Prob的參數。

投影片
paper

comments:
1. paper 的假設是錯的,如果整個音源來看是對的,可是如果看單一partial的話,並不是絕對。
------------------------------------------------------------------------------------
20081210
1. 找鋼琴inharmonicity 的曲線,直接套用此曲線即可。
2. 斷掉的partial相連,試著找出一組公式,放進去HMM裡當參數。或者用公式來 implement
3. 由義崧的演算法,找出F0之後,再找F0的倍頻,看看倍頻附近是否有peak存在(能量大的),這個peak則為F0的partial。找出一個F0以及其partial,將這些移除,再找下一組F0和partial。若有鋼琴存在,則套用[1]的曲線公式。
---------------------------------------------------------------------------------
20081216
1. 義崧學長有針對bin下去做平滑化,當初是避免有小突起的peak,不過這樣會造成multiple f0差三根bin會找不到,所以把這部分移除掉。
2. 根據20081210,找出F0之後,再找F0的倍頻,看看倍頻附近是否有peak存在(能量大的),這個peak則為F0的partial,這邊判斷方式用12平均率,f0的倍數上下半個半音是否有能量存在,大約是上下3%。
3. 上面那個判斷方式,在高頻部分,有可能會包含許多bin進來,因此,將最接近f0*multiple的peak視為f0的partial

投影片
----------------------------------------------------------------------------------
20081223
1. 這次完成找出multiple f0了,針對小提琴和長笛下去做處理,找partial的判斷方式為
f0 * mutiple * 0.97 <= peak <= f0 * mutiple * 1.03
找出的結果如下圖

2. piano inharmonicity:根據[H. Fletcher, E. D. Blackham, and R. Stratton, 「Quality of piano tones,」 J. Acoust. Soc. Am., vol. 34, no. 6, pp. 749–761, 1962.]這篇論文,鋼琴的partial 頻率和鋼琴每根弦的直徑、長度、張力、材質有關。

投影片

comments:
1. 判斷partial的範圍:若要找第N個partial,f(N):
(△f + f(N-1)) * 0.97 <= peak <= (△f + f(N-1)) * 1.03
△f = f(N-1) - f(N-2)
------------------------------------------------------------------------------------
20081225
1. 12月23號那張圖的第一段音樂,F0有260HZ和330HZ,可是找出來的結果330HZ沒有找到,這和我們設定上下3%其實沒有關連,會造成這樣的結果是因為義崧的程式有一段是針對二胡的特性來寫的,二胡的最高能量不一定落在f0,可能落在2或3倍頻,因此用這段程式碼來找出F0。將這部分拿掉就可以找到260HZ和330HZ了。
2. 將原本找partial的判斷式改為
(△f + f(N-1)) * 0.97 <= peak <= (△f + f(N-1)) * 1.03
△f = f(N-1) - f(N-2)
結果如下圖:

這邊發現一個問題:原訊號如果兩個partial相當接近,而一個partial 能量遠大於另一個partial,能量較小的那個partial會無法找到。以這張圖為例,F0為260和330,在990和1040附近應該都要有partial,可是990的能量遠大於1040,就無法找到1040這個partial。
我想這是因為一開始要將有peak的bin考慮進來的時候,包含1040HZ的這根bin並沒有特別突出,這根bin就沒有被考慮進來了。
------------------------------------------------------------------------------------
20081230
偷懶了一下,這麼晚才更新
1. 如果兩個音只差一個半音,只能找到一個F0,而且這個F0會落在兩個音頻率的中間。例如Violin:260Hz & Flute:277Hz,找出來的結果大約是269Hz,因此這269Hz的partial都沒有能量也就沒有找到。


投影片

comments:
1. 關於12/25提到的partial能量不夠大,DNA提到可以做類似將高頻的能量平方的動作,或許可以使peak更為明顯。
2. 12/25的結果,高頻部分有些partial斷掉,在HMM中加入是否為partial的condition。
-----------------------------------------------------------------------------------
20090106
comments:
1. 關於F0s差半個音無法辨別出來,可以針對低頻部分提高解析度來做
2. 高頻部分,可以利用影像處理的前處理方式,做一個operator來處理,來辨別出我們所要的資訊
-----------------------------------------------------------------------------------
20090209
1. 之前關於低頻F0s差一個半音無法辨別出來,這段期間有做一些提高解析度(zero padding)以及一些作法來實驗。
a. 經過 lowpass filter
b. 經過 lowpass filter 再做 zero padding
c. 認為高頻有太多的candidate影響投票,所以只拿一半的 candidate 來投票
d. 只拿1.2K以下的candidate來投票
發現都無法找出兩個F0(260Hz、277Hz)。
後來發現原來是義崧學長在找candidate的時候,會根據一個peak的前後兩根 bin 找最大個一根來當作candidate,在samplerate=44100,framesize=8192時,260Hz和277Hz大概差3~4根bin,所以在這個地方就只會把其中一個拉進去當candidate。所以沒有這兩個candidate。
2. 將這地方拿掉之後就可以正確的找到260Hz和277Hz了,只是高頻部分(2.5kHz以上)有點糟糕。

3. spectrum要幾次方以及protrudeValue的threshold會影響 260Hz&277Hz 和 260Hz&330Hz 的結果,第一個結果不錯,第二個就有點糟,這地方還要多測試。
------------------------------------------------------------------------------------
20090212
1. 多設定一個noise floor,將原本的spectrum扣掉這條 noise floor再去做後面的動作。noise floor的做法為往前往後看L點,取平均
s[i] = Σ x[i-k] / (2L+1) , k = -L ~ L
x:原本spectrum
這樣做可以避免若基頻落在高頻的時候,低頻一些peak會影響結果,導致找出來的F0落在低頻。
2. 原本義崧學長程式中protrudeValue表示的是 (magnitude of a peak) / (magnitude of the higher foot),這邊我改成用斜率表示。
260 & 277Hz

260 & 330Hz

1046 & 1108Hz

-----------------------------------------------------------------------------------
20090217
1. 修正bug:原本 F0 * 0.97 < F0 < F0 * 1.03,沒有處理在這個範圍內有兩個以上的bin。新增要找最接近的bin。
2. 在找 candidate 時,新增一個threshold:比最大能量小 48db(約1 / 256)的bin 不考慮進來。針對單純沒有變音的就抓的比較漂亮了。
1046 & 1108 Hz

3. 找了巴哈無伴奏的一段音樂來跑,有六段不同基頻(小明聽出來的),分別是
a. 0 - 1 sec : 830 Hz
b. 1 - 2 sec : 260 Hz & 493 Hz
c. 2 - 2.5 sec : 440 Hz
d. 2.5 - 3 sec : 554 Hz
e. 3 - 3.5 sec : 698 Hz
f. 3.5 ~ sec : 830 Hz
原始的圖如下:

找到的F0:在應該只有單音的地方找到多個F0,應該是換音所造成的,畢竟從能量上來看,這些frequency 以及其倍頻都還有能量存在。

F0 以及 Partial:

----------------------------------------------------------------------------------
20090223
1. 老師提出的對每一根有可能是f0的bin,將五倍以內的bin都取出來投票,若有得到F0以及其
partial,則下一輪投票就不要將這些考慮進來。只是這樣結果好像沒有比較好,跟上次的比較起來,F0少了一點。

2. 用midi產生DoMeSo,結尾加上 reverb,再加上ReFaLa。
Wav:

F0:在有重疊到的地方,找的還不錯

------------------------------------------------------------------------------------
20090225
1. 20090223提到的第一點,做出來效果不好是因為我程式少寫一些判斷式,所以少找了許多F0出來。下面是更改過後的結果。
做法是每個candidate都假設可能是F0,依照這根bin往上看5倍。

是有比原本的結果比較好,可是相對的高頻也多出了許多fake的F0,這是因為每個candidate都預先認為可能是F0,高頻部分有些剛好不是先前找到F0的partial,所以再往上看5倍,也有可能會認為當下的這根bin是F0。
2. 如果要用這種辦法,好像無法避免這種狀況。因此在這邊多加了一個threshold,當一個candidate的能量大於最大能量的1/8(約18db),才認為這個candidate可能是F0,再下去投票。
結果如下:高頻部分少了許多fake的F0。

3. 拿真正鋼琴的聲音來做測試
wave:

F0:當一個新的音起來,舊的音還有餘音的時候,而新的音剛好是舊餘音的倍數時,這時候就有可能把F0找成舊的音。

-----------------------------------------------------------------------------------
20090226
上面鋼琴曲的樂譜,原來有這麼複雜, Ballade No. 1 Op. 23,應該是蕭邦的吧

-----------------------------------------------------------------------------------
20090304
1. 我們為瞭解決低頻能正確找到F0,所以FFT的size增加到8192,但是,相對的原音在Vibrato時,會碎成許多小peak(如下圖),所以會找到許多相近的F0。

2. 解決辦法:在一個半音內(94% ~ 106%)只會存在一個F0,因此試著用在這範圍內,找出能量最大的來當作F0。跟20090225的巴哈比起來,第一段有抖音的部分,已經沒有非常接近的F0了。

3. 解決完這問題之後才突然發現,這問題其實可以靠HMM來解決,因為我們HMM要多加入partial和 amplitude 這兩個參數進去。到時候將HMM建構起來之後在和上面提到的方法來做比較。
-----------------------------------------------------------------------------------
20090310
1. 原本定義下列狀況下,candidate不相連。cCandidate:current candidate,rCandidate:往前看的 candidate
(cCandidate is F0) && (rCandidate is Partial)
(cCandidate is Partial) && (rCandidate is F0)
(cCandidate's F0 和 rCandidate's F0 差超過一個半音)
(cCandidate's Freq 和 rCandidate's Freq差超過一個半音)
老師建議將 candidate 的 Frequency 和 magnitude 都放進去 HMM 的 HiddenStateProb 裡。這樣可以讓 model 更加完美,讓人信服。
2. 維城學長是利用 Gaussian function ,△f當變數來算 prob,我們可以利用2維的Gaussian function,△f 和 △magnitude來當變數。function如下



3. 在前端部分,也就是f0 detection 部分,在找partial的部分加入一些 virtual node,可以讓後面的 HMM 的加以參考。要增加 virtual node的條件先假設 F0 往上看10倍,若real node比例達80%以上,再增加 virtual node。virtual node的magnitude為0。
4. 因為有這些 virtual node,magnitude 為0,所以 HMM 那邊多一個只有 △f 的 Gaussian function 給 virtual node 用。
-----------------------------------------------------------------------------------
20090312
1. 用不同的 Gaussian function 來處理node 之間的連線,會有問題,因此還是只用一個Gaussian function,只是virtual node的magnitude,直接用FFT的能量即可。

2. 原本討論要用 α*Decay + β* HiddenProb + (1 - α - β) * PartialFunc,這邊PartialFunc是考慮 Partial 的關係。原本HMM的連線方式是node 對 node,我們可以改成 整組對整組,也就是F0以及其partial視為一組下去做HMM。
-----------------------------------------------------------------------------------
20090318
1. 現在的作法是 α*Decay + (1 - α)* HiddenProb,HiddenProb是用二維的Gaussian function,△f 和 △magnitude來當變數,整組(F0+partials)下去算的。
結果如下:
小提琴 DoMeSo+ReFaLa:

巴哈無伴奏:

2. 接下來就是建立前後兩部分(f0 detect、HMM)的LOOP以及tune HMM 的參數(σ和α)。
-----------------------------------------------------------------------------------
20090325
1. 要training Gaussian function的參數,打算利用八度音來區隔,大略分成6個區段
100 ~ 261 Hz (C4)
261 ~ 523 Hz (C5)
523 ~ 1046 Hz (C6)
1046 ~ 2093 Hz (C7)
2093 ~ 4186 Hz (C8)
4186 ~ 8000 Hz
2. 用midi產生的wav來train這些參數(σ1,σ2,Cov),儘量有Vibrato和滑音。
-----------------------------------------------------------------------------------
20090408
1. 六個區域的參數已經train出來了。
只用一組參數的Bach

六組參數

變化好像不大
2. 皆下來的工作 a.建立loop b.train出attack state的initial weight c.擬出論文大綱
----------------------------------------------------------------------------------
20090421
20090421
1. 原本Loop的動作是
  • 找出f0
  • Tracking
  • Smooth
  • interpolated
  • 利用出來的結果回頭找F0

2. 不過因為smooth的動作經過多次loop之後會讓vibrato趨於平緩,因此這邊改用linear prediction的方式來校正node
  • 找出f0
  • Tracking
  • linear presiction
  • interpolated
  • 利用出來的結果回頭找F0

----------------------------------------------------------------------------------
20090506
1. vibrato 部分顯示出來會像是鋸齒波,而不是sin波,如下圖。

這是因為我們找出來的F0的曲線就是類似這樣子的。

2. 如果我們看f0那張圖在vibrato的時候,有時候在同一個frame會找到兩個點,這是因為在原本的頻譜圖上就有兩個peak存在了,這應該是頻率解析度造成的問題。

3. 既然我們知道它是vibrato了,那我們可以記錄它震盪的大小,經過多次smooth之後,會趨近於sin波,這時候我們再將它放大到原本震盪的大小。
4. 也可以用分bank的方式,低頻用高解析度,高頻用低解析度。
-----------------------------------------------------------------------------------
20090512
1. 記錄vibrato震盪的幅度,最後再修正到原本的位置。我是先用古琴來測試,第一張圖是一開始找到的F0,第二張是經過多次smooth之後的,第三張是是修正到原本的位置。
原本的F0,請忽略那幾條直線,畫線出問題

多次smooth之後

修正至原本位置

2. 用在Bach上,還有些問題,正在找出問題所在,應該是條件設定要調整。
----------------------------------------------------------------------------
20090602
1. 打算加入之前20090225我們討論過的,只往上看五倍下去投票,這樣子的結果比較漂亮。
下圖是沒有加入新的方法。

下圖是加入新的方法,可以看出換音的地方原本的音延長了許多。