====20081118====
這週的進度式開始實做上週所報告的Paper
依照上週所報告的Paper
Input為wav file
資料庫端為midi file
而雙方都需要轉成Chroma Vector
再以時間為index去做DTW比對
而資料庫端的midi file照paper所說
也可以先轉成wav檔再轉成Chroma Vector
所以下週就可以先跑一些結果出來了
這是一部分Chroma Vector的結果
左邊為12個Chroma Bin
顏色的深淺代表能量高低 越淺代表能量越高
====20081125====
繼上週所做的事情
就把剩下的程式給寫完了
並且做了一些實驗
PPT File
====20081202====
這週跑了多個版本的命運交響曲的實驗
以及想了一個計算Chroma Vector距離所可能會發生的問題
PPT File
備註:
1. 要開始做對樂譜和onset detection的部分
2. 也許可以用HMM從Chroma Vector找出音的多條路徑,再拿這些路徑的變化量去做DTW(用以解決key shift的問題)
====20081209====
這週我報告了一篇ISMIR2007的Paper
Paper內容是在說將掃描進電腦的樂譜(圖檔)和音樂錄音(wav,mp3)做Synchronization
也就是對譜的動作
而他使用的方法則是用我之前所報告的Chroma Feature來做比對
在此,我更正一下
我在報告Paper中有提到一點
關於一開始的音高記號如果OMR辨識錯誤的話
我當時說:"Paper說還是可以對的上"
抱歉,這一點是我在報告時講錯了
是我記錯了
Paper並沒有對於這一點有特別的說明
只有說那些local的臨時記號就算多錯幾個還是對的上
PPT File
====20081223====
這週的進度是把老師上週要我做的事情
回去想了程式流程圖
並完成了一部分的程式
以下是程式的流程圖:
MIDI:
經由MIDI parser處理之後
得到event
再經過處理
將其轉成以tick為時間單位的資料
再轉成chroma feature
WAV:
做完FFT之後
直接轉成chroma vector
接下來要將時間單位統一
由tick合併(透過MIDI的tempo可以換算成時間)
接下來分段做DTW比對
由比對的結果即可知道MIDI的onset的位置是對到WAV的哪個位置
而對到的這個位置 就是WAV的onset的位置
再經由這個位置 可以寫回MIDI File
另外老師上週有問我一個問題
褐色的部分是midi的部分 三個音時同時發聲
而紅色是真正的情況(wav) 時間點上可能會有一點點誤差
而做過DTW之後 褐色onset的位置 只會對到一個紅色的位置
而藍色的地方就是拿對到的onset的位置調整後的結果
如果需要三個音找到更正確的onset位置
則需要拿對到的onset附近的幾個frame下去做分析
目前進度:
由於程式需要midi的一些資訊以及最後又要寫回midi file
為了讓我對midi format以及順便了解舊的midi parser原本的問題在哪邊
所以我就用C#重寫了一個midi parser
也順利的找到了原本midi parser的問題所在
再順利的把event取出來之後
順利的把它拆成以tick為時間單位的資料
====20081230====
紫色字的部分是我上週的進度
紅色字的部分是我這週的進度
藍色字的部分是我未完成的進度
而這週有做了一個實驗
先去看MIDI的Chroma和MIDI合成Wav的Chroma有沒有可能對的起來
必須要先對的起來
這樣MIDI的Chroma才有可能和實際演奏的Wav對的起來
而在某些樂器中的Chroma會長的有點奇怪
有可能是FFT Size太小 則可能會被分在同一個Bin,
也有可能是FFT Size夠大,但因為泛音的頻率偏掉太多,造成離另一個音比較接近
可能的解決方法有:
1.增大FFT Size 但Hop Size不變
2.改用小波轉換
3.先經過一個Low Pass Filter 再轉Chroma
而在投影片最後 有兩張圖
分別為MIDI轉Chroma 以及 實際演奏轉Chroma 的圖
另外我有想了一個解決key shift的方法
過幾天我會整理補上
====想法====
這個想法是用來解決Key Shift的問題
想法:
去記錄音高變化的趨勢,從Chroma Feature再去做一次轉換。
首先,會有一個Base Semitone,這個Base Semitone為多少是由上一個Frame的Chroma Vector來決定,而目前Frame的Chroma Vector會依照這個Base Semitone來做位移(Shift)的動作,所以如何決定Base Semitone將會影響到呈現出來的結果。我想了很久,我覺得可以設一個Threshold,如果能量大於或等於這一個Threshold的Semitone且這個Semitone是目前Base Semitone加N個Semitone而N為最小且N>=0,就當作是新的Base Semitone。
而位移(Shift)的動作就是將Semitone – Base Semitone,值如果為負值就再加上12,看值為多少,就將其Semitone的能量移至此位置;也就是說,如果原本的Chroma Vector為[0,0,1,0,0,0,0,0,0,0,0,0],若Base Semitone為1,則轉換的結果為[0,1,0,0,0,0,0,0,0,0,0,0],而位移後的結果,可以視為目前Frame和上一個Frame的音高變化是原本的音高再提高一個半音,由此也可以推測出上一個Frame的Chroma Vector有可能是長這樣:[0,1,0,0,0,0,0,0,0,0,0,0]。
以下我將舉個例子來說明,原本的Chroma Vectors如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 | 0 | 0 | 0.6 | 0.6 | 0.8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
3 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0.8 | 0.8 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 | 1 | 0.7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
縱軸代表12個半音,橫軸代表時間(Frame Number),而每一個值代表能量(音量),假設Threshold = 0.6,值為0的位置可以視為原本就沒有能量或者是能量小於0.6。
接下來將一步步的將每一個Chroma Vector做轉換,以下的編號可以視為處理第n個Frame的過程。
0.在一開始,因為還未決定Base Semitone,所以要先決定Base Semitone,找最接近第0個半音且能量有超過Throshold的半音當作Base Semitone,在這個例子中Base Semitone為3,而轉後過後的Chroma Vector為[1,0,0,0,0,0,0,0,0,0,0,0]。
1. 此時Base Semitone為3,原本的Chroma Vector為[0,0,0,1,0,0,0,0,0,0,0,0]經過轉換的結果為[1,0,0,0,0,0,0,0,0,0,0,0],再重新決定Base Semitone為3。
2. 此時Base Semitone為3,原本的Chroma Vector為[0,1,0,0,0,0.6,0,0,0,0,0,0]經過轉換的結果為[0,0,0.6,0,0,0,0,0,0,0,1,0],再重新決定Base Semitone為5。
3. 此時Base Semitone為5,原本的Chroma Vector為[0,1,0,0,0,0.6,0,0,0,0,0,0]經過轉換的結果為[0.6,0,0,0,0,0,0,0,1,0,0,0],再重新決定Base Semitone為5。
4. 此時Base Semitone為5,原本的Chroma Vector為[0,0.7,0,0,0,0.8,0,0,0,0,0,0]經過轉換的結果為[0.8,0,0,0,0,0,0,0,0.7,0,0,0],再重新決定Base Semitone為5。
5. 此時Base Semitone為5,原本的Chroma Vector為[1,0,0.8,0,0,0,0,0,0,0,0,0]經過轉換的結果為[0,0,0,0,0,0,0,1,0,0.8,0,0],再重新決定Base Semitone為0。
6. 此時Base Semitone為0,原本的Chroma Vector為[1,0,0.8,0,0,0,0,0,0,0,0,0]經過轉換的結果為[1,0,0.8,0,0,0,0,0,0,0,0,0],再重新決定Base Semitone為0。
7. 此時Base Semitone為0,原本的Chroma Vector為[0,0,0,0,1,0,0,1,0,0,0,0]經過轉換的結果為[0,0,0,0,1,0,0,1,0,0,0,0],再重新決定Base Semitone為4。
8. 此時Base Semitone為4,原本的Chroma Vector為[0,0,0,0,1,0,0,1,0,0,0,0]經過轉換的結果為[1,0,0,1,0,0,0,0,0,0,0,0],再重新決定Base Semitone為4。
9. 此時Base Semitone為4,原本的Chroma Vector為[0,0,0,0,0,0,0,0,0,0,0,1]經過轉換的結果為[0,0,0,0,0,0,0,1,0,0,0,0],再重新決定Base Semitone為11。
10. 此時Base Semitone為11,原本的Chroma Vector為[0,0,0,0,0,0,0,0,0,1,0,1]經過轉換的結果為[1,0,0,0,0,0,0,0,0,0,1,0],再重新決定Base Semitone為11。
11. 此時Base Semitone為11,原本的Chroma Vector為[0,0,0,0,0,0,0,0,0,1,0,0]經過轉換的結果為[0,0,0,0,0,0,0,0,0,0,1,0]。
轉換的結果如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
10 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
9 | 0 | 0 | 0 | 0 | 0 | 0.8 | 0 | 0 | 0 | 0 | 0 | 0 |
8 | 0 | 0 | 0 | 1 | 0.7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
7 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 |
6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
2 | 0 | 0 | 0.6 | 0 | 0 | 0 | 0.8 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 0.6 | 0.8 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
接著,再依照這個結果,給予不同的Base Semitone,即能還原回原本的Chroma Feature,紅字粗體的能量所代表的Semitone為Base Semitone。
還原的過程如下所述,以下的編號可以視為還原第n個Frame的過程。
假設一開始的Base Semitone給予3,照理來說,結果會與原本的Chroma Feature一樣。
0. 此時Base Semitone為3,將[1,0,0,0,0,0,0,0,0,0,0,0]還原成[0,0,0,1,0,0,0,0,0,0,0,0],再重新決定Base Semitone為3。
1. 此時Base Semitone為3,將[1,0,0,0,0,0,0,0,0,0,0,0]還原成[0,0,0,1,0,0,0,0,0,0,0,0],再重新決定Base Semitone為3。
2. 此時Base Semitone為3,將[0,0,0.6,0,0,0,0,0,0,0,1,0]還原成[0,1,0,0,0,0.6,0,0,0,0,0,0],再重新決定Base Semitone為5。
3. 此時Base Semitone為5,將[0.6,0,0,0,0,0,0,0,1,0,0,0]還原成[0,1,0,0,0,0.6,0,0,0,0,0,0],再重新決定Base Semitone為5。
4. 此時Base Semitone為5,將[0.8,0,0,0,0,0,0,0,0.7,0,0,0]還原成[0,0.7,0,0,0,0.8,0,0,0,0,0,0],再重新決定Base Semitone為5。
5. 此時Base Semitone為5,將[0,0,0,0,0,0,0,1,0,0.8,0,0]還原成[1,0,0.8,0,0,0,0,0,0,0,0,0],再重新決定Base Semitone為0。
6. 此時Base Semitone為0,將[1,0,0.8,0,0,0,0,0,0,0,0,0]還原成[1,0,0.8,0,0,0,0,0,0,0,0,0],再重新決定Base Semitone為0。
7. 此時Base Semitone為0,將[0,0,0,0,1,0,0,1,0,0,0,0]還原成[0,0,0,0,1,0,0,1,0,0,0,0],再重新決定Base Semitone為4。
8. 此時Base Semitone為4,將[1,0,0,1,0,0,0,0,0,0,0,0]還原成[0,0,0,0,1,0,0,1,0,0,0,0],再重新決定Base Semitone為4。
9. 此時Base Semitone為4,將[0,0,0,0,0,0,0,1,0,0,0,0]還原成[0,0,0,0,0,0,0,0,0,0,0,1],再重新決定Base Semitone為11。
10. 此時Base Semitone為11,將[1,0,0,0,0,0,0,0,0,0,1,0]還原成[0,0,0,0,0,0,0,0,0,1,0,1],再重新決定Base Semitone為11。
11. 此時Base Semitone為11,將[0,0,0,0,0,0,0,0,0,0,1,0]還原成[0,0,0,0,0,0,0,0,0,1,0,0]。
還原的結果如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 | 0 | 0 | 0.6 | 0.6 | 0.8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
3 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0.8 | 0.8 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 | 1 | 0.7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
假設一開始的Base Semitone給予4。
0. 此時Base Semitone為4,將[1,0,0,0,0,0,0,0,0,0,0,0]還原成[0,0,0,0,1,0,0,0,0,0,0,0],再重新決定Base Semitone為4。
1. 此時Base Semitone為4,將[1,0,0,0,0,0,0,0,0,0,0,0]還原成[0,0,0,0,1,0,0,0,0,0,0,0],再重新決定Base Semitone為4。
2. 此時Base Semitone為4,將[0,0,0.6,0,0,0,0,0,0,0,1,0]還原成[0,0,1,0,0,0,0.6,0,0,0,0,0],再重新決定Base Semitone為6。
3. 此時Base Semitone為6,將[0.6,0,0,0,0,0,0,0,1,0,0,0]還原成[0,0,1,0,0,0,0.6,0,0,0,0,0],再重新決定Base Semitone為6。
4. 此時Base Semitone為6,將[0.8,0,0,0,0,0,0,0,0.7,0,0,0]還原成[0,0,0.7,0,0,0,0.8,0,0,0,0,0],再重新決定Base Semitone為6。
5. 此時Base Semitone為6,將[0,0,0,0,0,0,0,1,0,0.8,0,0]還原成[0,1,0,0.8,0,0,0,0,0,0,0,0],再重新決定Base Semitone為1。
6. 此時Base Semitone為1,將[1,0,0.8,0,0,0,0,0,0,0,0,0]還原成[0,1,0,0.8,0,0,0,0,0,0,0,0],再重新決定Base Semitone為1。
7. 此時Base Semitone為1,將[0,0,0,0,1,0,0,1,0,0,0,0]還原成[0,0,0,0,0,1,0,0,1,0,0,0],再重新決定Base Semitone為5。
8. 此時Base Semitone為5,將[1,0,0,1,0,0,0,0,0,0,0,0]還原成[0,0,0,0,0,1,0,0,1,0,0,0],再重新決定Base Semitone為5。
9. 此時Base Semitone為5,將[0,0,0,0,0,0,0,1,0,0,0,0]還原成[1,0,0,0,0,0,0,0,0,0,0,0],再重新決定Base Semitone為0。
10. 此時Base Semitone為0,將[1,0,0,0,0,0,0,0,0,0,1,0]還原成[1,0,0,0,0,0,0,0,0,0,1,0],再重新決定Base Semitone為0。
11. 此時Base Semitone為0,將[0,0,0,0,0,0,0,0,0,0,1,0]還原成[0,0,0,0,0,0,0,0,0,0,1,0]。
還原的結果如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
6 | 0 | 0 | 0.6 | 0.6 | 0.8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
4 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3 | 0 | 0 | 0 | 0 | 0 | 0.8 | 0.8 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 1 | 1 | 0.7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
而這個結果其實就是原本的Chroma Feature將音高移高一個Semitone的Chroma Feature,而要將其還原的原因並不是要證明這個結果是可以還原的,而是要證明說只要旋律相同,不論這個音樂是什麼調,經過轉換後的結果是一樣的。
但是這邊還有一個疑問,如果兩個來源轉換出來的Chroma Feature可能中間有一小段的不同,那經過轉換的結果又會有什麼不同呢?
經過部分變更的來源:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 | 0 | 0 | 0.6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
3 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0.8 | 0.8 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
轉換的結果如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
11 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
10 | 0 | 0 | 1 | 0 | 0 | 0.8 | 0 | 0 | 0 | 0 | 1 | 1 |
9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
8 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0.6 | 0 | 0 | 0 | 0.8 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
觀察這個結果與之前的結果,其來源是由原本的來源的第3、4、7個Frame修改後而成,而比對結果,與原本結果不同的為第3、4、5、7、8,其它地方還是相同的,所以只要這種不同的Frame不要太多,還是可以利用DTW來做對譜的動作。
====20090108====
這一週的進度取得了Onset的"大概位置"
接下來可能會用傳統的方式靠energy來取得比較正確的位置
接著我也會試著修改計算distance的方法
來試試看結果會不會比較好!
投影片中有一些解決Key Shift的資料
詳細的資料已在上方
其中學長有問說:為什麼我base semitone要一直改,不用同一個就好了
其實這問題我也想過
我meeting時回答的可能不好
我再重新整理一下
如何決定base semitone是一個問題
假設只以一開始決定base semitone就不更改的話
那有個先決條件
就是"這兩首歌的頭要對齊"
所以就不能用片段去對整首歌了
接著探討一下如果中間走音的話情況會如何
如果中間部分走音是shift一大段的pitch
那只以一開始的base semitone做調整的話
那這邊對過去可能會這一整片都有很大的distance (因為一整段走音 整個對不上)
但如果是用前一個frame的base semitone的話
那會有比較大distance的部分 會是"剛"走音的那幾個frame (影響範圍有限)
(如果之後又轉換回原本的pitch,那在剛轉換的那幾個frame的distance也會變大)
而整段走音的部分
因為變化趨勢還是一樣的
所以我認為distance不會變大
此外上週有一個Chroma Feature的圖
能量是集中在最上方的Chroma Bin
這是我寫程式的疏忽
把大於某個頻率的能量都分配到那根Bin
此Bug已解決
====20090113====
這週的進度為
將由DTW比對後的結果 (概略的Onset位置)
在做一次調整
調整方法為
第i個frame的x音的能量比例 - 第i-1個frame的x音的能量比例
如果大於threshold的話 則可能為Onset所在
途中
1.老師有提到說可以參考其它同時發聲的其它音高的Onset位置
2.DNA有提到說threshold的假設可以說是
經由取斜率(微分)的結果 大部分都是0.3(假設) 所以才設為0.3
其實當時我還聽不懂取斜率(微分)是該怎麼做
後來問DNA後 才知道就是後面的frame和前面的frame做相減
哈哈 請恕我才疏學淺 沒反應過來
====20090119====
本週做了一個小小的實驗
我修改了Midi和Wav計算距離的方法
主要是Midi轉Chroma後
同一個時間點通常只會有1~3個不等的Chroma elements有值
所以我的想法是只去比對這些有值的elements
而其它elements就先忽略
這個概念源自於阿扁講過的 "頭過身就過"
我就想說就只要比對這些有值elements就好了
而那些沒有值的elements如果去和wav比的話
反而會成為拉大distance的主因 !!
做了一個小實驗
以16秒的片段歌曲當做是input
去search完整的Midi file
共有五首片段歌曲
其中第五首是現場演奏
而前四首是Midi file而成出來的Wav file
因為樣本數太少
所以成功率的話..請各位看倌打個折扣
表格中的數字代表distance
越小代表越相近
而接下來會將input的Wav file加上reverb的效果
再跑一些實驗看看
====20090224====
繼續之前做的
只針對Wav File取一段去搜尋MIDI File
方法依然為DTW配合Chroma Feature
修改距離的計算方法
由原本的
修改為
因為MIDI File可以知道哪些音高有能量
所以只針對有能量的音高做運算
所以假設只有A音高有能量
則計算過程為
若A音高和B音高有能量
則計算過程為
輸入的Wav File有原始音檔(MIDI File合成)取16秒
以及Reverberate後的Wav File
其中做Dark Hall後的音檔和原本的音檔差異不大 (耳朵要很仔細聽才聽得出來)
Large Empty Hall差異比較大 (波形差很多 耳朵馬上可以聽出來)
結果還不錯 表格中的數字為距離
越小代表越相似
但是因為樣本數有點少
真正的結果得等我跑完真正的大實驗才會知道
不過我預想效果應該不會太差 (純屬預想)
因為經過Reverberate後的音檔 每個音高的能量比例會變
依照原始的方法
如果原本是符合的 經過這個一變動 在距離的計算就會變大 (因為其它音高會跑出能量 拉大距離)
但如果只比對MIDI File有能量的音高 則照理說可以避免掉這個問題
====20090227====
我整理一下週五和老師討論的內容
如果有理解錯誤的話 請指正
由於文森部分的Partial Tracking無法知道目前的F0到底是D4還是D5
所以我的部分相當於一個前處理的機制
在對完譜之後可以知道每一段對到譜上為哪些音 Ex: D4
所以可以把這個資訊告訴Partial Tracking的部分
這樣Partial Tracking就可以知道目前的F0是D4而不是D5
====20090303====
我整理一下我之前做的結果
不然可能有點亂
依照原本的方法
不管原本資料庫端或者輸入端是MIDI或Wav都無所謂
反正都可以直接轉為Chroma Vector再計算歐幾里得距離
但是假設其中一方一定是MIDI的話
則就可以知道目前是哪幾個音高為有能量的
所以可以針對那幾個有能量的音高去計算距離即可
這個方法可以避免掉reserb的影響
而我改善Key Shift的方法
則和原本方法一樣
不限制雙方為MIDI或Wav
如果資料庫端是MIDI 輸入端為Wav的話
做完DTW後所對到的結果
可以透過MIDI所給的資訊
找到Wav的Onset位置
而這個位置 可以再透過每個音框的音高的能量
去修正 找到更精確的Onset位置
但是如果要和其它paper比較的話
大多數的paper還是資料端和輸入端都是wav為主
而我這週做的就是把我之前所講的Key Shift的方法給實做
並且跑一些數據
卡農這首歌曲效果不彰的原因是
我取的那一小段歌曲在原音裡面的後段 就有經過移調然後重覆出現
我接下來會用最原始的方法測試經過reserb之後的音檔來搜尋會有多差
以及跑一下切巴哈無伴奏的結果
====20090310====
我又要來推翻我所說的話了
果然沒做過實驗之前所講的話需要打50%的折扣
如果資料庫端和輸入端都是wav的話
資料庫端為原曲
輸入端為原曲取16秒後經過reverb處理
其中我試過的種類有
Full Reverb (Medium Concert Hall (open))
Large Empty Hall Reserb
Shower Reverb
而音檔是使用Bach裡面的The Anna Magdalena Notebooks中的四首歌曲
anna-03 anna-04 anna-07 anna-10
以及Mozart的
Violin concerto No.1 in Bb, K.207 (Allegro moderato) vck207-1
Violin concerto No.2 in D, K.211 (Allegro moderato) kv211-1
Violin concerto No.3 in G, K.216 (Allegro) kv216-1
做完實驗的結果其實並沒有想像中的差
(資料庫中如果是MIDI的話 直接與Wav做DTW結果本來就不好 再reserb的話會更亂)
雖然distance有變大
但是還是比其它歌曲小
表格中的數字為Distance
Distance越大 代表越不相似
縱軸為Input 橫軸為資料庫端
不管有沒有經過Reverb
輸入端的片段歌曲 都可以成功的找到原始歌曲
同樣的音檔把資料庫中替換為MIDI File
並且使用原本的方法來做Search
以及用改善的方法來做Search (改善的方法有po在上週)
其實總體來看 是會比較好的
但是有些結果卡在第二名的原因是
其中有一首MIDI 在某段是沒有聲音的
這會造成我在計算Distance時 給他為0
所以這首歌在計算Distance時 不管是跟哪一首歌計算
Distance的結果都是非常低
順便一提 這次我用的樣本在經過Reverb之後Search的排名都沒有變
這次的結果我有列出排名
而修改後的方法也有與修改前的方法比較排名 (上升or下降)
接下來說明一下 我和文森的部分該怎麼做整合
首先 我這部分 MIDI和Wav 經過DTW之後 會輸出一份Onset的時間點以及音高
而同樣的Wav經過Partial Tracking之後 會輸出
Partial的音高
開始時間
持續時間
能量
並且會標明是屬於哪個Group(F0)
我想的修正方法很簡單
總之Parial Tracking會先有一份答案
然後再以DTW的結果
去看Onset 時間點附近的有沒有起始時間差不多的Partial
如果有的話 則去比對音高(頻率)
若有找音高相同的Partial
則把這個Group的F0更新為找到的這個Parial (可能更新前後不會變)
若沒找到 則可能是有幾個問題
1.連音問題 (時間點附近都沒Partial,因為連音,Partial Tracking把它連起來了)
2.譜錯 或者是 彈錯了 (雖然時間點附近有Partial 可是音高卻不同)
我現在比較傾向於先把這些程式整合搞定了再來解決這兩個問題XD
而在修正之後的輸出結果 會是 F0的音高 開始時間 持續時間 能量
接著就可以做合成了!
====20090324====
這一週測了幾首歌的Onset (利用MIDI和DTW)
但是由於MIDI的問題
所以目前只有一首歌找個還算不錯
這首歌是
Bach的Sonata No.1 in G-, BWV1001 (Siciliano)
由於Onset過多 我只取了幾個而已
結果請看投影片的圖!
另外有一個正規化的問題
一種是向量除以vector norm
另一種則是把一個向量的值mapping到0-1
轉檔程式會將兩種都轉出來
並著名是n1或n2
====20090401====
開始著手研究文森的程式
取得我想要的資訊
但卻發現 一首歌要下去分析實在是太龐大了 (跑不動)
只好分段下去跑
目前的想法是
分段下去跑 假設每一段是5秒鐘
可是這分段的時間位置 不一定就是音高的起始/結束
所以分析完的結果 必須得另外做一個合併的處理
依照文森目前的程式
Partial的頻率
起始Frame Index
持續的Frame Number
能量
F0
都可以取得
但是還沒有分Group的動作
我所謂的分Group的動作是指
400Hz 600Hz 這兩條 跟200Hz這一條 會是同一個Group
而對於分段後合併的想法
我合併的想法很簡單
如果前面那一段的Group的結束時間 和 後面這一段的Group的起始時間接近
且F0相同
那就合併
====20090421====
很久沒來寫了=_=
我補一下之前的東西
對Onset這部分
我找了很久 雖然網路上有Bartok 的midi
但是沒有老師給我那片CD的曲目...
我曾經試過去找wav轉midi的轉檔軟體
但是效果很差...
我覺得似乎...花錢請專家做midi比較快 囧
再來就是之前修改學長合成程式的部分
我稍微記錄一下
一開始我先把學長程式內Filter的觀念搞懂
其實也沒什麼 就跟slim差不多
不過有差別的是
學長寫的Filter 不是 Multi Thread
這個我畫的圖
分別標明了程式執行的順序
在搞懂了Filter之後
我就去看了學長合成程式也哪些Filter
大概就是長這樣
我把Noise的部分關掉 所以有關Noise的部份我沒有理會
而我看了程式之後 真正要改的只有 標明紅色的三個Filter
fAPP負責傳送AbstractPara
AbstractPara 就是 F0 和 Amp
經過fAP2SPI長出20個partial的Amp (這樣是一個Sinusoid)
再透過fSI2RIA的addPartial()這個method處理
那些方法的細節 我就不多講了
因為都是學長寫的XD
我的修改方法只是將
fAPP傳送AbstractPara 改成 傳送AbstractPara [] <---就是一堆Fo和Amp
fAP2SPI傳送Sinusoid 改成 傳送Sinusoidp[] <---就是好幾組Sinusoid
這邊都ok 反正就是多加for迴圈下去跑
接著就是fSI2RIA
其實也沒改什麼
比較要處理的就是phase
注意不同音的phase要另外算就行了
但是!!!
其實學長的程式實在是博大精深了
所以我只好先延用他的button來跑我改的程式XD
並沒有加一個新功能在內
其實之前都是會錯意...原來f0和能量是每個frame都有...
所以又重畫了一張流程圖 應該是要長這樣!
DTW只輸出onset的frame index和音高
接著和Partial Tracking的結果做修正
但其實我覺得我修正的方法還很差...
我想這部分是可以改進的
我只是去找時間差不多近的那一條partial而已
但是其實可能會誤判
我想比較好的方法 應該是寫一個Application
最後讓使用者自己修正一下比較好
甚至也可以讓使用者任意修改F0 合成出來的結果就會不同XD
所以這邊修正完會輸出成F0和能量
當然一個Frame會有多個F0
接著再丟給合成程式
聲音就出來了XD
接著...我會邊轉CD...邊寫論文...邊養身體>"<
等口試後我會把程式重整一次...並且詳細的寫上"註解"
====20090423====
貝多芬 String Trio in C-, Op.9, No.2
我成功抓到wmv檔案 也有了MIDI FIle
我兩邊都抓取部分來對Onset 感覺還OK? (私心的自己覺得>"<)
Part1
Part2
當然合成的程式我也有跑
但是 結果似乎不太好
我用的partial tracking的程式是0309的那版 (最初版)
不過我想等文森那邊都完成的話 合成出來的結果會變很棒
原因我整理一下
1.連線中間斷掉
2.低頻的都找不到? 我用cool edit看頻譜其實很明顯一條 但是低於100hz
稍微記錄一下 我今天跟老師談的內容
論文
1.第一章 Introduction
把一堆相關paper都寫進去
也當reference
切記要寫張智星老師的paper進去XD
2.第二章 簡單介紹DTW和Chroma Feature
3.第三章 Partical Tracking + DTW + 合成 (onset要在這章?)
4.第四章
4-1 利用Partical Tracking 結果 加強Chroma Feature
4-2資訊檢索
5.第五章 實驗
====20090424====
利用Partical Tracking結果 加強Chroma Feature
讓那些音高更明顯
從Partical Tracking的結果輸出F0 List
並且轉成12個音階
利用這個結果 加強原本Chroma Feature
若Partical Tracking結果對應到Chroma Feature的音高
就加個權重 ex: 平方? 乘以2之類的
====20090428====
流程圖
我這邊Enhance的方法是把能量乘以2
以下是Enhance之後的結果
Part1
Enhance前
Enhance後
Part2
Enhance前
Enhance後
Part3
Enhance前
Enhance後
====20090501====
我在Key Shift這邊,有一段解釋,是故意製造錯誤之後,再觀察經由Base Semitone轉換的結果
原文是這樣的:
觀察這個結果與之前的結果,其來源是由原本的來源的第3、4、7個Frame修改後而成,而比對結果,與原本結果不同的為第3、4、5、7、8,其它地方還是相同的,所以只要這種不同的Frame不要太多,還是可以利用DTW來做對譜的動作。
我後來發現...打這些字好像有誤導大家的嫌疑,因為我後來看,我也覺得我自己被我自己誤導了!所以要跟大家say sorry一下!
我今天報告後,想了很久,我想得在重新整理一下。
DTW除了計算Distance,還能取得Input和Reference的對應位置,至於對應位置的正確性,則就要看兩邊的時間(Index)上的內容,而DTW本來就能夠容忍部分的錯誤,至於容忍多少,要看那錯誤的片段有多長,以及那錯誤片段與原本正常片段的差距有多少(Distance)。
而我先前解決Key Shift的方法,有提到如果片段錯誤的話,那轉換的結果影響範圍有限,其實這點也只是保留原本Chorma的特性而已。
先看原本的Chroma,假設一首歌前半部的音高是錯的,而後半部的音高是對的,那轉成Chroma之後,自然也是呈現"錯對"的樣子。
而所以希望經過Base Semitone轉換之後的結果,也是跟原本的Chroma一樣,會是"錯對"的情況出現。
之所以提到這點,是因為當初在想轉換的方法時,都會想說只靠個某個Frame的某樣屬性做轉換,例如只靠第一個Frame的最高能量音高做轉換,但如果那個Frame剛好是的錯,那就慘了。假設有兩首一樣的歌,但是其中一首歌的第一個Frame是錯的,那兩首歌經過轉換後,會完全長得不一樣。
直接把例子套上以上的說法,原曲在Chroma上是"對對"的情況,而Query(假設前半部和原曲是不同的)在Chroma上是"錯對"的情況,如果靠著第一個Frame的某樣屬性做轉換,原曲依然是"對對"(我們假設他是對的,因為是放在資料庫),而Query則會變成"錯錯"的情況(因為是依賴第一個Frame做轉換,但因為第一個Frame和原曲不同),這個"錯錯"的情況意思是說,他跟原曲轉出來的不管是前半部還是後半部,都會長得不一樣。
而解決Key Shift也還有保留另一樣Chroma的特性,那就是從原曲任一時間點上擷取片段,和原曲整首直接轉再去擷取片段,不會有太大差異。(當然不可能完全一樣,從不同的sample點做FFT會有些微能量值的差異)
Chroma很直覺,擷取其中幾秒的歌曲片段,轉Chroma,會和將整首歌轉Chroma之後時間點相同的片段長的差不多。
所以希望新的轉換方法,也能有同樣的效果,不管我是擷取哪個時間點的片段做轉換,都希望能和原曲直接做轉換,接著看同樣時間點的片段的結果差不多。
很明顯Base Semitone的轉換方法有做到這一點,因為只參考前面一個Frame。
補充一下
如果"錯"的部分是key shift的話,那轉出來的結果,不會是"錯"的
====20090505====
Partial Convert to Chroma
F0 List + Chroma => Chroma (上週弄的)
F0 List => Chroma (拿f0 detection的結果直接轉chroma)
F0 List + Partial List => 128 dimensional (將f0和partial轉成128維度的向量)
F0 List + Partial List => Chroma (將f0和partial轉成chroma)
因為時間的關係 我只跑了F0 List + Partial List => Chroma
本來也想跑F0 List + Partial List => 128 dimensional 看看
但是show圖的程式 我來不及改了XD
總之先看一下結果
FFT=>Chroma
F0 detection enhance 上一張圖
Partial Tracking=>Chroma
總覺得Partial Tracking的結果很漂亮
但跟原圖的時間點有小小的差異
應該是FFT Size取很大的緣故
再補兩張 Partial Tracking=>Chroma
有些地方有斷掉 那是因為Partial Tracking我跑的是舊版程式
所以沒有補點
還有少部分的斷掉是Partial Tracking沒有連起來
====20090505====
昨天睡覺前無意間發現一篇paper
結果因為某部分很重要的地方看不太懂 讓我輾轉難眠
我英文還是太差了 誤會了他敘述的意思
多謝了小明學長替我解惑
這篇paper某個部分和我先前講的 解決key shift的方法類似
其實了解了之後...也覺得他的想法很簡單
但是當初就是沒想到><
這一張圖是原音轉Chroma
這一張圖代表的是原圖的 第 n+1 個frame 和 第 n 個frame 位移幾個半音之後的相似度 (縱軸是位移幾個半音)
所以簡單來說 他就是去記錄 前後frame 之間 移調後的相似度
而我講的方法 則是去參考前一個frame的最大能量個半音 為何
去調整目前這一個frame 的 Chroma Vector
用上一個frame的最大能量半音 來紀錄目前這一個frame要移調幾個半音 並且記錄有多少能量
所以
兩個方法都有去參考前一個frame
在記錄一種走勢
老師問我說 那他們的方法可以還原成原本的Chroma嗎?
我想答案是不行的
因為只有C圖的話 那只記錄相似度
只能大概猜出frame的走勢
至於這個走勢是從哪幾個音高 或者是 幾個音 所造成的
那就不得而知了
不過他們的paper並不是只拿C圖當特徵而已
原本的A圖也有
比對方法不是用DTW
詳細部分我沒有看
我只看Chroma Feature而已
補充:
我講的方法其實不是看最大能量的音高
而是有設一個Threshold
講最大能量只是為了方便說明和想像
不取最大能量的原因是
因為音檔是多音的
從單一首歌同樂器同調來看的話
並不能確定不同演奏家都會演奏時 某個音高一定會能量最大
從單一首歌同演奏家不同樂器同調來看的話
並不能確定不同樂器演奏時 某個音高一定會能量最大
從單一首歌同演奏家同樂器不同調來看的話
能量多寡也不會單單是往上移幾個半音這麼簡單
其實有點亂XD 我也不知道我的想法對不對
有待實驗證明...
====20090512====
我把上面那篇paper講的feature實做出來
並且和我的方法做比較
====20090519====
MIDI輸出的格式
目前我覺得可以用最流行的xml來紀錄
不然用一般的寫檔也是可以
輸出格式 以Track為單位
這邊的Track跟MIDI定義的Track不同
一個Track代表一條音
而時間的問題
我們討論的結果 決定弄一個統一的絕對時間
但是最小的單位時間 需要討論一下
另外頻率和音量 我們決定用陣列來存
因為希望這個格式 是一個統一個格式
而這個格式也能吃從文森程式output的結果
class Track
{
int 樂器id;
float[] 頻率;
float[] 能量;
int 起始單位時間;
int 持續單位時間;
Control[] control;
}
class Control
{
int type; //紀錄 control種類, ex: vibrato 就填1
int subType; //紀錄 是哪一個子類, ex: vibrato有三種,如果要第二種,就填2
string tablePath; //如果type是user define, 會由使用者指定這個路徑
int 起始單位時間; //在這個Track的單位時間多少時發生
int 持續單位時間;
}
====20080609====
我覺得我之前search MIDI Database的公式有點不太合理
所以我做了一些修改
原本是MIDI 轉 Chroma 後 看有幾個音高有發音 就去計算那幾個音高的distance
所以如果MIDI 轉 Chroma 後的音高越多的話 那distance會越大
所以我將公式改為 在開根號之前 先除以n
n就是轉Chroma後有幾個音高