25 12月 2011

[心聲] 一個人的逆向工程 sprint!

絕大部份的知識都來自於閱讀。不論是紙本的閱讀,或是網頁的閱讀。因此,有很多專有名詞,我只在自己的心裡默默念過,而且來沒有聽過「真的人類」把這個字眼念出來時的聲音。

GNU 這個字,我心裡知道它念做「個怒」,但是第一次聽到的時候,還是怔了一下,忍不住問出口「請問你說哪個字啊?」

另一個,像 GUI 。我知道它是 Graphic User's Interface 的縮寫,所以一直都以「G.U.I.」三個字母分開的方式在心裡念它。結果第一次聽到原來軟體工程師們是念做「姑以」的時候,我也是當場一愣…

我之前知道 Hacker 們有一種活動,內容大概是幾個 Hackers 找一間飯店的地方,接下來在活動期間內的三餐、點心加宵夜都叫外送或是客房服務, Hacker 們就只要專心在房間裡面瘋狂地寫程式,其他的生活瑣事都不用管。

這種活動,叫 sprint !但也是直到最近,才在新竹 Python 使用者的聚會裡聽到有人把這個字活生生地念出來。

這麼說來,我好像常常在玩一個人的 sprint。今年的耶誕節,跟前幾年一樣,我又在聲音訊號的波型圖和頻譜圖中渡過。

於是,中午前就買好啤酒、冷凍饅頭、麥當勞的套餐、咖啡、幾個 7-11 的飯糰,還跑了一趟 DVD 出租店,準備躲開這個滿街都被情侶閃得一如白晝的節日,逆向推算出 Praat 這套軟體裡的共振峰 (formants) 是怎麼算出來的。

當然,現在有自己的公司,我可以用一句「在商言商」或是「企業本來就是以盈利為目的」來說服自己採用比較「下賤」的方法,直接去讀 Praat 的原始碼,然後用 python 語言再寫一遍,就拿來用了。說這種方法很賤,是因為如果這麼做的話,那比較像是把一篇英文寫的論文,我用中文翻譯一次,然後就把中文版的當做是自己的研究創作了。

如果我真的這麼做,那就太對不住 Praat 的原作者 Paul Boersma 和 David Weenink 兩位阿姆斯特丹大學的語音學家的心血。如果我是 Hack 他們的程式來自己玩耍的話,那也就算了。但現在既然是為了自己公司的產品做的,我就不該,也不能這麼做。我希望自己的公司永遠不會為了賺錢,而採用這種不尊重別人心血付出的方式做事。

推來算去,音頻訊號的數值運算量真是「巨量」啊!平常還沒有什麼感覺。可是每次做這類的運算的實驗時,就會覺得…啊…我的單核心 2GHz 的 CPU 好慢啊,實驗一開始, CPU 的負載就滿檔了…但話說回來…除了遊戲以外,一般人在個人電腦上的運用,真的非得需要「同時用上 CPU 的四個核心」嗎?

等待著程式計算的時候,等得愈久,心裡面那個吵著要「去買台新電腦吧!」的破財小惡魔 (spending deamon) 的聲音就愈來愈大…

daemon 這個字真好玩。它一方面是「惡魔」的意思,一方面在 Unix/Linux 的系統裡,指的是在背景運作的常駐程式。這麼一來,也就是說…我的心裡常駐著一個勸敗的破財小惡魔啊!

一手推開旁邊 HP Mini 小筆電的螢幕,一手拉開啤酒的拉環,我開始自言自語…
我:「這部電腦用好好的,也沒有壞掉啊…沒有壞掉,就不必換吧?」
小惡魔:「重點是你的人生啊!你的人生都在等待中浪費掉了耶!換台多核心的電腦吧!你就可以用一部電腦同時做好多事了呢!」
我:「雖然桌機現在滿載了,但我只要轉過身,就能用筆電上網,聽音樂啦!再說…我已經用區網加上 script 把桌機和兩部筆電串在同一個 NFS 的目錄裡了,如果有必要的話,配合檔案輸出,我也是有 "三核心" 的運算能力啊…」
小惡魔:「又是區網,又是檔案輸出的,這樣 I/O 的速度就被拖慢下來啦!」

眼看我節節敗退,就快要曲服在小惡魔的攻勢下時,電腦喇叭發出了電子味十足的兩聲「嗶嗶」!我忍不住咧開嘴角…

之前在家裡看 CSI 的時候,坐在旁邊的老媽看到節目裡的幹員們對著電腦指指點點就能說出一堆「好像很厲害的東西。」後,她說:「你就是想做像這樣的工作,是不是?」我說:「唔…其實我比較想當幫他們設計這些檢驗程式的人。」隨便幾根纖維就能說「根據光譜分析,這個人去過河邊的磚石廠!因為這幾根纖維上面沾有幾種淡水藻類的細胞還有一點微量燒結過的黏土…」哦!這種程式真是太酷,也太唬爛了!

雖然我不像 CSI 的劇組有那麼多的經費可以弄出和黑板一樣大的透明螢幕 (不過…為什麼要做透明的螢幕?我在不透明的螢幕上看數據就已經看得我每晚眼睛痛得像火燒了,這些幹員們每天盯著透明的螢幕看,怎麼不會下班前就必需要每個人配一隻可魯了呢?),但是我做了一件很「宅」的事情…我下載了 CSI 的電腦聲音特效檔,並且在我的演算程式裡加上一段,讓它在算出結果的時候,會發出和 CSI 裡的電腦一樣的「嗶嗶」兩聲!

我的目標,是希望能畫出像 Praat 的 spectrogram 裡的圖:
但是,因為不知道 Praat 裡把每次做傅立葉轉換的窗口設得多大,所以只好慢慢試,每次一個窗口大小,就畫一次圖,然後和上圖裡的內容一個畫素一個畫素地去比較。在那帥氣的「嗶嗶」兩聲後,我得到的是一個滿奇怪的數值… 290。我本來預期會是256 或是 384 ,最接近也應該是 288。但…既然它說最像的是下面這張 290 :
那…好吧,就 290。至少,我不用再繼續和小惡魔的內心戲,對吧?

繼續分析著畫出這張 290 的圖的數據,我發現…人真是太神奇了!為什麼我們竟然可以受過訓練去看到「不存在」的東西呢?用 290 來做數值計算的窗口尺寸的話,每個頻率之間將會存在著「極大」的空隙,但是呈現在上圖裡的時候,我們卻可以 (受過訓練後) 睜眼說瞎話地說:「上圖裡有五條橫線和一條底線…」然後再根據橫線的分佈說出「根據聲譜分析,這是一個男生的聲音,共振峰分佈在…」這種鬼話?

就著這筆數據修修改改,推推算算又聽了幾十次的「嗶嗶」以後,我可以把頻率分佈之間的空隙壓縮到極微小的程度,但要付出的代價就是…我會失去時間 (橫軸) 的數據。但時間上的數據在分辨子音時是很重要的資訊,所以一定要想辦法把它保留住才行…

唔…一時想不出辦法,抓抓頭…

又經過了幾十個「嗶嗶」以後,我弄出一個比較接近需求的東西…
盯著它瞧了老半天,又把它背後的數據貼上表格裡看了又看,算了又算。站起身來,在斗室裡背著走來來回回地轉了幾圈…不行啊…這樣湊出來的時間軸是用「比例」推出來的,精確度是值得懷疑的…

抬頭看看鐘,已經十點多了。記得上次看時間的時候,才下午兩點而已呢!看看桌上的空啤酒罐,空了一半的咖啡粉,垃圾桶裡各種食物的包裝…啊…其實我買飼料來吃也差不多吧,我根本就不記得下午吃這些食物的時候是什麼味道…

先去洗個澡吧…於是帶著滿腹的疑惑,踏入浴室…猜不透啊…真是猜不透啊…想不通吶…真是想不通吶…到底要怎麼樣才能算出共振峰的數值呢?在嘩啦嘩啦的水聲中,我離開了這個世界…

等我再恢復意識的時候,我正盯著手上的洗髮精看,而且心裡覺得很奇怪。奇怪的是…

1. 我突然有種感覺,像是就在不久前,我的手上也有洗髮精!
2. 如果剛剛我的手上就有洗髮精,那為什麼我的頭髮還是乾的?
3. 等等…我的頭髮不是乾的,但是摸起來很粗糙,還有點黑黑的東西沾在上面。
4. …

我還沒想清楚第 4 點讓我覺得奇怪的東西是什麼,我的手就開始在身上擦洗了起來…

4. 啊!等等!我知道這個感覺,我覺得我剛剛已經洗過身體了?!

唉…我知道這肯定不是第一次,而且也絕對不會是最後一次我用洗髮精洗了兩次身體,而且用「含炭洗面乳」洗頭髮。

專心,洗澡要專心!

再回到電腦前,我決定要轉換一下心情,於是翻出「帝國毀滅」這部德國片。是啦…我也知道在聖誕節的平安夜裡一個人看帝國毀滅這種片子真是很煞風景…不過,DVD 店裡其它好看的電影都已經被其他的宅宅租光啦…一個人將就一下啦,反正如果不是看這部電影,還不是在寫程式。相較之下,看電影已經是「宅度」比較輕一點點的活動了吧。

一百多分鐘的片子全部用德文發音,我覺得我如果把這部片子連續看三遍的話,就要開始覺得「好像聽得懂他在說什麼了!」這樣…應該對得住大學時上過的德文課了。

前半段裡戰況還不太慘烈的時候,大家講話都好有禮貌。一直 bitte 來 bitte 去的。這是德文的 "Please",但是它念起來就像歐洲人用英文念 "Peter"。結果每次電影裡一傳出 bitte,我就覺得像是在叫我。這樣過了五十多分鐘後,我想…這樣就能想像好像我有很多朋友在和我聊天,只是除了他們叫我的名字以外,其他的話我都聽不懂。這樣應該能驅走一些寂寞的感覺吧?!

半夜兩點,帶著一杯熱咖啡,再次回到工作桌。我決定,我要換方法。這次我不要再受限於保留時間軸這個想法,直接看它的頻譜分佈。從這裡去推算共振峰,應該是可行性比較高的做法。畢竟…共振峰的定義本來就是基於頻譜分佈而來的。

再次找到 Praat 繪製的 spectrum,長得像這個樣子:
唔…好醜,但又好真實。這讓我想到那個笑話:
Mary 問 Peter 說
"Jack says I am pretty, Bob says I am ugly. What do you think?"
(Jack 說我好美,但 Bob 說我很醜,你覺得呢?)

Peter 答道
"I think they are both right."
(我覺得他們說的都對啊。)

Mary 問
"What do you mean?"
(什麼意思?)

Peter 說
"I think you are pretty ugly."

一般做語音分析的,都暗地裡會想…「啊…真希望我們的聲譜能長得像光譜一樣漂亮,每一個峰值都很明顯…」(參考:Wikipedia 裡的光譜分佈圖)

也許,這就是為什麼光電產業都已經和生技一樣紅透半邊天了,搞聲音的還要像科學怪人一樣躲在隔音室裡做實驗吧。

粗估了一下工作量,嗯…只要寫出另一支程式來算 spectrum,然後再有另一支程式來餵給它各種參數的變化,然後第三隻程式來判斷畫出來的結果和 Praat 的 spectrum 像不像…哈…不難嘛…(我都快哭了~)

凌晨三點十二分。我覺得抓滑鼠的那隻手會很冷。這個經驗只有我有而已嗎?現在都已經有 USB 的加熱墊,怎麼沒有人想要弄一個 USB 的加熱滑鼠或是「附加熱手套」的 USB 滑鼠呢?好啦,我幫你們想好點子了,專利也讓你們去申請吧,誰快去弄一隻能加熱的滑鼠吧。

凌晨四點三十七分,已經開始分不清是真的聽到了「嗶嗶」的聲音,還是那只是我腦子裡的聲音。我算出來以下的結果…
我忍不住說「哦哦~你們長得真像!簡值就是同一個媽生的啊!」然後又彷彿聽到這兩張圖說「廢話~我們是同一個聲音檔的 spectrum 啊!」

我再動手比對了一次 F1, F2, F3, F4 和 F0 等等共振峰的峰值。唔…很接近了。誤差都在千分之一以下,以頻率來說,夠準了。

快點把相關的實驗數據寫下來。之前曾有一次,跑了一日夜以後才得到的數據,就在我的瘋狂科學家式的「啊哈哈哈哈~算出來啦~」笑聲中,把視窗關了…

我猜想…我應該不能稱呼自己是「科學家」。但…又好像也不能叫自己是「語言學家」,那些 "XX學家" 的稱謂,是留給拿到博士學位的人的。唔…像我這樣離開學術界 (還是被踢出學術界?),不會有大學或是國科會的經費補助,卻還一直做些賺不到錢的研究的人,要叫什麼?(神經病?)

做好實驗記錄,剩下,就是想個辦法來取代「動手測量」共振峰這個動作,就可以「咻」地一下子算出 F0 ~ F4 的值了!不過那個辦法是什麼呢?呃…我還沒想到,等我先去睡一下,起來再想吧…

真是個充實的平安夜,啊…我的眼睛痛死了… @@

0 意見:

張貼留言