前言
上期留了尾,賣了關子。接著上回用 Python 播放多聲軌 MIDI 文件音樂繼續為您說。
如今,許多人嘗試用計算機創作樂器,普遍方法是隨機生成一段音樂,和現有曲子的相似度進行打分,一個分值範圍內算通過。我也這麼做?不,這樣做效率低下,隨機生成幾千首隻有一首通過,計算速度也十分低下(超級電腦不說),篩選出的曲子也不一定好聽。
我用什麼方法呢?今天,我們要了解許多令人髮指的樂理,以及計算令人髮指的樂理公式。準備好筆紙了麼?今天,就讓我,帶您進入美妙複雜的音樂殿堂吧!
樂理的代碼:
廢話不多說,先來講講“音程”:
音程及其算法:
看著玄乎,其實是最簡單,它表示兩音之間的“距離,其基本單位稱為度。在mido中,
以“半音”為基本單位,接下來,我都採用半音計數。1:小二度2:大二度/減三度3:小三度/增二度4:大三度/減四度5:純四度/增三度6:增四度/減五度7:純五度/減六度8:小六度/增五度9:大六度/減七度10:小七度/增六度11:大七度(單位:半音)
除了四度和五度(八度不算),度按減小大增來計算,沒有基準 。但,一般“大度”為最佳選擇。不信可以嘗試下,是大三度好聽,還是小三度好聽。除四度以外,只有理論上的增減,不會說增三度,只說純四度。因此,只需做11個函數就行了。比如說小二度:
<code>1.def sd_two(low=None,high=None): #小二度
2. if type(low) == str:
3. ···#就是轉換,前面的代碼都寫過
4. yin = []
5. if low and high == None:
6. high = low + 1
7. if high and low == None:
8. low = high - 1
9. yin.append(low)
10. yin.append(high)
11. return yin /<code>
我花了整天肝枯燥的做簡單計算 的代碼,想看去我的Github:
https://github.com/duoduo666/mido-Barock/blob/master/turn%20note/yin_cheng.py
記得star哦。
三和絃:
三和絃有四類,大三和絃,小三和絃,增三和絃,減三和絃。七和絃較複雜,有興趣讀者可自己搜搜。
大三和絃結構是:大三度+小三度。小三和絃結構是:小三度+大三度。增三和絃結構是:大三度+大三度,減三和絃結構是:小三度+小三度。最舒服的和絃是大三和絃,最噁心的和絃是減三和絃。
因此,我們只要知道一個音,就可以求出其他的音。我在這貼大三和絃代碼:
<code>1.def b_three(geng=None,zhong=None,wu=None):
2. yin = []
3. if geng and zhong == None and wu == None: #知道根音
4. zhong = geng + 4
5. wu = zhong + 3
6. yin.append(geng)
7. yin.append(zhong)
8. yin.append(wu)
9. return yin
10. if zhong and geng == None and wu == None: #知道中音
11. geng = zhong - 4
12. wu = zhong + 3
13. ····#同上
14. if wu and geng == None and zhong == None: #知道五音
15. zhong = wu - 3
16. geng = zhong - 4
17. ····#同上/<code>
轉位
三和絃有四類,每類都有3種“形態”,稱為“轉位”,分別是:
第一轉位(原位),第二轉位(4轉位),第三轉位(46轉位)每次轉位把最低音(根音)提八度(12半音)。為大家理解,我畫了大三和絃轉位圖(單位:半音)。
X代表根音(最低音),Y代表三音(中間音),Z代表五音(最高音)。清楚多了吧,其餘三個皆如此。
腦筋都不用動了,直接出轉換代碼。(轉換位大4和絃)
<code>····· #前面有
2. yin = []
3. if geng and zhong and wu: #若是三個都有
4. if zhong - geng == 4 and wu - zhong == 3: #若是第一轉為(三和絃)
5. geng += 12
6. yin.append(zhong)
7. yin.append(wu)
8. yin.append(geng)
9. return yin
10. if zhong - geng == 5 and wu - zhong == 4: #若是第三轉為(46和絃)
11. wu -= 12
12. yin.append(wu)
13. yin.append(geng)
14. yin.append(zhong)
15. return yin
16. if zhong - geng == 3 and wu - zhong == 5:
17. return True /<code>
但是,種類太多,我花了10天(誇張) 完成,這不貼了,有興趣的到我的GitHub
https://github.com/duoduo666/mido-Barock/tree/master/turn%20note
配上和絃(音程):
哇!可以求和絃和、音程了!鼓掌!。動動腦筋,在myin基礎上,更改下,給曲子配上和絃:
<code>1. def myin(fu,pai,time=120,du=None,chord=None,high=64,note="low",yue=2):
2. #和聲版
3. pig = int(beat(time)) #int取整,time要求整數
4. for i in range(len(pai)):
5. if type(pai[i]) == list:
6. ··· #上篇文章有,看看
7. else:
8. if chord == None and du == None:
9. ··· #上篇文章有,看看
10. else:
11. #和絃
12. if chord == "dasan": #大三和絃
13. if note == "low":
14. fu[i] = b_three(fu[i])
15. elif note == "zhong":
16. fu[i] = b_three(zhong=fu[i])
17. elif note == "wu":
18. fu[i] = b_three(wu=fu[i])
19. ····· #此處省略一千行
20.
21. #音程(度)
22. if du == "xiaoer": #小二度
23. if note == "low":
24. fu[i] = sd_two(fu[i])
25. if note == "high":
26. fu[i] = sd_two(high=fu[i])
27. ····#此處省略一千行
28.
29. #循環
30. for x in range(len(fu[i])):
31. yin(fu[i][x],pai[i]*pig,liang=high,unit=tra[x],qi=yue) /<code>
有太多的“音程”、“和絃”,這不可能全貼,看完整代碼?去:
https://github.com/duoduo666/mido-Barock/blob/master/play%20note/play%20note(basic).py
慶祝一下,我用這函數,給《瑪麗有隻小山羊》配了和絃和音程,只有你沒想到,沒有我做不出,去這裡(https://github.com/duoduo666/mido-Barock/tree/master/mary)聽聽。
巴洛克曲子算法及實現:
巴洛克時期有許多不同的種類曲子,二部曲,三部曲,四部曲,賓格,賦格……數不過來,不同種類的曲子有不同形式。今天我們實現二部曲。二部曲有很多形式,單開式,雙起式,加厚式……我們挑個簡單的,“單開式”。
《巴赫二部創意曲》第一首就是講這個。講之前,要貼幾段代碼:
倒影:
打個比方:[3,4,5]的倒影就是[3,2,1]。這形式在巴洛克時期全都是,實現函數:
<code>def dao(yin): #計算倒影
a = yin[0] * 2
daoyin = []
for i in yin:
b = a - i
daoyin.append(b)
return daoyin /<code>
首音乘2,以此減接下來的數,得出數組(list)
倒影難道音高不變了?總要變吧。動動腦經,得出答案:
<code>def getdao(xuanlu,base):
for i in range(len(xuanlu)):
if type(xuanlu[i]) == str:
xuanlu[i] = num(xuanlu[i])
if type(base) == str:
base = num(base)
xuanlu = dao(xuanlu)
high = base - xuanlu[0]
for i in range(len(xuanlu)):
xuanlu[i] += high
return xuanlu/<code>
以base位基音,得出xuanlu倒影。
分拆和絃、時間:
在巴洛克時期,總會把主題(主旋律)拆開來,分成個主題。但你不知道用戶會輸入怎樣的節奏型。再動動腦筋,就可以把旋律按節拍的不同拆開。
<code>1. def getlu(first,second,ind):
2. s = 0
3. c = 0
4. for i in range(1,len(second)):
5. if second[i] != second[s]:
6. c += 1
7. if c == ind:
8. return first[s:i]
9. else:
10. s = i
11. return first[s:] /<code>
同理,分拆時間:
<code>1. def gettime(paizi,ind):
2. s = 0
3. c = 0
4. for i in range(1,len(paizi)):
5. if paizi[i] != paizi[s]:
6. c += 1
7. if c == ind:
8. return paizi[s:i]
9. else:
10. s = i
11. return paizi[s:] /<code>
這樣你就可以獲取任意一段的代碼和時間了。
計算機計算樂曲實現:
有小白生氣了,算法還不講!別急,算法這不就來了?那最經典的BWV772舉例:
此圖版權為作者所有!我們用藍色框匡主題,綠色框匡副題和配旋律。用黃色代表倒影。我們用數學的語言總結下:(我畫的)
有個特別的。所有的曲子都要“解決”,“解決”是較複雜,有興趣的可以搜搜。這我自己做了個個性化 解決,大家可以拿來用。
<code>lastyin = [b_three(".do"),b_three(".mi"),b_three(".so"),b_three("do"),b_three("mi"),b_three("so"),'so','mi','do',"do","si"]
lastpai = [xxxx,xxxx,xxxx,xxxx,xxxx,xxxx,0.5,0.5,1.5,5]
myin(lastyin,lastpai,track=track4)
myin(["do"],[10],high=120) /<code>
此解決方法嚴禁抄襲。到這,相信只要智商>100,就可以寫出來。但,許多的小白還是不會寫。為了照顧小白,我原來想在這裡貼,但是實在太長,放不下。請去我的barok文件下載(https://github.com/duoduo666/mido-Barock/tree/master/barok)。
結語
如今,您可以通過計算機計算出巴洛克時期的二部曲的開場事了,只要有個好旋律,就可以出個好曲子。但其他的種類呢?可以買本《巴赫創意曲集》,一共30首曲子,每首曲子都很經典。可以自己挨個分析寫代碼哦。
閱讀更多 地表嘴強程序員 的文章