2010年12月30日 星期四

Score Alignment and Following - 小聽

   
[20110223]

‧DTW path onset selection 一個midi frame對多個wav frame的問題
1. midi的ADSR之A第一個值不從零開始,改成0.1。(也許是因為0對noise太敏感)
2. midi onset frame定為A state的中間。

‧MATLAB記憶體不足的問題
1. use memory defragmentation (因為MATLAB需要連續的記憶體)
2. frequency domain用其他的scale
3. others...

‧目前的Cakewalk舊版讀MAPS的midi會有錯

[20110217]

W partial之外的bin設為0的方法。請和2/9的圖來比較。


[20110210]

schedule:
deterministic harmonic constraint -> temperal smoothnese -> spectral smoothnese

[20110209]

同樣是 Friedrich Gulda 的 K 281 - Andante Amoroso
抓了一個低音域的連續八度音片段
 λ = 100, garbage = 1
58.2705Hz的基頻能量非常小,由於圖比例的關係看不出來。
但是實際上它的能量真的很小,且看的出來三倍頻能量比基頻大許多。


後來去看西班牙鋼琴資料庫的一些低於100Hz左右的單音頻譜,
發現也有某些二三倍頻的能量大於基頻許多的例子。


[20110126]

All is 440Hz.
piano : wav
violin : wav
trumpet :wav

[20110125]

P mask, tone model, if else.

[20110120]

Midi note envelope:
Transient part : A= 0.02s, D=0.02s, fixed.
Otherwise, S and R can be scaled.

K281.Andante - 2 bar

1. 將第1、2個template除外的其他template (3rd~13th),給之inital H,
而W的部分先用原本gaussion的initial partial方式來training ,如下圖。

結果:
2. 把3rd~13th template W也用上第一次的結果,如下圖。
結果:

兩者好像差不多...


[20110119]

harmonic bands寬度: 一個半音->半個半音
Mean of all onset difference (Midi synthesized-G Air-2 bars)
0 garbage = 0.057472555 -> 0.057610769           
1 garbage = 0.167695353 -> 0.087274952  (!)

對付實際演奏的音檔,應該還是需要garbage template的存在,
所以以後把bandwidth設成半個半音來做實驗好了。

因此將garbage template 個數1,半個半音的bandwidth為參數,
改變midi envelope為ADSR,如下圖:

Mean of all onset difference : 0.087274952 -> 0.400023036
結果每個onset都變糟了!

以template #14: 440Hz為例,共有三個note,


左圖是簡單的梯形envelope,Diff = ( 0, 0.053333333, 0.022358277 )
右圖是新的ADSR envelope,Diff = ( 0, 0.152018141, 0.376462585 )

看圖,如果把onset的位置像老師說的定在A stage的中間,那麼應該會準一點吧!


[20110118]
Friedrich Gulda - Mozart Piano Sonata K 281 - 2. Andante Amoroso - 3 bars
λ=100
λ=10000
λ=100, 1 garbage
λ=100, 3 garbage

Mean of all onset difference (Midi synthesized-G Air-2 bars)
0 garbage = 0.057472555
1 garbage = 0.167695353

[20110114]
套一個衰減較快的簡單envelope似乎效果比較好一點



[20100112]

今天大家討論之後發現好幾個問題將midi note的能量套一個簡單的envelope,如圖:

目前發現有兩個地方因此有所改進:

1. 對於同時出現的pitch音,在DTW時有了改善,以440為例,在第二小節後半的部分第一聲部和第二聲部同時出現。

原本:

後來:

可以看出在2500的附近path有找到第二個peak。

2. 90度的dtw path 會有 midi frame 一對多個 wav frames 的情況,因此我們需要要訂立一個規則去選擇那一個frame是我們要的,onset部分看起來都是選第一個 frame是最好的,所以假設規則是選最前面的frame,但是在offset的時候卻可能差很多,如下圖。

原本:
後來:
可以看出offset的位置依照規則來選的話結果算是好的。


[20110106]
todo :
1. midi中音符的地方能量改成"梯形"。
2. training一次後,使用initial W : 在某個時間點沒有其八度音的音,initial H : DTW的結果。

貼一下結果圖:



[20101230]

今天大家討論之後發現好幾個問題

1. 音檔比譜高了八度音
2. partial filter bands 忘記inverse
3. 音檔本身高頻就沒有能量
4. 左手應該是Do mi so,比譜多了一個E5。
    (實際用鋼琴測試了一下,應該是有彈mi)
5. 多音可以用garbage template來解決,
    少音卻可能會發生那個template吃掉別人的partial能量的現象。

更正一下結果圖:

‧λ=100的harmonic的效果不夠好,右邊的才有比較好的效果,
   其中第一個template的第二根peak就是 Mi (E5)的基頻。
‧partial數很少是因為音檔本身的問題。
‧目前的五個template是代表 C5、G5、C6、E6、G6
    可以發現八度音和五度音的問題確實會影響很大...


[20101229]

Input : (performance wav , piano )
(按圖可放大)

使用鋼琴的演奏音檔,觀察頻譜發現這個樂器的特性不是f0能量最大而是partial 1。
NMF的結果,對照initial template的圖可以很明顯的發現partial跑掉了,將harmonicity cost function的 λ 加大也沒什麼效果..



[20101227]

Input data:First bar of "Back - Air on the G String" (wav synthesized by MIDI )

Only initial:# partial = 10, Gaussion distribution ( σ = 1)
With additional harmonic cost function (by hanyo):λ = 0.02

The mean of aboutsolute difference between the above two :
W = 1.0837e-007
H = 9.2215e-004

Initial template放了對的頻率之後,有沒有使用harmonicity cost function的結果看起來是差不多的。分的結果看起來不錯,但,也許是因為input是由Midi合成的關係?


[20101221]

論文報告
Parallelism in Dynamic Time Warping for Automatic Signature Verification


[20101216]

將NMF的template設為只能是譜上出現的音+額外具有特殊功能的template,update時加上harmonic的限制。


假設在NMF的結果不錯的原則上,
有兩種方法:

1. 整首歌會出現的pitch都有一個自己的template,得到結果之後,再做單音對單音的 alignment。每個H row,分別去對那個pitch的score,得到自己的alignment。所以音檔裡總共有幾個pitch就會做幾次DTW。

2. 判斷那一個時間點有哪些音,template的個數和其代表的pitch會隨之改變。不做DTW,直接將H的值來分析結果。



[20101213]

●  純MATLAB  code的加速:

本來程式是依照這樣的公式寫,很直覺的就是用for loop針對matrix的每一個element去做計算。


 後來依照我11/23所報的第一篇paper上面的公式,他把它寫成更矩陣的形式。

 [ref. Accelerating Non-negative Matrix Factorization for Audio Source Separation on Multi-core and Many-core Architectures]

改寫後在matlab上跑,參數:frame size = 8192,hop size = 256,# of templates = 10, # of frames = 769。
只計算update部分的時間,iteration = 100次。

origin : 297.644882 (sec)
modified:28.522258 (sec)
speedup:10.4355倍

竟然差了十倍,看來在matlab上真的要盡量用矩陣運算來取代for loop寫法!


●  在MATLAB上使用CUBLAS library的SGEMM(Single-precision GEneral Matrix Multiply):

矩陣相乘維度參數 m x k x n
假設 C=A*B,A : m x k,B:k x n,C:m x n

每一列的意思:
  • MATLAB : 使用matlab指令A*B
  • myAPI:我寫的matlab函式,透過MEX-file得到matlab的參數,因為matlab是double-presicion,要先轉換型態之後,再去使用cublas library,之後再把值傳回。
  • Speedup:MATLAB time / myAPI time
  • only CUBLAS:myAPI中,不去計算matlab矩陣轉換到cuda矩陣的時間。
  • only cublasSgemm:only CUBLAS中,不去計算allocate cuda memory和搬運的時間,只計算lib中矩陣相乘函式cublasSgemm的時間。

左邊的參數會這樣設是仿造目前的參數W*H 來的,但這樣使用CUDA反而比MATLAB還要慢;右邊的實驗是想說資料維度大一點或許就會比MATLAB來的快,結果也如我想的。

接下來如果真的要使用mex & CUDA,應該不能一次矩陣相乘就呼叫一次,因為這樣資料要轉換型態、記憶體allocate還要搬好幾次,不划算。應該要寫一個把整個NMF過程都包含進去的API,最好是整個NMF都在GPU memory上面運作就好。

猜想11/23報的第一篇paper會比後面兩篇speedup來的小的原因是因為,他把每個operation拆開,每一個都寫成一個kernel function去執行,而後面兩篇可能是一次把事情做掉吧。




[20101206]

在Matlab上使用CUDA,可以參考Nvidia提供的pdf。
White Paper - Accelerating MATLAB with CUDA™ Using MEX Files

如果只要使用cuda提供的library,(ex. cufft)...等,那麼只需寫成.c檔就好了。
>> mex filename.c -IC:\CUDA\include -LC:\CUDA\lib -lcudart -lcufft
成功的話就會被compile成MEX-file(.mexw32)。

如果需要自己寫kernel function,要寫成cuda特有的.cu檔案才行,之後交給nvcc去compile。
這時候需要使用一些plugin tool。

A Guide to Using NVMEX tool


可能因為os、matlab、vc版本不同,在這邊會出現一些錯誤。

首先,我使用的是VC9,但範例中是VC8,因此需要修改一下nvmexopts.bat的一些路徑,
怎麼修改請看此pdf中的第6點 (連結)。


再來出現的錯誤
nvcc fatal   : Unknown option 'oC:\Users\Vivian\AppData\Local\Temp\mex_F9gfIA\test.obj'
看的出來因為路徑前面多了一個o所以找不到所需要的檔案。

只好去看一下nvmex.pl,把perl中的一些變數印出來看,發現是
$name_arg = $NAME_OBJECT . smart_quote($target_name);
$NAME_OBJECT這個變數的關係。

解決方法是把nvmexopts.bat中,
set NAME_OBJECT=-o 改成  set NAME_OBJECT=
也就是不給它值,就不會被干擾哩。


之後再compile,會發現會出現很多錯誤訊息,
google之後找到nvidia forums 有人和我有相同的問題! (連結)

將 nvmexopts.bat 中,
set COMPFLAGS=-c -D_WCHAR_T_DEFINED -Xcompiler "/c /Zp8 /GR /W3 /EHsc /Zc:wchar_t- /DMATLAB_MEX_FILE /nologo"

"/Zc:wchar_t- " 改為 "/Zc:wchar_t",也就是把"-"去掉,這樣雖然會出現一些warning,但是就可以compile過了!

感謝討論串中的eigma大大。



最後小小測試 fft v.s cufft,speed up大概是1.5~2.5左右。



[20101123]
報告
NMF on CUDA


[20101115]
實作chroma方法on MATLAB,依照Multi-pass...那一篇paper。
Frame size = 8192,hop size = 2048,DTW使用type I,與PSD的一樣。
平均差異值來看好像PSD好上一點,但PSD遇到長音感覺比較容易出錯,且chroma的異常值比較少。chroma在第344個錯誤可能真的是因為那個音的onset的能量太小。

但是在兩個paper中,有一點比較不一樣的地方是在DTW三個方向的weight。
PSD : (w0, w45, w90)=(1,2,1)
Chroma : (w0, w45, w90)=(1,1,1)
有點trick的是,因為是比min,(1,1,1)這樣的weight會比較傾向於走45度角,應該要讓它大一點畢竟走的距離是比較大的,可以看DTW path右上角的小小方區塊,一個走水平方向一個走斜對角方向,可能是此原因造成的差異,也許兩種都改成(1, sqrt(2), 1)會是比較公平的比較。


[20101112]

經由DTW path反推出alignment onset,與之前標的比較。圖為和alignment之後得到的onset與groundthruth onset比較的difference。
另外,因為使用的是typeI的DTW (0, 45, 90度),所以有可能會有一個midi frame對多個wav frame的情形,下圖分別是取中間frame、第一個frame、最後一個 frame來做為比較的差。

difference error (seconds):
每個frame之間距離2048,所以resolution大約是46 ms。

以下以取中位數frame的情況來分析,數字代表音符的index;
如果說去除大於1.5秒的那3個值,重新計算difference平均 = 0.0937 s,大約是兩個frame 。


第344個音符是BWV1007這曲子中,中間長音之後的第一個音符,在演奏的音檔中,這個音符的onset音量很小。

而第655、656個notes是曲子的結尾,是長音。


接下來有點想要在matlab上實作一次chroma的方法,比較一下這兩種方法對於BWV1007的結果如何。

[20101108]

Implement 6月7號所報告的論文,使用Matlab...令人感動的方便許多。

Midi parser的部分感謝這個網站與它的主人

經由midiInfo可得到每個note的資訊([track chan nn vel t1 t2 msgNum1 msgNum2]),之後再利用他的piano_roll,此原本是用來畫圖的function,我們丟進適當的時間間隔參數(hop的時間長度),就可以視為是我們的譜的roll,接著用回傳的PR矩陣,可以知道每個frame有哪些音符,再利用它造出我們的filter。每個note有8個bandpass filter,bandwith為一個semitone。

依然是先使用Bach BWV1007 prelude做實驗,wav是2分44秒,共656個notes。
圖中藍色線為spectrum,綠色線為band filters。上圖是wav的第2個frame vs midi的第2個frame,distance較小;下圖是wav的第10個frame vs midi的第220個frame,distance較大。

論文中的hop size為256,所以有5.8ms的resolution。
可是如果這樣的話,matlab記憶體會不夠,因為矩陣變得相當大;且論文中提及他實驗的一首兩分半的巴哈小提琴獨奏,就需要2GB的記憶體,但筆電的RAM也才2GB...

所以先使用frame size = 8192,hamming window,hop size = 2048。

左邊是distance的矩陣,顏色越深代表越相似;
右邊紅色線是DTW找出來的對應路徑,0度, 45度, 90度的 typeI,weight=[1,2,1],頭對頭、尾對尾;此外記錄一下一些參數 thetaD = 0.5, thetaS = 0.5, ss = 1, sd = 1。
可以發現結果和左邊用肉眼看出的由distance小的element所那條組合成的線很相近,不過這也只能說是DTW找出來的path和最小cost真的很符合而已。

要知道結果好不好,還是要和ground truth(之前用cool edit標的)比較,下一步應該要把cue的資訊弄進matlab計算正確率。


[20101026]

報告
Artificial Neural Network: An Overview
投影片


[20100928]

論文報告
A Multi-Pass Algorithm for Accurate Audio-to-Score Alignment
投影片


[20100802]

論文報告
Improving Polyphonic and Poly-Instrumental Music to Score Alignment
投影片


[20100608]

Q:
我有一個spectrum,已知裡面的某一個f0,想要知道它是不是單音且為harmonic ?
A:
1. filter : 因為知道f0,在每個倍頻上用 gaussian 去 model 每個 peak
2. 計算 : spectrum 的總能量 - spectrum 經過 filter 後的能量
3. 如果是單音且為harmonic,那麼剩下的能量應該會很小。


[20100607]

論文報告
Alignment of Monophonic and Polyphonic Music to Score - Ircam.
投影片

除了之前看的chroma feature,也有好一些人是使用這篇論文提出來的方法。這篇論文是2001年publish的,它提出了一個名為 Peak Structure Distance(PSD) 的 feature,這個Distance用來當作DTW中的local distance使用,相對於之前我們的作法就是用來取代Euclidean distance。

PSD簡單來說,就是去算score frame與 audio frame 的peak的相似度,越相近distance越小。另外它還model了一個note的開始 (attack model) 與 結束 (silence model) 。

它做了很多仔細的實驗和數據,結果看起來不錯,感覺上還蠻值得參考的。下次會看也是由Ircam在2003年發表的paper,關於這個方法提出的改進。


[20100604]

以 Mozart piano sonata K.545 的前四小節為測試曲子,修改 midi 來合成測試的 wav。
Midi 合成 wav 軟體 : WinGroove

目前ground truth : Calkwalk 看 event list -> Cool Edit 人工標記
(未來:不執著於要存到wav裡的cue,用另外的檔案代替儲存。)

新增輸出 onset error 詳細資料的 html table。

測試了合成時有無reverberation、某個時間點譜不只一個音出現但audio其中一個音比譜晚出現半拍的情況。

進度投影片
link


[20100521]

由於想了解DTW在一些特定的情況之下會有怎樣的行為,因此我用midi式的chroma feature來作實驗,測試了比原本的 chroma 多音、少音、平移幾個半音,對於兩種 type 的 DTW 會有怎樣的結果。

另外也測試了 piano 與 trumpet 的片段。

進度投影片
link


[20100503]

論文報告
Handling Asynchrony in Audio-score Alignment
投影片



[20100430]

現在的目標,是讓score alignment夠準,然後能自動截取audio中每個音的起始時間,還有結束時間,它的f0和partials的frequency、amplitude,來做合成使用。

新增輸出 cue 詳細資料的 html table、輸出 alignment 結果所對應的midi、wave 之 frame、second 的 html table。

程式有bug待修。

進度投影片
link


[201003022]

論文報告
GPU ...



[20100204]

兩件事情:解決讀midi的bug、score alignment的onset時間 v.s 人工標記的onset時間。

1. 讀midi的bug : 在某些時候會少讀了一些長度
發現依然是讀檔時,byte轉換發生的問題,java的byte是signed,所以當值大於127它就會變成負的,再去做排列就會錯。這個問題之前也發生在讀wav的時候,用一樣的方式解決就好了。

更正一下上次po的圖,BWV1007前兩小節(點圖可放大)
midi :
wav origin :
wav considering partials :


2. score alignment 結果的onset時間 v.s 人工標定的onset時間

FFT frame size : 4096
hop size (兩個frame起始位置間隔) : 512
表格裡面的值 (秒) :
|score alignment 結果 - 人工標定的onset時間| / 總共onset個數


可以發現前四組結果,有考慮partials的方法會比沒有考慮來的好一些,
但是如果是整首BWV1007來做比對,兩者結果都變差許多,而且有考慮partials的方法結果還變得比沒有原始的方法差。

對於整首的這組結果來觀察,發現平均值增大的原因可能是因為有幾個onset的差異比平均大許多,大概一秒鐘左右。而有考慮partials的方法差異大的onset比原始方法的這種情況還要多。

新方法大約310-343+後面24個onset誤差較大,原始方法大約323-343+後面20個onset誤差較大所致。第343個onset對於BWV1007剛好是歌曲的段落,是一個長音,而且BWV1007這首歌除了中間和最後的兩個音是長音,其它都是16分音符,不曉得是不是因為這個原因讓判斷變差。


[20100120]

論文報告
Music Score Alignment and Computer Accompaniment
投影片


[20091231]

BWV 1007前2小節對譜全圖 (點圖可放大)
沒加新方法的 wav :

有往上加 partial 的 wav :
midi :

可以看出,有加了往上疊加 partial 能量方法的對譜效果比較好,
最後面的部分沒對好,是因為 midi parser 那部分有些問題,最後面少讀了一些音。
所以接下來要幫 midi parser 的部分code debug。
→ check 完學長原本的 c# 程式應該是對的,所以可能是改到 java 的時候不知道哪裡改錯了...  (20100105)


[20091221]

首先是解決冠廷學長之前沒處理到的部分:由於 map 到每個 pitch class 的 bin 數量不會一樣,所以要做一次 normalize 的動作。

左邊圖片是原本的,右邊是有加上取平均。(也就是傳統chroma)
1. white noise
2. BWV1007-15s

之後就作新加的部分,要往上加 partial 能量,也加上了 normalize 取平均的步驟。
以 BWV1007 前 15s 為例:
1. original
2. 每個 bin 從 frequency domain 中找最接近的partial's bin,加總其能量並取平均。
3. 每個 pitch 從 frequency domain 中找最接近的 partial's bin,加總其能量並取平均。(花較少時間)
目前以第三個方法為主。

上面三個圖之間似乎沒有很大的變化,
第二個比較稍微不一樣一點,第一個圖和第三個圖只有些微差距。

令人在意的是第二個音,譜是 RE,但是卻是五度音的 LA 能量較強,用了新的方法依然沒解決這個問題,這蠻出乎意料的。後來印出一些資料來看,發現可能是threshold設太小的問題。

這個threshold是用於判別這個bin是不是目前基頻的partial:
| (bin frequency/基頻) - ((bin frequency/基頻)最接近的整數) | <= threshold   所以我試著將 threshold 從0.001 調整為 0.1,第二個音 RE 就出現了! 對譜的結果也比之前的好



[20091217]

論文報告
Audio Thumbnailing of Popular Music Using Chroma-Based Representations
投影片


[20091216]

與老師討論了一下,以後可能有兩個方向可以走。

1. 假設 midi 是對的。
我們可以經由 DTW 的 cost 去調整 partial 的比例,也可以說是 chroma template 的 weighting 參數,以貼近現在樂器的特性。
比如說現在這把大提琴第三個partial的能量會特別高,希望可以經由 DTW cost feedback 來調整我們的 chroma template 的參數。

2. 假設知道是什麼樂器,而且只適用在這首歌只有一種樂器上,但是這樂器可以是多音。
(1) 把 midi 經由這樂器的音色庫,合成出符合這樂器的 wav,轉成 chroma 後再進行對譜。
(2) 由 wav 來建 instrument model,藉由這個來讓 chroma 更準確。


[20091211]

看了老師的回應,和小明學長討論了一下,預計的做法是:
FFT(4096) -> map 2048個bin到最接近的 pitch -> 每個pitch從frequency domain中找最接近的partial's bin,加總其能量,取平均。

這樣應該會減少一些計算量。


[20091209]

為了解決五度音等partial重疊導致能量貢獻給別的音名的問題,但是又想要維持使用chroma,也不想要在這裡使用pitch detection等較複雜的演算法。經過討論之後,決定現在多一個步驟的做法:讓每個頻率往上找它的partial,把其能量加起來到自己身上,這樣重疊的partial能量就會貢獻到可能是它的f0的身上。

流程 :
FFT (size:4096) → Map 每個 bin 到最接近的 pitch frequency → 每個 bin 往上找倍頻的能量並加到自己本身 → 每個 bin 分配到 chroma vector

我們使用的pitch frequency table是參考wiki的音高頻率表

另外就是這個演算法花的時間很久...

結果:
發現最下面那條Do的pitch class的能量一直非常大。

後來發現是因為第一個bin大約是10.7666Hz左右,然而第一個bin一定是所有bin頻率的因數,對照pitch frequency table,10.7666Hz最接近的是C0(DO),因此它的能量因此會最大。

忽略了第一根bin的結果:
發現變成是往上數第六條的能量最大,對照音名是FA。這是因為第二根bin也是好多bin們的因數,第二根bin頻率大約是21.5332Hz,對照表最接近的是F0,因此得知。


後來和小明學長討論發現了另一個問題,都是關於應該需要去取平均的地方。

1. 冠廷學長做Chroma的方式,如果是採用每根bin就map到跟它頻率最接近的那個音之後加起來,那麼事實上他可能忽略了一個問題,低頻的部分兩根bin中間可能有好多的音在那個範圍,在高頻的部分可能在兩個音的範圍中間會有好多根bin,因此會有每個音所擁有的bin會不同數量的問題,我們實驗用white noise當作input,真的發現chroma的顏色並沒有分布的很均勻。所以應該要讓每個音除以它所擁有的bin的個數,取平均。

2. 在我們新加的方法中,低頻的bin會有較多的partial,所以能量加到自己身上之後,應該也要除以partial的個數來取平均。雖然這樣當能量懸殊的時候還是會造成彼此相對的差異減少,不過總是比沒有做normalize來的正確一些。



[20091201]

用BWV1007前四小節去跑,發現wav chroma錯誤了。
1. 前兩個音SO(低)、RE的部分,推論是因為五度音的關係,f0相差1.5倍,因此倍頻重疊了,RE的部分能量被認為是 SO 的。
2. 後面四個音也錯了,變成都是LA,推測是因為frame size不夠大,造成 fft 後頻率域的resolution不夠高。

origin frame size : 2048

frame size : 4096

frame size : 8192

可以看出增加frame size以增加frequency的解析度,結果準確許多。
不過第二個音 RE 的部分為什麼chroma顯示出來是 LA 的能量最強呢,是因為 RE 和 LA 是五度音嗎?
但是觀察spectrum,發現440 Hz左右真的有一條能量強的partial,所以不只是 RE 和 LA 第一個重疊的倍頻880Hz所分配給 LA 的部分。
→ 440Hz是這裡的 RE(146.83Hz) 的三倍頻沒錯,之前誤以為是它的高八度 RE(293.66Hz) ,而它的三倍應該是880Hz,所以才會疑惑為什麼會有440Hz的強能量。(20091202)

(按圖可放大)
另外,SO 的能量一直很強,造成餘音的效果。雖然譜上看起來是單音的樂曲,但是實際上是多音。可能是因為樂器的特性,第三個partial的能量特別強。

目前把頻率域的值map到chroma gram的方法是,準備一個10個八度音的frequency tabel,然後就去對和哪個pitch最接近,再map到chroma vector。
這樣的方法,五度音的partial能量會分配給兩者頻率較高的那一個。ex. RE (293.66Hz)的第三個partial、LA(440Hz)的第二個partial,大約是880Hz,而880Hz對照frequency tabel是LA。
但是學長也提到,如果採用傳統f0 detection的投票方法,那麼五度音的重疊partial能量會分配給兩者頻率較低的那一個音。

學長建議,接下來有兩條路。
第一條路,去解決五度音在chroma vector上表現的問題。
另一條路就是略過五度音的問題,找個沒有五度音的片段,往下找DTW在對譜時所展現的特性,也就是找DTW在對錯譜前後的參數變化情況。



[20091128]

把DTW 的matrix印出來。
本來是要印成文字檔,但是實在不好觀察,所以就做了另一個可以輸出成HTML的版本,這樣可以用簡單的方式去讓印出來的tabel上色和排列。

不過table真的很大,光是一分多鐘的dtw table的txt檔案,就可以達到450MB左右。
以下是用BWV1007前四小節的結果。

type 1 :




type 2 :


粉紅色底的格子是代表dtw找出來的path。



[20091124]

標音檔的SOP(手稿)

工作畫面
上方是cool edit,左邊是cue list(Desc欄寫pitch),下方是catwalk,主要是拿來顯示譜。


[20091122]

標好了巴哈無伴奏大提琴BWV 1007 Prelude,大約兩分五十秒,655個音,655個cue。
每個cue我都給他一樣的長度(4096個sample),因為要抓住那個音是哪個瞬間出現的有點難,所以後來決定去抓換音的瞬間,因為換音耳朵比較好辨認,所以我想起頭音的時間點就設cue的中點。

小筆記:
1. 20小節的地方音檔或譜似乎有錯,
音聽起來是do# la mi fa so mi fa so
譜是do# la do re mi do re mi
觀察DTW的時候可以注意一下這地方。
(應該是midi錯,因為去找過youtube上面的影片聽過跟wav是一樣的)
2. 發現mi不知道為什麼波形amplitude都比較大
3. 同一個音連續出現的話有點難聽出onset,所以是看波型來標。

之後,用之前的java程式去跑跑看,在作DTW一直出現例外 java.lang.OutOfMemoryError: Java heap space,有試著逐步幫JVM加大他的記憶體,但是還是出現一樣的例外。
所以我就想知道這樣的長度DTW到底需要多大的記憶體,就用學長之前的C#程式去跑,發現DTW大概吃掉1.5G左右的記憶體。可是給JVM這麼大的記憶體參數,會顯示無法建立的訊息。

目前wav的frame size是沿用學長的2048 overlap 512,想改成4096 overlap 2048,這樣可以減少frame的數量。此外midi是用一個tick當作一個frame,所以frame的數量很大。因此兩者所構成的DTW matrix使用的空間是很大的。



[20091112]

論文報告
An Efficient Multiscale Approach to Audio Synchronization
投影片



[20091023]

讀cue的程式寫好了,用 java去改寫,因為想說之前的chroma部分也是用java來做。
結果大概如下圖,測試的是原本語音的檔案。



因為我們的目的是要知道onset,所以對於cue來說,我們需要的就只是某個cue的起始時間。所以學長建議我,在幫音樂wav標onset的時候,cue的長度用很短就可以了。

現在我先著手標記巴哈無伴奏BWV1007的onset,因為它是單一樂器,而且它的節奏不會很快,可能會比較容易。現在覺得有個問題就是...要抓住並判斷音出現的那瞬間真的有點難@@


[20091006]

為了可以在wav上面標記出正確的onset作為比對資料,和小明學長去了吳老師實驗室詢問了一下,知道了可以用cool edit直接在wav檔裡面記錄cue list,方法很簡單,就是用滑鼠選取這個cue的範圍,然後按下F8就可以了。

學姊也給了一隻他們之前寫的程式給我,是用VC6+MFC環境寫的關係,還有它的output有用到資料庫,我的電腦上執行不起來,所以想說自己來改寫一個。


[20090924]

論文報告
Polyphonic Audio Matching and Alignment for Music Retrieval
投影片


[20090924]

學長的程式已經轉換到java完畢。
以前的程式架構,是每個步驟都是分散手動進行。


然後我現在把它整合在一起。

Improvement :
1. 整合、連貫各個project的功能。
2. 自行從GUI選擇讀取的檔案,不再受限於固定名稱。
3. draw onset frames
4. 可以使上下兩個scroll bar同步移動方便對照


程式畫面和流程 :



[20090908]

學長的MidiParser專案轉換到java已完成,得到的結果也和學長的一致。bug仍然是出在byte的問題,不過由於上次的經驗,這次解決就快多了。

這個專案的功用是:讀取midi file並分析,得到midi的chroma,也輸入了上個步驟得到的wav chroma,將兩個chroma做DTW,最後輸出onset的資料。

另外發現學長midi的delta-time(variable-length quantity)算法好像有些錯誤。這部分還需要find out。

→ 學長沒有錯,是我誤解code的意思。 (20090909)

[20090831]

首先確定JAVA和C的input stream對於wav值都是使用同樣排列方法。


使用上次說的網站的方法去做會有問題,因為它這樣出來的值全部都會是正數,這樣不是我們想要的結果。所以我們要偵測第二個byte的highest bit是0還是1,如果是1的話,代表這是一個負數,所以我們在幫int的最高和第二高的byte補上1。

由此得到的int就是我們要的sample。和MATLAB的值對照過,兩者是相同的。



另外這是如果我們每一個sample想用short去存的方法。(最初是用short)



比起最之前的寫法,是多了把在smaple裡的lower byte & 0xff 這個步驟,因為這樣可以先確保他會先轉換成是一個positive的int,再轉換成short,這樣值就不會錯。如果直接轉換的話,他可能會認為byte值是負的然後就轉換到一個不正確的short,之後higher byte再往左移8 bit之後合併數值會有問題。之後也確認了這個方法與MATLAB的值一致。

最後使用的是網路上找的java FFT code,學長使用的FFT code的結果,虛部會差一個正負號,但是因為我們用的是能量值所以不會影響到chroma。不過我不確定我找的那個是不是open source,能否自由使用...

能解決這個問題感謝DNA與小明學長的幫忙。接著我開始來改MIDI Parser的部分,找到了java有提供javax.sound.midi這個package,試看看能不能拿來在這個部分使用。


[20090824]

把兩邊程式的FFT結果印出來,發現值真的不同,著手改寫冠廷學長使用的c# FFT sourse code改成JAVA,錯誤還是存在。後來小明學長建議用MATLAB裡的wavread還有fft function去做,把從MATLAB得到的wav還有fft值分別和C#、JAVA讀到的wav之後用MATLAB fft做的結果去比較。

結果是發現JAVA的是在讀取wav檔的值就有錯了,每一個frame裡錯誤的個數、index都不一定,錯誤的element值和正確的值相差的都是256的倍數,目前測試結果最大可差別到256*8=2048。猜想可能是overflow之類的問題。

Google到這個網址,Reading and Writing Wav Files in Java,它說因為JAVA不像C語言,沒有unsigned type的設計,都是two's Complement,所以使用java的File-IO得到的資料還要經過處理,他提供的解法是比如說2 bytes的short 就用4 bytes的int來代替,int用long來代替。這個可能就是我們的問題所在,會用此方法來試試看。



[20090818]

與冠廷學長交接之後,開始著手改寫程式從C#轉到JAVA,這是為了將來可以使用在authoring tool上。目前改寫至可以運作的部分有:
1. Read wav file → FFT → Chroma Vector
2. Music Library

但是比對我的程式和學長的程式對同一個wav檔案所轉出來的chroma,發現能量最高(=1, because of normalization) 的地方在某一時間區段是不同的,後來覺得只比對能量=1的地方好像不是很好,所以以下是用圖片來呈現。發現c#的結果乾淨許多…

c#







java






由於學長程式的FFT是使用c#的open source code,我目前java的版本也是先使用外面找的java code,所以推測可能是在FFT這步驟出現不同所以導致結果不一致。老師建議把先FFT的結果印出來作驗證。



[20090714 by SCREAM Lab, NCKU, Taiwan. 位於 下午 6:08]

在MIREX2008裡面有一個比賽項目叫做Score Alignment, 網址如下:

MIREX2008 Score Alignment or Score Following

其實就是冠廷學長的論文其中的一部分. 冠廷用的是Chroma Feature, 其論文我們過一陣子再Post出來, 但是我們一貫的討論可以在下面看到:

冠廷的Polyphonic Music Information Retrieval

這個問題對我們很重要, 不過一般的Score Alignment做的要是能從頭Follow到尾, 也就是冠廷做的. 研究上當然是要如此完整, 但是假如以短時間內能用到我們要做的應用, 那麼是可以有一些妥協的. 比如說, 我們可以讓使用者把一段Wave框起來, 在讓它來對Target的譜子, 而且一次只要對一部分的譜就好, 例如四小節, 八小節, 長短就看我們的演算法的好壞.

這個串今天由我來起個頭, 接下來就由小聽來接續. 我建議可以將冠廷學長的方法先弄起來, 然後找其他人的論文來Implement, 久了後, 相信會越做越好, 也許有一天我們也可以去參加比賽.

另外就是Score Alignment會是Authoring tool的一部分.


44 則留言:

SCREAMLab 提到...

喔喔!
多年前, 我從INTEL system轉到Motorola System時遇到類似的問題. 因為一個word裡, High與Low的位置先後不同的問題.

SCREAMLab 提到...

純研究, 應該可以用.

如我說的, 冠廷學長有做一版MIDI parser, 問他一下吧!

Vivian 提到...

冠廷學長有給我他的c# MIDI Parser,目前就是在看他的code,但是能讀取的midi格式似乎有一些限制。
所以想說有些功能java有提供function可以用,某些對應的功能可以改成用他們提供的也許會比較沒有額外的問題。

SCREAMLab 提到...

"學長midi的delta-time(variable-length quantity)算法好像有些錯誤"

這個假如你星期四還沒看懂, 星期五找我一下.

Vivian 提到...

噢噢 我知道了...之前想錯方向
謝謝老師!

SCREAMLab 提到...

Do you find anything not reasonable about the score alignment algorithm?

Per my previous opinion, please find a method so that we can do 分段對譜 or something similar.

SCREAMLab 提到...

現在我們要進行分段對譜的工作了, 最緊單的方式是根據DTW的error大小決定是否align出了錯而需要以新的且正確的點再出發. 有不清楚之處, 我們可以找時間討論一下.

另外可以將MIDI那個track zoom一下, 讓上下同步再捲動視窗時可以看到align的點也是同步的嗎?

SCREAMLab 提到...

一段時間沒更新了, 有進度嗎?

Vivian 提到...

前陣子和小明學長去吳老師實驗室問過,知道了cool edit可以將wav標記cue的list,那邊的學姐也給我了一隻他們的程式,它可以把cue的資訊從wav檔裡面讀出來。
不過可能因為這隻程式是用VC6+MFC環境寫的關係,還有它的output有用到資料庫,我在我的電腦上執行不起來。

目前已在trace code,研究他是怎麼讀cue的資料,然後接下來自己把這個功能寫一次。

ARWEN 提到...

我知道要抓準onset時間有點難, 不過有時答案的模稜兩可的, 這時我想需要人工去看一下, 並記錄一下program找出來的與你標記的差多少.

另外, cooledit是語音的, polyphonic signals也可以用嗎?

Vivian 提到...

cool edit只是來幫我們記錄cue的工具,不是自動的,cue是在哪個時間開始、哪個時間結束都是用手動來標記,所以不限定用在語音訊號上。現在onset我是用耳朵去聽,會盡量抓到那一瞬間,但是要完全準不太可能...
如果是polyphonic的音樂,節奏快或是有很多樂器一起出現的話,可能就會比較難判斷出onset了

87showmin 提到...

我以為看cooledit的波形圖就可以知道onset大約在哪了,耳朵是輔助。

Vivian 提到...

波型圖看不出來onset在哪邊,因為在演奏裡每個音之間沒有明顯的中斷,波形圖看起來也沒有明顯的波谷。
有時候在換音的可能區間選了小片段聽來找onset,會覺得有兩個同時音出現的感覺,有些難以判斷,不過我會盡力在一個frame size的誤差之內標對。

SCREAMLab 提到...

請問一下, Bach的曲子標完了嗎? 可以用嗎?

Vivian 提到...

標完了,已更新文章。

SCREAMLab 提到...

可以先對個20~30秒, 看看會不會可以跑.

既然midi會錯, 那麼看看是哪裡錯以及錯了會發生什麼事. 當然也可以自己製造一些可預期的錯誤.

明天我可以看一下demo嗎?

SCREAMLab 提到...

mi會比較大聲? 也許是錄音本身的問題而已. 以前學長試郭一些改善對譜的方法, 我們可以根據實例來看看.

另外請你設計一套簡單易懂的標準流程(SOP), 我可以請以後的專題生來開始標其他複雜一點的曲子.

87showmin 提到...

請問你指令是怎麼打的?我查到的資料有舉例:java -Xmx128m BigApp,其中-Xmx跟128m中間沒有空白也沒有等號。http://tinyurl.com/yzppezn, http://tinyurl.com/yzzc2er這裡有其他提示。

另外,原本是overlap 1/4,你改完後變成overlap 1/2,這樣frame數應該還是一樣多 ...

冠廷當時會把做過的DTW通通存下來應該是為了方便程式可以同時往前往後看對齊後的結果,可能還是要動一下他的記憶體架構,否則曲子一大還是會遇到這種情況。

Vivian 提到...

對,我是這樣打的。剛試了一下我指令的參數最大可以給-Xmx1436m,不過這應該會因為環境而不同。把曲子剪到一分多鐘去測試是可以跑的,我想目前就先用這樣的資料來做,記憶體的事情可能可以緩一點解決。

我是這樣算的(chroma feature sampling rate):
原本 44100/(2048-512) = 28.7 (Hz)
想改成 44100/(4098-2048) = 21.53(Hz)
是差不多,可是會少一點。因為之前看的paper都是將frame overlap 1/2,所以想說改成是不是比較好,不知道我這樣的想法有沒有問題呢?

87showmin 提到...

overlap取1/2或1/4其實都可以,不過frame size取太大的話會降低時間解析度,你可以都試試,看看結果有什麼不同。

當然,現階段你所關心的問題應該不是這個。

SCREAMLab 提到...

440很大, 我想因為他差不多是RE的三倍頻. 大提琴加拉琴不一定照著平均率來分配音高, 有時高一點, 有時低一點. 其實比較接近自然率. 這讓我有點為難, 因為照這樣來說, 似乎要做一下pitch/partial tracking後效果才會好, 不過我們再想想辦法, 因為後這者準確率也不高呀! 也許改一下chroma feature的做法會好一點.

我等你們想個兩天, 我們再來討論一次.

SCREAMLab 提到...

我想要算很久的原因多半是因為你是一根根bin來算的, 以精確度來講, 當然好. 若要快一點, 也許就先Quantized成一個八度12個音, 也就是把每個音名當成1個bin. 當然, 在Quanitzed時也許需要再考慮能量要如何分配到相鄰的bin的問題, 我覺得用Window的寬度來做應該就很好了.

當然, 低音的部分會多一點, 不過只要這12個vector是平均的就應該可以了.

這點有問題我們可以再討論.

SCREAMLab 提到...

另外就是, 我覺得要對得準, 單靠wave與midi來做也許不夠.

以前冠廷學長做過先把MIDI轉成Wave, 再用兩個wave來比, 效果有時是會變好的.

這讓我想到最近大家在聊的Instrument model. 假如我們目前主要對付獨奏樂器曲目的話, 那麼靠著preview或者說是Profile一遍這曲子後, 建出該錄音所用的樂器的音色model, 然後將MIDI轉wave時用此一音色來轉, 那麼應該會更準確. 畢竟, 我們是有在合成的技術的, 所以只要建出此instrument model就可以了, 而且我認為此一model事實上只要八九不離時就夠了. 以前義崧就已經完成胡琴音色庫的擷取了, 只是polyphonic上會在麻煩一點而已.

所以我在想, 我們是不是找AAA與胤霖一起來談一下, 做一個建Polyphonic獨奏錄音音色庫的演算法呢?

也許繞一下路後, 之後會更容易做.

SCREAMLab 提到...

起始的地方好像沒對到.

後面的部分有一部分看起來不錯, 下形騎我們一起來看一下. 圖太小, 我的眼睛頗吃力.

87showmin 提到...

我爬了一下你之前的文章,查到之所以要將frame size加大到4096,是為了增加頻域的解析度,來解決[20091201]這天的問題。不過用在BWM1007卻有這個問題,你知道這首歌的tempo是多少嗎?在tempo=60的情況下16分音符會佔1/4秒,也就是44100/4 = 11025個samples,理論上4096的時間解析度夠用,就算是判斷錯了,也不可能誤差到10個frame (也就是你說的一秒)。如果連續的16分音符會導致大誤差出現,是否是程式在找onset時累積了誤差呢?

SCREAMLab 提到...

我請小聽做兩件事:

1. 檢查是否音符有對到. 這個交叉檢查midi檔就知道了.
2. 假如上面沒問題, 那麼看看onset誤差超過我們定的上限值的, 抓出來看一下.

我希望從DTW cost就可以知道上面兩種問題, 除非這辦不到, 才回去查. 然後改變DTW Tracking的設定後在重新Track, 希望可以找到更好的路徑.

我懷疑showmin說的問題是因為音符根本不對了. 那麼這個onset也就沒意義了.

SCREAMLab 提到...

還有, 我記得DTW對於Duration兩者差太多的狀況會出問題. 所以當拉的人把長音拉太長, 那麼就毀了.

這是一個我們需要想一下解決辦法的問題.

D. N. A. 提到...

有關老師提到的 兩者duration差太多會毀掉

我想是跟 dtw的使用形式有關

如果是像是LCS的最初形式
S(x,y) = max(S(x-1,y-1), S(x,y-1), S(x-1,y)) 這樣的話,它永遠會找到最佳解 如果找到的解依然不夠好 那表示這兩個組合也不可能有更好的matching

但是我記得 dtw的使用形式有的是S(x,y) =max(S(x-1,y-1), S(x-2,y-1), S(x-1,y-2)) 或是其他缺乏S(x-1,y)與S(x,y-1)項的形態 那就會有老師說的問題 因為它能match的時間差距變小了

雖然打了這麼多字 要是我搞錯問題的話 請跟我說 囧

87showmin 提到...

你週五做出來的實驗中,Onset誤差也大概在50-60ms,我還是很好奇用傳統chroma feature套用到他的test data會能有多糟。

Vivian 提到...

to DNA:
DTW的type不同會影響結果,最基本的type (x-1,y) (x-1,y-1) (x,y-1) 理論上會有最佳解,在5/21中作了測試,也發現是這樣沒錯。
但是如果用audio轉成chroma去對midi直接轉成的chroma,另一個(x-1,y-1) (x-2,y-1) (x-1,y-2)在6/4的實驗結果中,卻有比較好的效果,這是因為這個type比較greedy,三種可能的path的方向都比較接近45度角,而且每一步走的距離也比較大,所以比較能避開一些雜訊之類的。所以我想如果是audio chroma和midi chroma去比,那用第二種會比較適合,如果是兩個本質上比較相近的sequence,要找出很好很好的對應位置,那就用第一種應該會比較好。

to showmin:
你說的 "他的test data" 是指?

D. N. A. 提到...

我發現一個丁點 我回了一個二月份的問題XDDD
因為我一直以為是六月二號的問題lol
小聽不要扁我Q__Q

---我是分隔線---

的確包含S(x-1,y-2), S(x-2,y-1)項目的dtw對雜訊比較不敏感 但若是要解決時間差距過大的問題或許可以考慮

1.加入S(x,y-1)與S(x-1,y)項 讓它成為五項

2.事先做一層過濾 再用基本型式的lcs去比對

3.不要理我,這是二月份的問題了lol

LUDWIG 提到...

以前冠廷學長在的時候,我跟他提過,Chroma跟DTW之間要有創新,後來我們用的是base semitone的方式。那時我對採用什麼樣的DTW distance有一點想改,但是卻沒想到要怎麼改。事情就托下來,現在是小聽可以想想的時候了。

上星期我跟胤霖在想如何判斷一個H是否是pure harmonic時,我說過,可以用一組Harmonic Mask把Peaks拿掉,剩餘的能量大的就應該不是了。

現在看到PSD,我覺得實在有點類似的觀念。

我再強調目標:

對於拉錯彈錯的,我只是要避開他們,但是讓其他演奏對的部分對得上就好。因為最後我們是會回到原來的Spectrogram去找參數的。至於Bach那無伴奏的問題要怎麼解決呢?請小聽把問題寫下來,大家來想一下吧!

SCREAMLab 提到...

請問測試音檔是midi產生的孩是我們之前從CD抓下的呢?

過去我們做過一些利用midi音檔作的實驗,但是故意弄錯某些音,請問這個方法的表現如何?

Vivian 提到...

測試音檔是傅尼葉的CD。

可能要測試一下才知道,會另外以調整過的midi合出來的wav來作實驗。

SCREAMLab 提到...

我在想,雖然用NMF方出來的結果會有助於你的研究,但是如何把NMF放進DTW終究還是需要一個適合的演算法。

畢竟,NMF算是MONOPHONIC的特徵,你要如何作呢?是把分開的NMF家再一起再作DTW,還是把SCORE分開來對NMF資訊?還是其他呢?

請你想一下,下星期說一下。你可以私下來找我,或是把想法放上來,或是其他?

LUDWIG 提到...

小聽:

假如NMF的結果分出了N個Templates,那麼我們可以說這是一個Multi-Dimensional的Data,只是這個Multi-Dimension跟一般的N-by-M Matrix,以Chroma來說,其實我們可以把它看成是一個12-by-T(此地我換成T是意味這是代表時間)的矩陣。兩者有一點不一樣。但是意義上差不多。當然,我們可以犧牲一點記憶體,把NMF的W and X弄成一個regular的N-by-M Matrix。
試想一下,樂譜本身其實原來也是Multi-Dimensional,不是嗎? 狀況跟NMF的結果差其實一樣。一樣是音高加上音長。音高就是template。但是過去,因為我們用的是Chroma Features,所以硬是將樂譜弄成一個跟Chroma一樣的12-by-T的矩陣。

所以,只要設法把樂譜跟NMF的表示方式弄成一樣,就容易用DTW來比對了。因為音都分開了,所以優勢很多,因為資訊變多了,所以請善用此一優勢,不要隨便音為方便而drop掉任何資訊。

87showmin 提到...

memo一下剛的討論。

因為已經有樂譜資訊,所以其實可以將樂譜有出現的音高資訊加到NMF的cost function來force它的template們只會在這些音高的partials上有能量。在這樣的前提下,如果NMF分出來的template剛好都是單音(而且沒有重複出現),那就可以直接拿 X 來與樂譜比對了。X維度是時間,Y維度是tempalte(音高)個數。

相對的,如果要用現成胤霖的方法會有個問題,就是她會將一個音高分成數個template,要用到對譜上面的話必須要先合併同一個音高的X, W,那將會是個問題。

SCREAMLab 提到...

還記得Bach的起頭音是好幾個音和再一起,可是錄音中,這本來應該一起撥出的音卻前後差了有快一秒鐘。

也許用 NM可以解決這個問題。

Vivian 提到...

對,因為音可以藉由NMF分開了,我們可以做單一pitch的alignment。詳細的星期四再跟老師討論~

SCREAMLab 提到...

您有注意到嗎?這裡面八度音的問題很嚴重喔!

但是因為你知道譜了,所以應該有解。

但是,我看了結果,很疑惑,因為261 and 391的能量都沒找到,為什麼呢?

87showmin 提到...

12/27的例子中也有五度音跟八度音,為何就沒有出現F0不見的問題呢?真的只是F0能量非最高的關係嗎?

Vivian 提到...

是因為有一些情況才會這樣,詳情已更新在上面。

匿名 提到...

請問我要抓出MIDI檔的音頻 要用什麼程式抓出她的音軌

Vivian 提到...

要看你是使用什麼語言,google看看有沒有人提供open source。如果你和我一樣是用MATLAB,文章中有library的連結。不然就是了解midi格式之後,自己寫parser。