純音手工特調:用 Python 做聲音加法合成

類比合成器上常可見到幾款基本波形,用以構成更複雜的聲音。事實上,只要秘方在手,全部基本波形都可以用 sine wave 純音組合而成。

之前提過一個單頻率可以產生某一個音高的聲音。其實大部份樂器發出的聲音都用一組特定頻率構成每個音高,而用上不同的組合秘方就可以產生不同音色(timbre)。

Timbre /ˈtambə/: The character or quality of a musical or vocal sound (Oxford English Dictionary)

Photo by Nature Zen on Unsplash

泛音(harmonics)的比例是音色變化的重要一環。我們要找到基音/基頻(fundamental frequency)及其整數倍數頻率之間的音量比例。

小提琴的聲音

先看看一個小提琴的 A440 音,基音是 440 Hz 。在此之上聲音裏還混有一個 880 Hz (440×2), 一個 1320 Hz (440×3), 一個 1760 Hz (440×4) 如此類推。聲音分析工具可以找出下圖中的秘方:音量比例(amplitude ratio)。(先別理會震音啦

頻譜分析(spectral analysis)得出的小提琴音色秘方
分析用了此小段小提琴錄音

簡單合成後,聲音是這樣的:

簡陋的加法合成產生的小提琴音

雖不像小提琴,但跟原來的 sine wave 純音也有一段距離。

A simple sine wave

把 sine wave 純音混合成新聲音叫「加法合成」(additive synthesis)。下面我們試用 Python 一步步製作。

Python 裏的加法合成

我們從 import library 開始。IPython顯示聲音播放器,matplotlib製作圖表,numpy處理數據陣列,math提供數學 function 。另外我們先定義取樣率 sampling rate sr

準備妥當

之前我們見過用 Python 產生純 sine wave。把其放進 makesine() function,重複使用就方便一點。

產生 sine wave 的 function

然後我們就可以多叫 makesine() 幾次,產生指定頻率 freq 和長度 dur 的聲音了。結果可以用 numpy.concatenate() 放到一起輸出。

試試 makesine()

基本的純音聽來也像樣。接着我們可以製作整數倍數關係的音頻,再疊加起來。這裏用了 freq*ii1 開始,每次加 1 。每個音頻都用上 amplist 裏指定的音量。疊好了就放到 out

用加法合成調出幾種基本音形

好了,之前說到的基本音形在此,只用簡陋的加法合成器產生,用了首 10 個泛音的音量。(我太懶,不理會第 11 之後的泛音啦

Sine wave 就只有一個泛音
Square wave 只有單數泛音
Sawtooth wave 泛音一個比一個弱
Triangle wave 也只有單數泛音,漸弱較明顯

再看看之前的小提琴音⋯⋯

簡陋的小提琴音

同樣以 440 Hz 為基音,用上不同的泛音比例,聽起來也有明顯分別。

旋律製作

準備工夫做好,我們可以做個 pitch-frequency 轉換器:

MIDI 音高比頻率方便多了

還有個旋律播放機來處理一列音 notes 和長度 durs 的組合,再指定泛音比例 harmonics

用上之前的 function 分工合作

旋律來了!這裏 p 是要播的音, d 是每個音的長度(放快 4 倍),而 h 是泛音音量。

認得出是甚麼旋律嗎?

大概聽起來像 80 年代?(而其實是 90 年代的產物

加法合成也有點費時失事,連電腦也花不少功夫,以往因運算資源缺乏更甚。像拿原色顏料手工調色一樣,加法合成可以給 developer/musician 很大的自由,但現成聲音便捷得多,也更受歡迎。

下次我們再談其他編程工具和軟件,可以方便一點的用到現成的聲音再處理。

--

--

Chuck-jee Chau 周卓之
電腦音樂研究筆記 Computer Music Research Notes

Lecturer/Musician at Hong Kong, made an “Intro to Computer Music” course at CUHK, appears as a collaborative pianist/percussionist in shows 大學講師,以向學生推廣電腦音樂研究為己任