鋼琴從古到今一直是樂曲常用的樂器,但是鋼琴聲因為同時包含了打擊與絃樂器的特色,因此不易使用FM等方式進行實作。Csound支援Phase Vocoder,且在QuteCsound中也有工具能夠分析傳入的WAV檔案。使用Phase Vocoder就可以輕易模擬出鋼琴的聲音。
Phase Vocoder
Phase Vocoder技術建立於傅利葉轉換的基礎上,需要一些專門的數學來推導,在本文章中就不去探討。
Csound 鋼琴聲實作
在Csound中,提供多種Phase Vocoder相關的opcode,例如本文使用的「pvoc」就是其中之一。將鋼琴聲的WAV檔使用QuteCsound的PVANAL工具,進行分析,轉成pvx檔案,再由pvoc運算子讀取進來。使用pvoc,可以在維持聲音音色的情況下,任意調整聲音的長度與音調。
idur init p3*1.5
ifC4 init cpspch(8.00)
ifC4u init cpspch(8.01)
ifD4 init cpspch(8.02)
ifD4u init cpspch(8.03)
ifE4 init cpspch(8.04)
ifF4 init cpspch(8.05)
ifF4u init cpspch(8.06)
ifG4 init cpspch(8.07)
ifG4u init cpspch(8.08)
ifA4 init cpspch(8.09)
ifA4u init cpspch(8.10)
ifB4 init cpspch(8.11)
ifreq init cpspch(p4)
ipvx init 3.00
ipitchInt = floor(p4)
ipitchDecimal = p4 - ipitchInt
krr = 1
if(ipitchDecimal>=0&&ipitchDecimal<0.005) then
ktime line 0, idur, ipvx
krr = ifreq/ifC4
assig pvoc ktime, krr, "piano_C4_2.pvx"
elseif(ipitchDecimal>=0.005&&ipitchDecimal<0.015) then
ktime line 0, idur, ipvx
krr = ifreq/ifC4u
assig pvoc ktime, krr, "piano_C4u_2.pvx"
elseif(ipitchDecimal>=0.015&&ipitchDecimal<0.025) then
ktime line 0, idur, ipvx
krr = ifreq/ifD4
assig pvoc ktime, krr, "piano_D4_2.pvx"
elseif(ipitchDecimal>=0.025&&ipitchDecimal<0.035) then
ktime line 0, idur, ipvx
krr = ifreq/ifD4u
assig pvoc ktime, krr, "piano_D4u_2.pvx"
elseif(ipitchDecimal>=0.035&&ipitchDecimal<0.045) then
ktime line 0, idur, ipvx
krr = ifreq/ifE4
assig pvoc ktime, krr, "piano_E4_2.pvx"
elseif(ipitchDecimal>=0.045&&ipitchDecimal<0.055) then
ktime line 0, idur, ipvx
krr = ifreq/ifF4
assig pvoc ktime, krr, "piano_F4_2.pvx"
elseif(ipitchDecimal>=0.055&&ipitchDecimal<0.065) then
ktime line 0, idur, ipvx
krr = ifreq/ifF4u
assig pvoc ktime, krr, "piano_F4u_2.pvx"
elseif(ipitchDecimal>=0.065&&ipitchDecimal<0.075) then
ktime line 0, idur, ipvx
krr = ifreq/ifG4
assig pvoc ktime, krr, "piano_G4_2.pvx"
elseif(ipitchDecimal>=0.075&&ipitchDecimal<0.085) then
ktime line 0, idur, ipvx
krr = ifreq/ifG4u
assig pvoc ktime, krr, "piano_G4u_2.pvx"
elseif(ipitchDecimal>=0.085&&ipitchDecimal<0.095) then
ktime line 0, idur, ipvx
krr = ifreq/ifA4
assig pvoc ktime, krr, "piano_A4_2.pvx"
elseif(ipitchDecimal>=0.095&&ipitchDecimal<0.105) then
ktime line 0, idur, ipvx
krr = ifreq/ifA4u
assig pvoc ktime, krr, "piano_A4u_2.pvx"
else
ktime line 0, idur, ipvx
krr = ifreq/ifB4
assig pvoc ktime, krr, "piano_B4_2.pvx"
endif
av linen 1, 0.05, p3, 0.05 ;ring the amplitude
assig = assig * av / krr
out assig, assig
如果要讓鋼琴聲音聽起來更渾厚,可以加入echo,讓前一個聲音可以稍微延續到下一個聲音,實作方式如下:
gasig init 0
instr 1
;piano
;p4=pitch
;p3=duration
idur init p3*1.5
ifC4 init cpspch(8.00)
ifC4u init cpspch(8.01)
ifD4 init cpspch(8.02)
ifD4u init cpspch(8.03)
ifE4 init cpspch(8.04)
ifF4 init cpspch(8.05)
ifF4u init cpspch(8.06)
ifG4 init cpspch(8.07)
ifG4u init cpspch(8.08)
ifA4 init cpspch(8.09)
ifA4u init cpspch(8.10)
ifB4 init cpspch(8.11)
ifreq init cpspch(p4)
ipvx init 3.00
ipitchInt = floor(p4)
ipitchDecimal = p4 - ipitchInt
krr = 1
if(ipitchDecimal>=0&&ipitchDecimal<0.005) then
ktime line 0, idur, ipvx
krr = ifreq/ifC4
assig pvoc ktime, krr, "piano_C4_2.pvx"
elseif(ipitchDecimal>=0.005&&ipitchDecimal<0.015) then
ktime line 0, idur, ipvx
krr = ifreq/ifC4u
assig pvoc ktime, krr, "piano_C4u_2.pvx"
elseif(ipitchDecimal>=0.015&&ipitchDecimal<0.025) then
ktime line 0, idur, ipvx
krr = ifreq/ifD4
assig pvoc ktime, krr, "piano_D4_2.pvx"
elseif(ipitchDecimal>=0.025&&ipitchDecimal<0.035) then
ktime line 0, idur, ipvx
krr = ifreq/ifD4u
assig pvoc ktime, krr, "piano_D4u_2.pvx"
elseif(ipitchDecimal>=0.035&&ipitchDecimal<0.045) then
ktime line 0, idur, ipvx
krr = ifreq/ifE4
assig pvoc ktime, krr, "piano_E4_2.pvx"
elseif(ipitchDecimal>=0.045&&ipitchDecimal<0.055) then
ktime line 0, idur, ipvx
krr = ifreq/ifF4
assig pvoc ktime, krr, "piano_F4_2.pvx"
elseif(ipitchDecimal>=0.055&&ipitchDecimal<0.065) then
ktime line 0, idur, ipvx
krr = ifreq/ifF4u
assig pvoc ktime, krr, "piano_F4u_2.pvx"
elseif(ipitchDecimal>=0.065&&ipitchDecimal<0.075) then
ktime line 0, idur, ipvx
krr = ifreq/ifG4
assig pvoc ktime, krr, "piano_G4_2.pvx"
elseif(ipitchDecimal>=0.075&&ipitchDecimal<0.085) then
ktime line 0, idur, ipvx
krr = ifreq/ifD4
assig pvoc ktime, ifreq/ifG4u, "piano_G4u_2.pvx"
elseif(ipitchDecimal>=0.085&&ipitchDecimal<0.095) then
ktime line 0, idur, ipvx
krr = ifreq/ifA4
assig pvoc ktime, krr, "piano_A4_2.pvx"
elseif(ipitchDecimal>=0.095&&ipitchDecimal<0.105) then
ktime line 0, idur, ipvx
krr = ifreq/ifA4u
assig pvoc ktime, krr, "piano_A4u_2.pvx"
else
ktime line 0, idur, ipvx
krr = ifreq/ifB4
assig pvoc ktime, krr, "piano_B4_2.pvx"
endif
av linen 1, 0.05, p3, 0.05 ;ring the amplitude
assig = assig * av / krr
gasig = gasig + assig
;out assig, assig
endin
instr 99
gaecho delayr 0.1 ;delay line length, echo delay 0.1 seconds
gaout = gaecho*0.4 + gasig ;echo amplitude reduce to 0.4 ratio
delayw gaout ;write gaout into delay line
out gaout,gaout ;out delay line
gasig = 0 ;
endin