顯示原始碼/* Project: 31 equal temperament of the 5th harmonic Author: Kong Kao Advisor: Prof. James Ma Last update: January 11, 2008 */ <CsoundSynthesizer> <CsOptions> </CsOptions> <CsInstruments> ; Initialize the global variables. sr = 44100 kr = 4410 ksmps = 10 nchnls = 1 giBase = 110 ; frequency (Hz) of the lowest pitch giStep = 5^(1/31) ; frequency ratio of the interval ; function tables giftScale = 10 giftResolve = 11 /* Find the index of the 1st possible interval to which the given interval tends */ opcode Resolve, i, i iScale xin iIndex = 0 iCurrent = 0 iCount = 0 L1: if(iCurrent == iScale) goto L2 iDest table iIndex, giftResolve if(iDest > -1) then iIndex = iIndex + 1 goto L1 endif iIndex = iIndex + 1 iCurrent = iCurrent + 1 goto L1 L2: xout iIndex endop /* Search the index of the 1st occurence of the given value in the function table. I defined it to be reusable. :P */ opcode Search, i, ii ift, iTarget xin iIndex = 0 iLength tableng ift SSearch: iTemp table iIndex, ift if(iTemp==iTarget) goto ESearch loop_lt iIndex, 1, iLength, SSearch ESearch: if(iIndex==iLength) then iIndex = -1 endif xout iIndex endop /* Convert scale into pitch number. Register is considered, so the pitch number may exceed number of steps a cycle has. Can be reusable for other temperament by simple modification */ opcode scale2pitch, i, i iScale xin iPitch table iScale, giftScale, 0, 0, 1 xout iPitch + 31*floor(iScale/16) endop ; A simple instrument that utters a note with given duration instr 2 iAmp = ampdb(80) iFreq = giBase * giStep^p4 ift = p5 iSustain = (p3>0.5) ? 0.4 : p3*0.8 kAmpEnv expseg 0.01, 0.01, 1, iSustain, 0.5, p3-iSustain, 0.001 kFreqEnv lfo 0.005, 100, 2 aSig oscil iAmp*kAmpEnv, iFreq*(1+kFreqEnv), ift out aSig endin ; The main program instr 3 iCount = 1 ; number of notes iRange = 3 ; the max interval a succesion in a voice may have iStart = 1 ; the start-time of the next note iOverlap = 1.5 ; the ratio of which a note would have during its time iPrevLow = 16 ; the 1st note of the lower voice, pre-decided iPrevHigh = 24 ; the 1st note of the higherer voice, pre-decided schedule 2, 0, 2, 31 schedule 2, 0, 2, 48 MelodyGen: iPrevLowPN scale2pitch iPrevLow iPrevHighPN scale2pitch iPrevHigh PitchGen: iLow = iPrevLow + (2*floor(rnd(2))-1)*iRange if(iLow < 0) goto PitchGen iHigh = iPrevHigh + (2*floor(rnd(2))-1)*iRange if(iHigh < iLow) goto PitchGen iLowPN scale2pitch iLow iResolve Resolve (iPrevHighPN - iPrevLowPN)%31 Resolve: iInterval table iResolve, giftResolve if(iInterval==-1) goto Decided /* There are 2 cases to match this condition: 1. The previous interval is consonant 2. There's no resolution for the mode For each case, checking the resolution is not necessary anymore, so just jump to using a randomly decided pitch. */ iTemp Search giftScale, (iLowPN + iInterval)%31 if(iTemp>-1) then iHigh = iTemp QQ: ; Correct the problem that a larger-than-PO interval may cause. if(iPrevHigh-iHigh > 8) then iHigh = iHigh + 16 goto QQ endif goto Decided endif iResolve = iResolve + 1 goto Resolve Decided: if(iHigh > 32) goto PitchGen ; Make sure the register would not go too high iHighPN scale2pitch iHigh iConsonance Resolve (iHighPN - iLowPN)%31 iConsonance table iConsonance, giftResolve ; Though not always, consonant intervals would have a higher probability ; to have longer time value. iDur = rnd(1)*1 + ((iConsonance==-1) ? 0.5 : 0) schedule 2, iStart, iDur*iOverlap, iLowPN, 2 schedule 2, iStart, iDur*iOverlap, iHighPN, 1 iStart = iStart + iDur iPrevLow = iLow iPrevHigh = iHigh iCount = iCount + 1 /* ending condition There's a preservation of 2 seconds for disonant intervals to resolve, but that does not guarantee the music would not exceed the length given. */ if(iConsonance>-1 || iStart<p3-2) goto MelodyGen endin </CsInstruments> <CsScore> ; Waveforms f 1 0 65536 10 20 1 2 1 4 0 1 f 2 0 65536 9 \ 1 20 0 \ 2.5 3 33 \ 7 1 90 ; Scale f 10 0 16 -2 \ 0 2 3 5 8 9 11 13 17 19 21 23 25 26 28 30 /* Resolution rule Each line shows the tendency toward which the interval drift. -1 ends the tendency list of that interval For example, the 1st line shows that unison is consonant, the 2nd line shows the interval of 1 step tends to be unison, and the 6th line shows the interval of 5 steps tends to be 3 or 8 steps. */ f 11 0 64 -2 \ -1 \ 0 -1 \ 3 -1 \ -1 \ 3 -1 \ 3 8 -1 \ 3 8 -1 \ 8 -1 \ -1 \ 8 10 -1 \ -1 \ 10 13 -1 \ 10 13 -1 \ -1 \ 13 -1 \ 13 -1 \ 13 19 -1 \ 19 -1 \ 19 -1 \ -1 \ 19 21 -1 \ -1 \ 21 -1 \ 24 -1 \ -1 \ -1 \ 25 -1 \ 28 -1 \ -1 \ -1 \ 31 -1 \ i 3 0 60 e </CsScore> </CsoundSynthesizer>
DescriptionThis project shows one probability for dividing the traditional major 17th in just intonation, which has the frequency ratio of 5, into 31 steps. For each step the ratio would be 5^(1/31). In this project, not all 31 steps are used because I was also trying to experiment with a system of tonality and scale.
While reading the code, always note the difference between scale and pitch number: the former means the order within the scale, while the latter means the number of steps. Variables that presents pitch number would have postfix "PN" within its name.
Term to be usedStep: the smallest interval in this temperament, frequency ratio of 5^(1/31) Scale: the mode used in this piece (not all 31 pitches are used here) SD(Scale degree): the order(begin at 0) which the pitch has within the scale PN(Pitch number): number of steps between the pitch and the lowest note PO(pseudo-octave): the interval whose frequency is 5:1 Cycle: a complete scale within a PO Problems unsolvedThere's no guarantee that adding a PO to a consonant interval makes a consonant interval. I don't know the way to dynamically decide the length of output file. For now, a long enough p3 for i-statement is used. 怎麼算出哪幾個音是和諧音呢?照理說平均律裡除了需要定義的八度之外是不會有符合純率的和諧音的,但是人耳其實可以接受有些許誤差的和諧音,所以就可以這樣算出來(以JavaScript為例):
function ETConsonance(ratio, divider) { var str = '<table border="1"><tr><td> </td>'; var ratioArr = new Array(); for(var i = 1; i <= divider; i++) { ratioArr[i] = Math.pow(ratio,i/divider); str += '<th>' + i + '</th>'; } str += '</tr>'; for(var j = 1; j < 10; j++) { str += '<tr><th>' + j + '</th>'; for(i = 1; i <= divider; i++) { var times = j * ratioArr[i]; var style = (Math.abs(times-Math.round(times))<0.05) ? ' style="font-weight: bold;"' : ''; str += '<td' + style + '>' + times.toString().substr(0, 5) + '</td>'; } str += '</tr>'; } document.writeln(str); } ETConsonance(5, 31); // 換成2和12就可以得到平常用的12-EDO,你可能會很驚訝3和8跟純律的差距竟是這麼大
結果就會是:
如上,粗體字就是可以考慮的"接近"和諧的音程。如第三音的六倍頻接近基準音的七倍,即3個最小音程的頻率比接近7:6;依此類推8個最小音程的頻率比接近3:2
至於建構在主音上要怎麼配置音階,我參考了12平均律中大調音階的一些現象:
3和4(半因數)都是和諧音程,但是與主音相差三個和四個半音的兩個音並不會同時出現 do到fa的關係同於sol到高音do的關係(馬老師提到的某種對稱性,我忘記專有名詞了..QQ) 由第一點可知會造成"風格"的音階通常不會把所有跟主音成和諧關係的所有音級都用進去;至於第二點我則決定不在此次使用(但是我另外有考慮到不同於大調音階,而是改用反向對稱的方式)。
但是目前為止仍然有一些其他的問題。首先由於一個音階的循環(又稱
假八度pseudo-octave ,於本例中頻率比是5,以下簡稱PO)並不是2的倍數,所以把某個音移高一個PO所得到的音並不一定跟原本的狀態類似。舉例來說某兩個音的頻率成7:6的關係,若將高音者一高一個PO之後會得到35:6,原則上雖然仍接近整數比,但是和諧度卻是變低了。「和諧度變低」的另一個佐證是把傳統西樂的兩個完全五度相疊會得到不太和諧的大二度,而若由此推論,可知移高傳統的八度也會造成和諧度變低,只是因為2是最小的質數,所以和諧度的差異沒有那麼大。(事實上,隨著音程的增大,不和諧的感覺也會由於低音的泛音不足以與高音者產生交互作用而減少)
其他發現:12-EDO中,若X和Y成和諧關係(半音數3, 4, 5, 7, 8, 9),則將其中一音移高和移低大三度的結果勢必至少有一仍是和諧。
後記: 馬老師說我這學期可以用這個抵其他的作業。花了整整兩天證明自己仍然是個菜鳥,很多想要的功能都弄不出來。很難得的這次寫程式雖然不太順,但寫得還蠻平心靜氣的(也許是因為剛好穿著資工系服的關係^^|||b)。我想當初跟學長姐們一起學Csound的時候,其實我並沒有比較厲害或是花了比較少的時間,只是因為比較習慣寫程式而且有自信可以做完想要做的功能,所以壓力比較小吧。看樣子下學期還是要跟著上Csound才好(當然是期中之後再說XD)iJigg 我一直連不上,shopping前幾天也說她連不到Blog上面的內嵌播放器..總之我後來還是用經由Hans教的方法:把Box.net 當免空用 話說這篇花了我兩個小時(HTML碼就接近11KB...orz),有點想乾脆拿來當論文題材XD..不過音律的問題大概早在幾百年前就被研究到爛掉了,就算是電腦應用上也..也許來個任意律制的自動作曲? 然後我還邀請了馬老師來看這篇..希望推論過程不會被批說太慘(其實看了幾遍之後就覺得寫這樣的東西還蠻小兒科的)......
... read more