Csound-003 樂器與樂譜
來自專欄我的創想與雜談4 人贊了文章
在上一期的教學之中,我們簡單講述了下如何使用Csound作為一個播放工具。而在這一期,我將通過分享一些簡單的代碼來讓各位同學創造一些屬於自己的聲音。但首先,我們要理清楚在Csound中的兩個概念:樂器與樂譜。在最早的csound中,樂器與樂譜是獨立開來的兩個文件,一個是.orc(Orchestra,管弦樂器),另一個是.sco(Score,樂譜)。雖然這兩個文件形式在後來的CsoundQT中消失了,但是CSD文件的結構仍然遵循這兩個文件的邏輯。
在這裡,我希望各位能打開自己的Csound,並把我所在文章中打入的代碼拷貝進去,從而了解Csound運行的過程。我將在代碼中打入充足的注釋來幫助大家學習。
首先,Csound的變數分為三種,a變數,k變數,以及i變數。
其中,a變數是更新速度=音頻採樣率(sr,sample rate)的變數,其速度非常快,但是對系統資源的要求更高,在一些音頻方面的應用可以使用。而k變數則是更新速度=控制更新率(kr,control rate)的變數,它的更新速度一般是採樣率的幾十分之一,也就是說它可以攜帶更新速率相比音頻採樣率慢的信息,它並不適合攜帶音頻信號,但是更省資源,適合傳輸adsr,lfo等信息。而i變數,則是每次更新速度等同於樂譜事件更新速度的信息,可以把它想像成一個定值,只有每次在收到新的樂譜信號的時候才會更新。其速度非常慢,而且每次變化都是跳變,不會包含任何的插值。一般情況下,在建立一個只能接受i變數的opcode時才會用到它。理解a,k,i這些變數是非常緩慢的過程,特別是迷一樣的i變數,如果現在看不懂是沒關係的,在之後的學習中,會有更多的例子來講述這些信息。
這是一段講述Csound結構的代碼,由於其除了注釋之外並沒有任何可運行的程序內容,所以本身只是一個初始化後的空程序。
如例1所示,有幾點值得記下來的部分:
在設置區域中,可以用代碼的形式調用MIDI驅動方式,以及輸入輸出的結構。
在<CsInstruments>下方,則是整個音頻系統的設置,sr = iarg 是現在整個系統中的音頻採樣率,在一般情況下設置為44100即可。在這裡,kr = iarg,是整個系統中的控制更新率。這兩個statement在極特殊的情況下會用樂譜信息來更新其對應的iarg,但是一般情況下輸入 sr = 44100, kr = 4410,是最保險的手段。
在新建每個csd文件中,sr和kr都是事先幫你輸好的。但是kr的表示方式是ksmps,其形式參數在默認中是32,也就是說,每經過32個採樣點後更新一次,用實際數據來說即是44100/32,也就是約1378的更新率。0dbfs代表了整個系統音頻信號的最大值,默認為1,以作者的個人習慣,一般是把它給去掉的,如果它等於1,任何在接下來的參數中大於1的音頻信號輸出到外部的話,都會過載。在此將這條statement去掉的話,只要數據不超過32768(16bit音頻的最大值)就不會爆音。
例1:
<CsoundSynthesizer>
<CsOptions>
;---------以下區域為設置
-odac -d ;激活實時輸出
;---------以上區域為設置
</CsOptions>
<CsInstruments>
sr = 44100 ;採樣率
ksmps = 32 ;控制更新率
nchnls = 2 ;現在所調用的輸出數
0dbfs = 1; 定義1為整個系統最響值,建議刪除
;---------以下區域為樂器寫作區域
;---------以上區域為樂器寫作區域
</CsInstruments>
<CsScore>
;---------以下區域為樂譜寫作區域
;---------以上區域為樂譜寫作區域
</CsScore>
</CsoundSynthesizer>
從例1中我們看到,整個代碼分為兩個大區域,一個是樂器區域,一個是樂譜區域。在之中我們可以打入一些信息讓整個csound跑起來。(例2)
例2:
<CsoundSynthesizer>
<CsOptions>
-odac -d
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
nchnls = 2
;---------以下區域為樂器寫作區域
instr 1;編號為1的樂器
a1 oscil 10000, 440 ;輸出a1,使用被稱為oscil的opcode,輸出振幅為10000,輸出頻率為440
outs a1, a1 ;輸出到,a1到第一個聲道,a1到第二個聲道
endin ;該樂器結束
instr 2;編號為2的樂器
a1 oscil 10000, 550 ;輸出a1,使用被稱為oscil的opcode,輸出振幅為10000,輸出頻率為440
outs a1, a1 ;輸出到,a1到第一個聲道,a1到第二個聲道
endin ;該樂器結束
instr 3;編號為3的樂器
a1 oscil 10000, 660 ;輸出a1,使用被稱為oscil的opcode,輸出振幅為10000,輸出頻率為440
outs a1, a1 ;輸出到,a1到第一個聲道,a1到第二個聲道
endin ;該樂器結束
;---------以上區域為樂器寫作區域
</CsInstruments>
<CsScore>
;---------以下區域為樂譜寫作區域
i 1 0 2 ;開啟編號為1的樂器,從0秒開始,運行2秒
i 2 2 2 ;開啟編號為2的樂器,從2秒開始,運行2秒
i 3 4 2 ;開啟編號為3的樂器,從4秒開始,運行2秒
;---------以上區域為樂譜寫作區域
</CsScore>
</CsoundSynthesizer>
當拷貝以上代碼到csoundqt並運行之後,就會得到音頻結果。
我們暫時不需要去管每個opcode的作用是什麼。從上面的例子中,我們可以清楚的看到,在樂器寫作區域中我們定義了3個樂器,編號分別為1,2,3。然後在樂譜寫作區域中我們定義了三個事件,把這三個樂器從0 2 4秒開始各開啟了2秒。由於我在樂器中通過使用oscil這個opcode讓它以440 550 660播放了三個正弦波,所以最後的結果聽起來就像一個三和弦的琶音。
需要注意的是,在樂器寫作區域,以及樂譜寫作區域中,各個參數的分割是不一樣的。以我剛剛使用的正弦波為例,我們可以仔細看一下每個opcode之間的區別。
instr 1;編號為1的樂器
a1 oscil 10000, 440 ;輸出a1,使用被稱為oscil的opcode,輸出振幅為10000,輸出頻率為440
outs a1, a1 ;輸出到,a1到第一個聲道,a1到第二個聲道
endin ;該樂器結束
i 1 0 2 ;開啟編號為1的樂器,從0秒開始,運行2秒
對比以上代碼即可發現,在樂器寫作區域中,必須要用逗號把各個參數分隔開。而在樂譜寫作區域中,只需要添加空格就可以把各個參數分割開來。此外,每個opcode的運行結構都不一致,必須用特定範圍的參數來填滿它的argument才能使它正確編譯。
總結:
Csound分為樂器部分與樂譜部分。
其中,樂器部分是讓csound緩存下之後需要調用的樂器,而樂譜部分則是給樂器命令,使它打開特定時間,從而使這個樂器發出聲響。這點和真實情況的管弦樂隊別無二致。所以,學習csound,首先需要理解這樣一個概念:創造樂器,並利用樂譜讓它演奏。
推薦閱讀:
※編程之道(英漢對照)
※DrRacket 的安裝與 SICP 的配置
※【必看】Android乾貨整理
※操作工永遠是對的!錯的是管理!!
※編程的思考 其一