社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

用 Python 进行音乐创作

Python中文社区 • 5 年前 • 828 次点击  

文/世界上的霸主  图片来源于网络
投稿邮箱:pythonpost@163.com

前言

上期留了尾,卖了关子。接着上回用 Python 播放多声轨 MIDI 文件音乐继续为您说。

如今,许多人尝试用计算机创作乐器,普遍方法是随机生成一段音乐,和现有曲子的相似度进行打分,一个分值范围内算通过。我也这么做?不,这样做效率低下,随机生成几千首只有一首通过,计算速度也十分低下(超级电脑不说),筛选出的曲子也不一定好听。

我用什么方法呢?今天,我们要了解许多令人发指的乐理,以及计算令人发指的乐理公式。准备好笔纸了么?今天,就让我,带您进入美妙复杂的音乐殿堂吧!

乐理的代码:

废话不多说,先来讲讲“音程”:

音程及其算法:

看着玄乎,其实是最简单,它表示两音之间的“距离其基本单位称为度在mido中,以“半音”为基本单位,接下来,我都采用半音计数

1:小二度
2:大二度/减三度
3:小三度/增二度
4:大三度/减四度
5:纯四度/增三度
6:增四度/减五度
7:纯五度/减六度
8:小六度/增五度
9:大六度/减七度
10:小七度/增六度
11:大七度
单位:半音

除了四度和五度(八度不算)度按减小大增来计算 没有基准。但,一般“大度”为最佳选择。不信可以尝试下,是大三度好听,还是小三度好听。除四度以外,只有理论上的增减,不会说增三度,只说纯四度。因此,只需做11个函数就行了。比如说小二度:

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  

我花了整天肝枯燥的做简单计算 的代码,想看去我的Github:

https://github.com/duoduo666/mido-Barock/blob/master/turn%20note/yin_cheng.py

记得star哦。

三和弦:

三和弦有四类,大三和弦,小三和弦,增三和弦,减三和弦七和弦较复杂,有兴趣读者可自己搜搜。

大三和弦结构是:大三度+小三度小三和弦结构是:小三度+大三度增三和弦结构是:大三度+大三度,减三和弦结构是: 小三度+小三度最舒服的和弦是大三和弦,最恶心的和弦是减三和弦。

因此,我们只要知道一个音,就可以求出其他的音。我在这贴大三和弦代码:

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.            ····#同上

转位

三和弦有四类,每类都有3种“形态”,称为“转位”,分别是:第一转位(原位),第二转位(4转位),第三转位(46转位)

每次转位把最低音(根音)提八度(12半音)为大家理解,我画了大三和弦转位图(单位:半音)。

X代表根音(最低音),Y代表三音(中间音),Z代表五音(最高音)清楚多了吧,其余三个皆如此。

脑筋都不用动了,直接出转换代码。(转换位大4和弦)

·····  #前面有
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  

但是,种类太多我花了10天夸张) 完成,这不贴了,有兴趣的到我的GitHub

https://github.com/duoduo666/mido-Barock/tree/master/turn%20note

配上和弦(音程):

哇!可以求和弦和、音程了!鼓掌!动动脑筋,在myin基础上,更改下,给曲子配上和弦:

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)  

有太多的“音程”、“和弦”,这不可能全贴,看完整代码?去:

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]。这形式在巴洛克时期全都是,实现函数:

def dao(yin):                 #计算倒影
    a = yin[0] * 2
    daoyin = []
    for i in yin:
        b = a - i
        daoyin.append(b)
    return daoyin 

首音乘2,以此减接下来的数,得出数组(list)

倒影难道音高不变了?总要变吧。动动脑经,得出答案:

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

以base位基音,得出xuanlu倒影。

分拆和弦、时间:

在巴洛克时期,总会把主题(主旋律)拆开来,分成个主题。但你不知道用户会输入怎样的节奏型。再动动脑筋,就可以把旋律按节拍的不同拆开。

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:]  
同理,分拆时间:
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:]  

这样你就可以获取任意一段的代码和时间了。

计算机计算乐曲实现:

有小白生气了,算法还不讲!别急,算法这不就来了?那最经典的BWV772举例:

此图版权为作者所有!我们用蓝色框匡主题,绿色框匡副题和配旋律。用黄色代表倒影我们用数学的语言总结下:(我画的)

有个特别的。所有的曲子都要“解决”,“解决”是较复杂,有兴趣的可以搜搜。这我自己做了个个性化 解决,大家可以拿来用。

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)  

此解决方法严禁抄袭。到这,相信只要智商>100,就可以写出来。但,许多的小白还是不会写。为了照顾小白,我原来想在这里贴,但是实在太长,放不下。请去我的barok文件下载(https://github.com/duoduo666/mido-Barock/tree/master/barok)。

结语

如今,您可以通过计算机计算出巴洛克时期的二部曲的开场事了,只要有个好旋律,就可以出个好曲子。但其他的种类呢?可以买本《巴赫创意曲集》,一共30首曲子,每首曲子都很经典。可以自己挨个分析写代码哦。

如果有问题,请到我的github的issue模块哦:

https://github.com/duoduo666

赞 赏 作 者



Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。


投稿邮箱:pythonpost@163.com


投稿点击阅读原文   喜欢文章,点个在看

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/55852
 
828 次点击