想做个网站怎么做,网站用户体验比较,成华区微信网站建设公司,建英语网站目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境PC环境配置 模块实现1. 钢琴伴奏制作1#xff09;和弦的实现2#xff09;和弦级数转为当前调式音阶3#xff09;根据预置节奏生成伴奏 2. 乐句生成1#xff09;添加音符2#xff09;旋律生成3#xff09;节… 目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境PC环境配置 模块实现1. 钢琴伴奏制作1和弦的实现2和弦级数转为当前调式音阶3根据预置节奏生成伴奏 2. 乐句生成1添加音符2旋律生成3节奏生成 3. 贝斯伴奏制作1添加贝斯轨2预置贝斯轨 4. 汇总歌曲制作1日志模块2音乐可视化3Impromptu类 5. GUI设计1用户界面空间初始化2将控件绑定功能信号与槽的绑定 系统测试工程源代码下载其它资料下载 前言
本项目旨在实现上下文相关的即兴演奏音乐生成。用户可以通过选择主音调式和输入歌曲信息如BPM每分钟节拍数、弦级数和重复次数等参数来定制所要生成的音乐。
用户首先选择主音调式这将为生成的音乐设定一个基本的音乐调性。接着用户输入歌曲信息包括BPM、弦级数和重复次数等参数这些参数将决定音乐的节奏和结构。
基于用户选择的主音调式和输入的歌曲信息项目将通过算法生成上下文相关的即兴演奏音乐。音乐的旋律、和弦进行和节奏等元素将根据用户输入的参数进行自动调整以符合用户的要求。
通过这个项目用户可以根据自己的喜好和需求定制个性化的即兴演奏音乐。无需专业音乐知识用户只需选择主音调式和输入简单的歌曲信息便可以生成符合自己心情和风格的音乐作品。这为音乐创作和欣赏带来了更多的自由和乐趣。
总体设计
本部分包括系统整体结构图和系统流程图。
系统整体结构图
系统整体结构如图所示。 系统流程图
伴奏制作、即兴旋律生成的流程如图1所示贝斯模块及GUI (Graphical User Interface图形用户接口)制作流程如图2所示。 图1 伴奏制作、即兴旋律生成的流程 图2 贝斯模块及GUI制作流程 运行环境
本部分包括Python环境和PC环境配置。
Python 环境
需要Python 3.7及以上配置安装库包括hmmlearn、numpy、pypianoroll、pygame、mido、musthe、PyQt5、PyQt-tools (仅支持Windows) 在Windows cmd中使用以下命令:
pip install hmmlearn, numpy, pypianoroll, pygame, mido, musthe安装PyQt 5和PyQt- tools:
pip install sip
pip install PyQt5
pip install PyQt-tools将当前目录下的4.ui转换输出成4.py文件:
python -m PyQt5.uic.pyuic 4.ui -o 4.pyPC环境配置
本程序最终将打包成.exe在Windows环境下运行。安装能读取并播放MIDI文件程序的用户可自行查看生成文件反之在选项卡中选择“自动播放”选项播放生成的MIDI文件。
模块实现
本项目包括5个模块钢琴伴奏制作、乐句生成、贝斯伴奏制作、汇总歌曲制作和GUI设计下面分别给出各模块的功能介绍及相关代码。
1. 钢琴伴奏制作
用户选择调式、输入和弦级数后首先将和弦级数转换为和弦名称其次用musthe将和弦名称转换为对应音最后根据用户选择的预置节奏型向MIDI中的钢琴轨写入钢琴伴奏。
1和弦的实现
本部分代码完成添加和弦功能。
#midi_extended/Track.py中的TrackExtended类
def my_chorus_num(self, all_note, length, num1, velocity70, channel0, change1): #change为1表示级数调用索引音阶0表示和弦名称调用无需索引音阶base_note 60 #基音base_num 0delay 0for chord_note in all_note:for j in range(num):count 0for note in chord_note:note base_note base_num * 12 sum(self.scale[0:note]) if change else base_note base_num * 12 note - 1super().append(Message(note_off, notenote, velocityvelocity if count else velocity 10, time0 if count else round(0.96 * self.meta_time * length), channelchannel))count count 1 #设第一排为重拍2和弦级数转为当前调式音阶
将用户输入的和弦级数数字1~7转换为绝对的和弦名称再用musthe()方法将和弦名称转为当前调式下的音阶。
def change(self, num, key, mode, count4):#将和弦从数字更改为字符串d {C: 1, D: 2, E: 3, F: 4, G: 5, A: 6, B: 7}result []try:if type(num) int and 0 num 8:s musthe.Scale(musthe.Note(key), mode)scale []for i in range(len(s)):scale.append(str(s[i]))for i in range(count):try: #对音阶数7取余result.append(d[scale[(num - 1 2 * i) % 7][0]])except IndexError:#五声音阶的数目比较少可能会存在超出索引范围的现象对5取余result.append(d[scale[(num - 1 2 * i) % 5][0]])else:raise TypeError(num should be int from 1~7.)except NameError:return self.change(num, key, aeolian, count)return result3根据预置节奏生成伴奏
本项目为4/4拍和3/4拍的歌曲各提供了6种预置节奏型共12种节奏型的钢琴伴奏其中预置节奏型由日常演奏经验而得是常用的节奏型能适应大多数曲目。
def my_chorus_4_simple(self, chord_progression, type1, change1, circulation1): #4/4拍节奏预置def mode1(): #模式1if change:for chord in chord_progression:self.my_chorus(chord, 4)else:self.my_chorus_num(chord_progression, 4)def mode2(): #模式2if change:for chord in chord_progression:self.my_chorus(chord, 1, 1, 80)self.my_chorus(chord, 1, 1)self.my_chorus(chord, 1, 1, 60)self.my_chorus(chord, 0.5, 2)else:l len(chord_progression)for j in range(circulation):self.my_chorus_num([chord_progression[j % l]], 1, 1, 80)self.my_chorus_num([chord_progression[j % l]], 1, 1)self.my_chorus_num([chord_progression[j % l]], 1, 1, 60)self.my_chorus_num([chord_progression[j % l]], 0.5, 2)def mode3(): #模式3if change:for chord in chord_progression:self.my_chorus(chord, 1, 1, 80)self.my_chorus(chord, 1, 1)self.my_chorus(chord, 1.5, 1, 60)self.my_chorus(chord, 0.5)else:l len(chord_progression)for j in range(circulation):self.my_chorus_num([chord_progression[j % l]], 1, 1, 80)self.my_chorus_num([chord_progression[j % l]], 1, 1)self.my_chorus_num([chord_progression[j % l]], 1.5, 1, 60)self.my_chorus_num([chord_progression[j % l]], 0.5)def mode4(): #模式4if change:for chord in chord_progression:self.my_chorus(chord, 2, 1, 80)self.my_chorus(chord, 1.5, 1, 60)self.my_chorus(chord, 0.5)else:l len(chord_progression)for j in range(circulation):self.my_chorus_num([chord_progression[j % l]], 2, 1, 80)self.my_chorus_num([chord_progression[j % l]], 1.5, 1, 60)self.my_chorus_num([chord_progression[j % l]], 0.5)def mode5(): #模式5if change:for chord in chord_progression:self.my_chorus(chord, 0.5, 1, 80)self.my_chorus(chord, 0.5, 2)self.my_chorus(chord, 1)self.my_chorus(chord, 0.5, 1, 60)self.my_chorus(chord, 0.5, 2)else:l len(chord_progression)for j in range(circulation):self.my_chorus_num([chord_progression[j % l]], 0.5, 1, 80)self.my_chorus_num([chord_progression[j % l]], 0.5, 2)self.my_chorus_num([chord_progression[j % l]], 1)self.my_chorus_num([chord_progression[j % l]], 0.5, 1, 60)self.my_chorus_num([chord_progression[j % l]], 0.5, 2)def mode6(): #模式6if change:for chord in chord_progression:self.my_chorus(chord, 0.5, 1, 80)self.my_chorus(chord, 0.5, 2)self.my_chorus(chord, 0.25, 4)self.my_chorus(chord, 0.5, 1, 60)self.my_chorus(chord, 0.5, 1)self.my_chorus(chord, 0.25, 2)else:l len(chord_progression)for j in range(circulation):self.my_chorus_num([chord_progression[j % l]], 0.5, 1, 80)self.my_chorus_num([chord_progression[j % l]], 0.5, 2)self.my_chorus_num([chord_progression[j % l]], 0.25, 4)self.my_chorus_num([chord_progression[j % l]], 0.5, 1, 60)self.my_chorus_num([chord_progression[j % l]], 0.5, 1)self.my_chorus_num([chord_progression[j % l]], 0.25, 2)type_d {1: mode1, 2: mode2, 3: mode3, 4: mode4, 5: mode5, 6: mode6}type_d.get(type)()
def my_chorus_3_simple(self, chord_progression, type1, change1, circulation1): #3/4拍的预置def mode1(): #模式1if change:for chord in chord_progression:self.my_chorus(chord, 3)else:self.my_chorus_num(chord_progression, 3)def mode2(): #模式2if change:for chord in chord_progression:self.my_chorus(chord, 1, 1, 80)self.my_chorus(chord, 1, 2)else:l len(chord_progression)for j in range(circulation):self.my_chorus_num([chord_progression[j % l]], 1, 1, 80)self.my_chorus_num([chord_progression[j % l]], 1, 2)def mode3(): #模式3if change:for chord in chord_progression:self.my_chorus(chord, 1, 1, 80)self.my_chorus(chord, 0.5, 4)else:l len(chord_progression)for j in range(circulation):self.my_chorus_num([chord_progression[j % l]], 1, 1, 80)self.my_chorus_num([chord_progression[j % l]], 0.5, 4)def mode4(): #模式4if change:for chord in chord_progression:self.my_chorus(chord, 0.5, 1, 80)self.my_chorus(chord, 1)self.my_chorus(chord, 0.5, 3)else:l len(chord_progression)for j in range(circulation):self.my_chorus_num([chord_progression[j % l]], 0.5, 1, 80)self.my_chorus_num([chord_progression[j % l]], 1)self.my_chorus_num([chord_progression[j % l]], 0.5, 3)def mode5(): #模式5if change:for chord in chord_progression:self.my_chorus(chord, 1.5, 1, 80)self.my_chorus(chord, 0.5, 3)else:l len(chord_progression)for j in range(circulation):self.my_chorus_num([chord_progression[j % l]], 1.5, 1, 80)self.my_chorus_num([chord_progression[j % l]], 0.5, 3)def mode6(): #模式6if change:for chord in chord_progression:self.my_chorus(chord, 0.75, 1, 80)self.my_chorus(chord, 0.25)self.my_chorus(chord, 0.75)self.my_chorus(chord, 0.25)self.my_chorus(chord, 0.75)self.my_chorus(chord, 0.25)else:l len(chord_progression)for j in range(circulation):self.my_chorus_num([chord_progression[j % l]], 0.75, 1, 80)self.my_chorus_num([chord_progression[j % l]], 0.25)self.my_chorus_num([chord_progression[j % l]], 0.75)self.my_chorus_num([chord_progression[j % l]], 0.25)self.my_chorus_num([chord_progression[j % l]], 0.75)self.my_chorus_num([chord_progression[j % l]], 0.25)type_d {1: mode1, 2: mode2, 3: mode3, 4: mode4, 5: mode5, 6: mode6}type_d.get(type)()2. 乐句生成
使用hmmlearn利用马尔可夫模型生成旋律和节奏。其中旋律表示为数字17加上0和-11~7对应音阶中第17音(五声音阶对应五个音)0对应休止符-1对应延音音符节奏表示为数字1、2、4、8、16、32、 6、12、24分别表示全音符、二分音符、四分音符、八分音符等。
1添加音符
音轨内添加一个普通音符/休止符/延音音符的相关代码如下:
#向音轨内添加一个普通音符此函数由MusicCritique提供
def add_note(self, note, length, modulation0, base_num0, delay0, velocity90, scale[0, 2, 2, 1, 2, 2, 2, 1], channel0, pitch_type0, tremble_settingNone, bend_settingNone):bpm self.bpmbase_note 60 modulationif pitch_type 0: try:super().append(Message(note_on, notebase_note base_num * 12 sum(scale[0:note]), velocityvelocity, timeround(delay * self.meta_time), channelchannel))super().append(Message(note_off, notebase_note base_num * 12 sum(scale[0:note]), velocityvelocity, timeint(round(0.96 * self.meta_time * length)), channelchannel))except IndexError: #选中五声音阶时只有五个音而hmm最多生成七个音super().append(Message(note_on, notebase_note base_num * 12 sum(scale[0:note - 2]), velocityvelocity, timeround(delay * self.meta_time), channelchannel))super().append(Message(note_off, notebase_note base_num * 12 sum(scale[0:note - 2]), velocityvelocity, timeint(round(0.96 * self.meta_time * length)), channelchannel))elif pitch_type 1: #颤音try:pitch tremble_setting[pitch]wheel_times tremble_setting[wheel_times]super().append(Message(note_on, notebase_note base_num * 12 sum(scale[0:note]), velocityvelocity, timeround(delay * self.meta_time), channelchannel))for i in range(wheel_times):super().append(Message(pitchwheel, pitchpitch, timeround(0.96 * self.meta_time * length / (2 * wheel_times)), channelchannel))super().append(Message(pitchwheel, pitch0, time0, channelchannel))super().append(Message(pitchwheel, pitch-pitch, timeround(0.96 * self.meta_time * length / (2 * wheel_times)), channelchannel))super().append(Message(pitchwheel, pitch0, time0, channelchannel))super().append(Message(note_off, notebase_note base_num * 12 sum(scale[0:note]), velocityvelocity, time0, channelchannel))except:print(traceback.format_exc())elif pitch_type 2: try:pitch bend_setting[pitch]PASDA bend_setting[PASDA]
#结合PASDA(Prepare-Attack-Sustain-Decay-Aftermath)属性值实现MIDI滑音和颤音效果prepare_rate PASDA[0] / sum(PASDA)attack_rate PASDA[1] / sum(PASDA)sustain_rate PASDA[2] / sum(PASDA)decay_rate PASDA[3] / sum(PASDA)aftermath_rate PASDA[4] / sum(PASDA)super().append(Message(note_on, notebase_note base_num * 12 sum(scale[0:note]), velocityround(100 * velocity), timeround(delay * self.meta_time), channelchannel))super().append(Message(aftertouch, timeround(0.96 * self.meta_time * length * prepare_rate), channelchannel))super().append(Message(pitchwheel, pitchpitch, timeround(0.96 * self.meta_time * length * attack_rate), channelchannel))super().append(Message(aftertouch, timeround(0.96 * self.meta_time * length * sustain_rate), channelchannel))super().append(Message(pitchwheel, pitch0, timeround(0.96 * self.meta_time * length * decay_rate), channelchannel))super().append(Message(note_off, notebase_note base_num * 12 sum(scale[0:note]), velocityvelocity, timeround(0.96 * self.meta_time * length * aftermath_rate), channelchannel))except:print(traceback.format_exc())def add_rest(self, length, velocity80, channel0): #增加休止符super().append(Message(note_off, note0, velocityvelocity, timeround(0.96 * self.meta_time * length),channelchannel))def add_tenuto(self, length): #增加延音音符off super().pop() #list的最后一个音符note_offon super().pop() #list的最后一个音符note_onoff.time round(off.time 0.96 * self.meta_time * length)super().append(on)super().append(off)2旋律生成
相关代码如下
def hmmmelody():startprob np.array([0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.10, 0.00, 0.00]) #初始分布#状态转移矩阵由日常演奏经验得出transmat np.array([[0.05, 0.10, 0.20, 0.15, 0.20, 0.10, 0.05, 0.05, 0.10], [0.10, 0.05, 0.10, 0.20, 0.20, 0.10, 0.10, 0.05, 0.10], [0.20, 0.10, 0.05, 0.10, 0.10, 0.20, 0.10, 0.05, 0.10], [0.10, 0.10, 0.20, 0.05, 0.10, 0.10, 0.20, 0.05, 0.10], [0.10, 0.20, 0.10, 0.10, 0.05, 0.10, 0.20, 0.05, 0.10], [0.05, 0.10, 0.20, 0.25, 0.10, 0.05, 0.10, 0.05, 0.10], [0.05, 0.10, 0.20, 0.10, 0.25, 0.10, 0.05, 0.05, 0.10], [0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.16, 0.00], [0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.16, 0.00]])means np.array([[1], [2], [3], [4], [5], [6], [7], [0], [-1]])#covariance为协方差covars .000000000001 * np.tile(np.identity(1), (9, 1, 1)) #identity的参数1要和means每一行中列数对应#np.identity 制造对角阵使用np.tile把对角阵复制成4行1列1条的三维矩阵model hmm.GaussianHMM(n_components9, covariance_typefull)model.startprob_ startprobmodel.transmat_ transmatmodel.means_ meansmodel.covars_ covars#产生样本X, Z model.sample(50)m []for i in range(50):temp int(round(X[i, 0]))m.append(temp)#print(m)return m3节奏生成
相关代码如下
def hmmrhythm():#初始概率startprob np.array([0.15, 0.15, 0.20, 0.20, 0.00, 0.00, 0.20, 0.10, 0.00])transmat np.array([[0.15, 0.15, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10], [0.20, 0.20, 0.20, 0.10, 0.05, 0.05, 0.10, 0.05, 0.05], [0.05, 0.20, 0.20, 0.20, 0.10, 0.05, 0.05, 0.10, 0.05], [0.05, 0.05, 0.20, 0.20, 0.20, 0.10, 0.05, 0.05, 0.10], [0.10, 0.05, 0.05, 0.20, 0.20, 0.20, 0.10, 0.05, 0.05], [0.05, 0.10, 0.05, 0.05, 0.20, 0.20, 0.20, 0.10, 0.05], [0.05, 0.05, 0.10, 0.05, 0.05, 0.20, 0.20, 0.20, 0.10], [0.10, 0.05, 0.05, 0.10, 0.05, 0.05, 0.20, 0.20, 0.20], [0.20, 0.10, 0.05, 0.05, 0.10, 0.05, 0.05, 0.20, 0.20]])#每个分量的均值means np.array([[1], [2], [4], [8], [16], [32], [6], [12], [24]])#每个分量的协方差covars .000000000001 * np.tile(np.identity(1), (9, 1, 1))
#identity的参数1要和means每一行中的列数对应#np.identity 制造对角阵使用np.tile把对角阵复制成4行1列1条的三维矩阵#建立HMM实例并设置参数model hmm.GaussianHMM(n_components9, covariance_typefull)model.startprob_ startprobmodel.transmat_ transmatmodel.means_ meansmodel.covars_ covars#产生样本X, Z model.sample(32)for i in range(32):X[i, 0] int(round(X[i, 0]))r X[:, 0]sum 0i 0new_r []while 1 - sum 0:sum 1 / r[i]new_r.append(1 / r[i])i 1new_r[i - 1] 0new_r[i - 1] 1 - np.sum(new_r)#print(r[0:i - 1])#print(new_r)#print(np.sum (new_r))return new_r3. 贝斯伴奏制作
为丰富曲目内容预置14组贝斯供用户选择。
1添加贝斯轨
向歌曲内添加贝斯轨的相关代码如下
#向音轨内添加一个普通音符此函数由MusicCritique提供
def add_bass(self, note, length, base_num-2, velocity1.0, channel6, delay0):bpm self.bpmscale self.scalebase_note 60super().append(Message(note_on, notebase_note base_num * 12 sum(self.scale[0:note]), velocityround(80 * velocity), timeround(delay * self.meta_time), channelchannel))super().append(Message(note_off, notebase_note base_num * 12 sum(self.scale[0:note]), velocityround(80 * velocity), timeint(round(0.96 * self.meta_time * length)), channelchannel))2预置贝斯轨
根据日常演奏经验对4/4拍和3/4拍的歌曲分别给出7种常用贝斯轨共14种其中函数的输入chord_progression可以是和弦名称也可以是和弦级数。例如
self.chord_progression [Fmaj7, Em7, Dm7, Cmaj7]或self.chord_progression 4321。
def my_bass_4_simple(self, chord_progression, type1, change1):d {C: 1, D: 2, E: 3, F: 4, G: 5, A: 6, B: 7}#这里只用7个音因为add_bass内部已经有对音阶的索引所以不用12个音def mode1():for chord in chord_progression:self.add_bass(d[chord[0]] if change else int(chord),0.25)#根音self.add_rest(0.25) #休止self.add_bass(d[chord[0]] if change else int(chord), 0.25)self.add_rest(0.5)self.add_bass(d[chord[0]] if change else int(chord), 0.25)self.add_rest(0.5)self.add_bass(d[chord[0]] if change else int(chord), 1)self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 1) #五音
#此处对和弦名与和弦级数做了兼容处理函数的输入可以是和弦名也可以是和弦级数
#change为1表示和弦名为0表示和弦级数在add_bass里会做相应的处理def mode2():for chord in chord_progression:for i in range(16): #十六音符根音self.add_bass(d[chord[0]] if change else int(chord), 0.25)def mode3():for chord in chord_progression:self.add_bass(d[chord[0]] if change else int(chord),0.5)#根音self.add_bass(d[chord[0]] if change else int(chord), 0.5)self.add_rest(0.5)self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 0.5) #五音self.add_bass(d[chord[0]] if change else int(chord), 0.5)self.add_bass(d[chord[0]] if change else int(chord), 0.5)self.add_rest(0.5)self.add_bass((d[chord[0]] - 1) % 7 if change else (int(chord) - 1) % 7, 0.5) #七音def mode4():for chord in chord_progression: #行进贝司self.add_bass(d[chord[0]] if change else int(chord), 1)#根音self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 1) #五音self.add_bass(d[chord[0]] if change else int(chord), 1)#根音self.add_bass((d[chord[0]] - 1) % 7 if change else (int(chord) - 1) % 7, 0.75) #七音self.add_bass((d[chord[0]] - 1) % 7 if change else (int(chord) - 1) % 7, 0.25) #七音def mode5():for chord in chord_progression:self.add_bass(d[chord[0]] if change else int(chord), 1)#根音self.add_bass(d[chord[0]] if change else int(chord), 1)#根音self.add_bass(d[chord[0]] if change else int(chord),1.5)#根音self.add_bass((d[chord[0]] - 1) % 7 if change else (int(chord) - 1) % 7, 0.5) #七音def mode6():i 0for chord in chord_progression: #击弦贝司if i % 2 0:self.add_bass(d[chord[0]] if change else int(chord), 0.25, channel8) #根音self.add_rest(0.5)self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 0.25, channel8) #五音self.add_rest(0.5)self.add_bass(d[chord[0]] if change else int(chord), 0.5, channel8) #根音self.add_bass(d[chord[0]] if change else int(chord), 0.25, channel8) #根音self.add_rest(0.5)self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 0.25, channel8) #五音self.add_rest(0.5)self.add_bass(d[chord[0]] if change else int(chord), 0.5, channel8) #根音else:self.add_bass(d[chord[0]] if change else int(chord), 0.25, channel8) #根音self.add_rest(0.5)self.add_bass(d[chord[0]] if change else (int(chord) 4) % 7, 0.25, channel8) #五音self.add_rest(0.5)self.add_bass(d[chord[0]] if change else int(chord), 0.5, channel8) #根音self.add_bass(d[chord[0]] if change else int(chord), 0.5, channel8) #根音self.add_bass(d[chord[0]] if change else int(chord), 0.5, channel8) #根音self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 0.5, channel8) #五音self.add_bass(d[chord[0]] if change else int(chord), 0.5, channel8) #根音i 1def mode7():i 0for chord in chord_progression:i 1if i % 2:elf.add_bass(d[chord[0]] if change else int(chord), 2)#根音self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 2) #五音else:self.add_bass(d[chord[0]] if change else int(chord), 2) #根音self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 1) #五音self.add_bass(d[chord[0]] if change else int(chord), 1) #根音type_d {1: mode1, 2: mode2, 3: mode3, 4: mode4, 5: mode5, 6: mode6, 7: mode7}type_d.get(type)()def my_bass_3_simple(self, chord_progression, type1, change1):d {C: 1, D: 2, E: 3, F: 4, G: 5, A: 6, B: 7}def mode1():i 0for chord in chord_progression:i 1if i % 2:self.add_bass(d[chord[0]] if change else int(chord), 2) #根音self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 1) #五音else:self.add_bass(d[chord[0]] if change else int(chord), 1) #根音self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 1) #五音self.add_bass(d[chord[0]] if change else int(chord), 1) #根音def mode2():for chord in chord_progression:self.add_bass(d[chord[0]] if change else int(chord), 3) #根音def mode3():i 0for chord in chord_progression:i 1if i % 2:self.add_bass((d[chord[0]] - 1) % 7 if change else (int(chord) - 1) % 7, 1) #七音self.add_bass(d[chord[0]] if change else int(chord), 1) #根音self.add_bass((d[chord[0]] 2) % 7 if change else (int(chord) 2) % 7, 1) #三音else:self.add_bass((d[chord[0]] - 1) % 7 if change else (int(chord) - 1) % 7, 1) #七音self.add_bass(d[chord[0]] if change else int(chord), 1) #根音self.add_bass((d[chord[0]] - 1) % 7 if change else (int(chord) - 1) % 7, 1) #七音def mode4():for chord in chord_progression:self.add_bass(d[chord[0]] if change else int(chord), 1) #根音self.add_bass(d[chord[0]] if change else int(chord), 1.5) #根音self.add_bass((d[chord[0]] 4) % 7 if change else int(chord) 4, 0.5) #五音def mode5():i 0for chord in chord_progression:i 1if i % 2:self.add_bass(d[chord[0]] if change else int(chord), 0.5) #根音self.add_bass(d[chord[0]] if change else int(chord), 0.5) #根音self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 1) #五音self.add_bass(d[chord[0]] if change else int(chord), 1) #根音else:self.add_bass(d[chord[0]] if change else int(chord), 0.5) #根音self.add_bass(d[chord[0]] if change else int(chord), 0.5) #根音self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 1) #五音self.add_bass(d[chord[0]] % 7 if change else int(chord), 0.5) #根音self.add_bass((d[chord[0]] - 1) % 7 if change else (int(chord) - 1) % 7, 0.5) #七音def mode6():for chord in chord_progression:self.add_bass(d[chord[0]] if change else int(chord), 0.5) #根音self.add_bass(d[chord[0]] if change else int(chord), 0.5) #根音self.add_bass((d[chord[0]] 4) % 7 if change else (int(chord) 4) % 7, 0.5) #五音self.add_bass(d[chord[0]] if change else int(chord), 0.5) #根音self.add_bass((d[chord[0]] - 1) % 7 if change else (int(chord) - 1) % 7, 0.5) #五音self.add_bass(d[chord[0]] if change else int(chord), 0.5) #根音def mode7():for chord in chord_progression:self.add_bass(d[chord[0]] if change else int(chord), 0.25) #根音self.add_rest(0.25) #根音self.add_bass(d[chord[0]] if change else int(chord), 0.25) #根音self.add_rest(0.5) #根音self.add_bass((d[chord[0]] 4) % 7 if change else int(chord) 4, 0.25) #五音self.add_rest(0.5) #根音self.add_bass(d[chord[0]] if change else int(chord), 0.5) #根音self.add_bass((d[chord[0]] - 1) % 7 if change else (int(chord) - 1) % 7, 0.5) #根音type_d {1: mode1, 2: mode2, 3: mode3, 4: mode4, 5: mode5, 6: mode6, 7: mode7}type_d.get(type)()4. 汇总歌曲制作
完成钢琴伴奏制作、乐句生成模块后使用类Impromptu调用并完成MIDI文件的写入与播放并使用装饰器完成日志记录函数piano_roll_test()实现音乐的可视化。
1日志模块
制作歌曲时记录日志在当前目录下生成日志文件。
import logging
from functools import wraps
def decorator_log(fun):logging.basicConfig(levellogging.DEBUG, format%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s, datefmt%a, %d %b %Y %H:%M:%S, filename./test.log, filemodew)wraps(fun)def fun_in(*args, **kwargs):logging.debug({} start..format(fun.__name__))fun(*args, **kwargs)logging.debug({} end..format(fun.__name__))return fun_in2音乐可视化
相关代码如下
#将音乐的旋律高低与时值长短可视化保存图片于my/data下函数由MusicCritique提供
def piano_roll_test(self):path self.file_pathmid MidiFileExtended(path, r)mid.turn_track_into_numpy_matrix(Piano, ../my/data/Piano.npy)mid.generate_track_from_numpy_matrix(../my/data/Piano.npy, (288, 128), Piano, False, True, ../my/data/Piano.png)mid.turn_track_into_numpy_matrix(Melody, ../my/data/Melody.npy)mid.generate_track_from_numpy_matrix(../my/data/Melody.npy, (288, 128), Melody, False, True, ../my/data/Melody.png)if self.sw_bass:mid.turn_track_into_numpy_matrix(Bass, ../my/data/Bass.npy)mid.generate_track_from_numpy_matrix(../my/data/Bass.npy,(288, 128), Bass, False, True, ../my/data/Bass.png)3Impromptu类
后台所有功能汇总类在此实现即兴曲目的信息输入可以保存并播放文件实现音乐可视化。
print(Import start.) #初次运行import时间较长
from midi_extended.MidiFileExtended import MidiFileExtended
import my.Q_myhmm
import my.decorator_log
import numpy as np
import time
print(Import end.)
class Impromptu:根据和弦进程自动生成旋律。bpm正整数每分钟心跳数time_signature每个小节中的节拍数通常为n/m默认的节奏伴奏目前仅支持4/4或3/4Key音符可以是C D E F G A BMode定即兴的规模file_pathMIDI文件的路径和名称chord_progression和弦列表intensity水平即兴演奏和垂直即兴演奏的参数repeat重复相同和弦进行的时间def __init__(self):self.bpm 120self.time_signature 4/4self.key Cself.mode majorself.file_path ../my/data/song.mid#self.chord_progression [Fmaj7, Em7, Dm7, Cmaj7]#self.chord_progression [Cmaj7, Am7, F, E7]self.chord_progression 4321#列表是已经整理好数据类型即列表内全是字符和弦名或全是级数由GUI 检查self.intensity 0self.repeat 1self.mid MidiFileExtended(self.file_path, type1, modew)self.accompany_type 1self.sw_bass Falseself.bass_type 1self.silent Falseself.accompany_tone 4 if self.silent else 0self.note_tone 26 if self.silent else 0propertydef scale(self): #定义各种参数d {major: [0, 2, 2, 1, 2, 2, 2, 1],dorian: [0, 2, 1, 2, 2, 2, 1, 2],phrygian: [0, 1, 2, 2, 2, 1, 2, 2],lydian: [0, 2, 2, 2, 1, 2, 2, 1],mixolydian: [0, 2, 2, 1, 2, 2, 1, 2],minor: [0, 2, 1, 2, 2, 1, 2, 2],locrian: [0, 1, 2, 2, 1, 2, 2, 2],major_pentatonic: [0, 2, 2, 3, 2, 3],minor_pentatonic: [0, 3, 2, 2, 3, 2]}aliases {Ionian: major, aeolian: minor}try:self._scale d[self.mode.lower()]except KeyError: #异常处理try:self._scale d[aliases[self.mode]]except KeyError: raise KeyError(Can not find your mode. Please check your key.)return self._scalemy.decorator_log.decorator_logdef chorus(self):track self.mid.get_extended_track(Piano)track.scale self.scaleif type(self.chord_progression) list: #绝对的和弦名称for i in range(self.repeat):if self.time_signature[0] 4: track.my_chorus_4_simple(chord_progressionself.chord_progression, type2)else: track.my_chorus_3_simple(chord_progressionself.chord_progression, type2)else: #是级数表示的和弦change_result []for chord in self.chord_progression:change_result.append(track.change(int(chord),self.key, self.mode))for i in range(self.repeat):if self.time_signature[0] 4:track.my_chorus_4_simple(change_result, type1, change0, circulationlen(self.chord_progression))else:track.my_chorus_3_simple(change_result, type1, change0, circulationlen(self.chord_progression))print(To specify the accompaniment, you can also call function in ./midi_extended/Track.py/my_chorus)help(track.my_chorus)my.decorator_log.decorator_logdef note(self):track self.mid.get_extended_track(Melody)#track.print_msgs()for j in range(self.repeat):print(\r note {} is making....format(j 1), end)for chord in self.chord_progression:melody my.Q_myhmm.hmmmelody()rhythm my.Q_myhmm.hmmrhythm()multiple int(self.time_signature[0])d {C: 1, Db: 2, D: 3, Eb: 4, E: 5, F: 6, Gb: 7, G: 8, Ab: 9, A: 10, Bb: 11,B: 12, C#: 2, D#: 4, F#: 7, G#: 9, A#: 11}if self.intensity:np.random.seed(round(1000000 * time.time()) % 100) # Seed must be between 0 and 2**32 - 1p np.array([self.intensity, 1 - self.intensity])if type(self.chord_progression) list: #已经是绝对的和弦名称modulation np.random.choice([0, d[chord[0]]], pp.ravel())else: #是级数modulation np.random.choice([0, sum(self.scale[0:int(chord)])], pp.ravel())else:modulation 0#modulation sum(self.scale[0:d[chord[0]]])for i in range(len(rhythm)):m melody[i]if m 0: #是一个普通音符track.add_note(m, rhythm[i] * multiple, modulation, 1, velocity110, scaleself.scale, channel3)#sum(self.scale[0:d[chord[0]]]))#print(add_note, m, rhythm[i]*multiple)elif m 0: #是休止符track.add_rest(rhythm[i] * multiple)#print(add_rest, m, rhythm[i]*multiple)else: #是延音符track.add_tenuto(rhythm[i] * multiple)#print(add_tenuto, m, rhythm[i]*multiple)def bass(self):track self.mid.get_extended_track(Bass)track.scale self.scaleif type(self.chord_progression) list: #已经是绝对的和弦名称for i in range(self.repeat):if self.time_signature[0] 4:track.my_bass_4_simple(chord_progressionself.chord_progression, type1)else: track.my_bass_3_simple(chord_progressionself.chord_progression, type1)else: #是级数表示的和弦for i in range(self.repeat):if self.time_signature[0] 4:track.my_bass_4_simple(self.chord_progression, typei 1, change0)else:track.my_bass_3_simple(self.chord_progression, typei 1, change0)def piano_roll_test(self): #定义测试path self.file_path #文件路径mid MidiFileExtended(path, r)mid.turn_track_into_numpy_matrix(Piano, ../my/data/Piano.npy)mid.generate_track_from_numpy_matrix(../my/data/Piano.npy, (288, 128), Piano, False, True,../my/data/Piano.png)mid.turn_track_into_numpy_matrix(Melody, ../my/data/Melody.npy) #数据写入矩阵mid.generate_track_from_numpy_matrix(../my/data/Melody.npy, (288, 128), Melody, False, True, ../my/data/Melody.png)if self.sw_bass:mid.turn_track_into_numpy_matrix(Bass, ../my/data/Bass.npy)mid.generate_track_from_numpy_matrix(../my/data/Bass.npy, (288, 128), Bass, False, True, ../my/data/Bass.png)def write_song(self): #定义写入歌曲del self.midself.mid MidiFileExtended(self.file_path, type1, modew)self.mid.add_new_track(Piano, self.time_signature, self.bpm, self.key, {0: 4 if self.silent else 0}) #4})#这里的轨道0和1音色是30代表具体乐器音色self.chorus()self.mid.add_new_track(Melody, self.time_signature, self.bpm, self.key, {3: 26 if self.silent else 0}) #26self.note()if self.sw_bass:self.mid.add_new_track(Bass, self.time_signature, self.bpm, self.key, {6: 39 if self.silent else 33,7: 35, 8: 36})self.bass()
if __name__ __main__: #主函数silence Impromptu()print(silence.scale)silence.write_song()silence.mid.save_midi()silence.piano_roll_test()print(Done. Start to play.)#silence.mid.play_it()5. GUI设计
为方便用户交互使用PyQt5 Designer拖动控件设计图形界面使用PyQt-tools将制作好的.ui文件转为.py代码完成用户界面初始化再将控件绑定对应功能。
1用户界面空间初始化
此代码由制作的.ui文件经PyQt-tools转换而成在Windows下运行。
from PyQt5 import QtCore, QtWidgets
class Ui_MainWindow(object):def setupUi(self, MainWindow): #设置界面MainWindow.setObjectName(MainWindow)MainWindow.resize(800, 680)self.centralwidget QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName(centralwidget)self.verticalLayoutWidget QtWidgets.QWidget(self.centralwidget)self.verticalLayoutWidget.setGeometry(QtCore.QRect(0, 0, 800, 680))self.verticalLayoutWidget.setObjectName(verticalLayoutWidget) self.verticalLayout_2QtWidgets.QVBoxLayout(self.verticalLayoutWidget)self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)self.verticalLayout_2.setObjectName(verticalLayout_2)self.verticalLayout_3 QtWidgets.QVBoxLayout()self.verticalLayout_3.setObjectName(verticalLayout_3)self.frame QtWidgets.QFrame(self.verticalLayoutWidget)self.frame.setEnabled(True)self.frame.setStyleSheet(background-image:url(./background.jpeg);)self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)self.frame.setFrameShadow(QtWidgets.QFrame.Raised)self.frame.setObjectName(frame)self.w_time_signalture QtWidgets.QComboBox(self.frame)self.w_time_signalture.setGeometry(QtCore.QRect(360,220, 111, 21))self.w_time_signalture.setObjectName(w_time_signalture)self.w_time_signalture.addItem()self.w_time_signalture.addItem()self.w_mode QtWidgets.QComboBox(self.frame)self.w_mode.setGeometry(QtCore.QRect(360, 140, 111, 21))self.w_mode.setObjectName(w_mode)self.w_mode.addItem()self.w_mode.addItem()self.w_mode.addItem()self.w_mode.addItem()self.w_mode.addItem()self.w_mode.addItem()self.w_mode.addItem()self.w_mode.addItem()self.w_mode.addItem()self.w_bass QtWidgets.QComboBox(self.frame)self.w_bass.setGeometry(QtCore.QRect(360, 300, 111, 21))self.w_bass.setObjectName(w_bass)self.w_bass.addItem()self.w_bass.addItem()self.w_bass.addItem()self.w_bass.addItem()self.w_bass.addItem()self.w_bass.addItem()self.w_bass.addItem()self.w_bass.addItem()self.w_accompany QtWidgets.QComboBox(self.frame)self.w_accompany.setGeometry(QtCore.QRect(360, 260, 111, 21))self.w_accompany.setObjectName(w_accompany)self.w_accompany.addItem()self.w_accompany.addItem()self.w_accompany.addItem()self.w_accompany.addItem()self.w_accompany.addItem()self.w_accompany.addItem()self.w_key QtWidgets.QComboBox(self.frame)self.w_key.setEnabled(True)self.w_key.setGeometry(QtCore.QRect(360, 100, 111, 21))self.w_key.setMaxVisibleItems(7)self.w_key.setObjectName(w_key)self.w_key.addItem()self.w_key.addItem()self.w_key.addItem()self.w_key.addItem()self.w_key.addItem()self.w_key.addItem()self.w_key.addItem()self.verticalLayout_3.addWidget(self.frame)self.verticalLayout_2.addLayout(self.verticalLayout_3)self.label QtWidgets.QLabel(self.centralwidget)self.label.setGeometry(QtCore.QRect(190, 340, 141, 31))self.label.setObjectName(label)self.w_play QtWidgets.QPushButton(self.centralwidget)self.w_play.setGeometry(QtCore.QRect(360, 490, 93, 28))self.w_play.setAutoDefault(False)self.w_play.setDefault(False)self.w_play.setFlat(False)self.w_play.setObjectName(w_play)self.label_7 QtWidgets.QLabel(self.centralwidget)self.label_7.setGeometry(QtCore.QRect(190, 380, 121, 31))self.label_7.setObjectName(label_7)self.w_intensity QtWidgets.QSlider(self.centralwidget)self.w_intensity.setGeometry(QtCore.QRect(340, 430, 160, 22))self.w_intensity.setMaximum(100)self.w_intensity.setSingleStep(1)self.w_intensity.setOrientation(QtCore.Qt.Horizontal)self.w_intensity.setObjectName(w_intensity)self.w_repeat QtWidgets.QLineEdit(self.centralwidget)self.w_repeat.setGeometry(QtCore.QRect(360, 380, 113, 21))self.w_repeat.setInputMask()self.w_repeat.setMaxLength(32767)self.w_repeat.setObjectName(w_repeat)self.w_bpm QtWidgets.QLineEdit(self.centralwidget)self.w_bpm.setGeometry(QtCore.QRect(360, 180, 113, 21))self.w_bpm.setObjectName(w_bpm)self.w_chord_progression QtWidgets.QLineEdit(self.centralwidget)self.w_chord_progression.setGeometry(QtCore.QRect(360,340,113,21))self.w_chord_progression.setObjectName(w_chord_progression)self.label_6 QtWidgets.QLabel(self.centralwidget)self.label_6.setGeometry(QtCore.QRect(190, 180, 121, 31))self.label_6.setObjectName(label_6)self.label_5 QtWidgets.QLabel(self.centralwidget)self.label_5.setGeometry(QtCore.QRect(190, 100, 121, 31))self.label_5.setObjectName(label_5)self.label_3 QtWidgets.QLabel(self.centralwidget)self.label_3.setGeometry(QtCore.QRect(190, 420, 121, 31))self.label_3.setObjectName(label_3)self.label_2 QtWidgets.QLabel(self.centralwidget)self.label_2.setGeometry(QtCore.QRect(190, 220, 121, 31))self.label_2.setObjectName(label_2)self.label_4 QtWidgets.QLabel(self.centralwidget)self.label_4.setGeometry(QtCore.QRect(190, 140, 121, 31))self.label_4.setObjectName(label_4)self.label_8 QtWidgets.QLabel(self.centralwidget)self.label_8.setGeometry(QtCore.QRect(190, 260, 121, 31))self.label_8.setObjectName(label_8)self.label_9 QtWidgets.QLabel(self.centralwidget)self.label_9.setGeometry(QtCore.QRect(190, 300, 121, 31))self.label_9.setObjectName(label_9)self.checkBox QtWidgets.QCheckBox(self.centralwidget)self.checkBox.setGeometry(QtCore.QRect(630, 430, 91, 19))self.checkBox.setObjectName(checkBox)MainWindow.setCentralWidget(self.centralwidget)self.menubar QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 798, 26))self.menubar.setObjectName(menubar)self.menusetting QtWidgets.QMenu(self.menubar)self.menusetting.setObjectName(menusetting)self.menuhelp QtWidgets.QMenu(self.menubar)self.menuhelp.setObjectName(menuhelp)self.menuAbout QtWidgets.QMenu(self.menubar)self.menuAbout.setObjectName(menuAbout)MainWindow.setMenuBar(self.menubar)self.statusbar QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName(statusbar)MainWindow.setStatusBar(self.statusbar)self.actionsetting QtWidgets.QAction(MainWindow)self.actionsetting.setObjectName(actionsetting)self.actionexit QtWidgets.QAction(MainWindow)self.actionexit.setObjectName(actionexit)self.actiondocument_2 QtWidgets.QAction(MainWindow)self.actiondocument_2.setObjectName(actiondocument_2)self.actionabout QtWidgets.QAction(MainWindow)self.actionabout.setObjectName(actionabout)self.menusetting.addSeparator()self.menusetting.addAction(self.actionsetting)self.menusetting.addSeparator()self.menusetting.addAction(self.actionexit)self.menuhelp.addAction(self.actiondocument_2)self.menuAbout.addAction(self.actionabout)self.menubar.addAction(self.menusetting.menuAction())self.menubar.addAction(self.menuhelp.menuAction())self.menubar.addAction(self.menuAbout.menuAction())self.retranslateUi(MainWindow)self.w_key.setCurrentIndex(0)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow): #重新加载界面_translate QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate(MainWindow, MainWindow))self.w_time_signalture.setItemText(0,_translate(MainWindow,4/4))self.w_time_signalture.setItemText(1, _translate(MainWindow,3/4))self.w_mode.setItemText(0, _translate(MainWindow, major))self.w_mode.setItemText(1, _translate(MainWindow, dorian))self.w_mode.setItemText(2, _translate(MainWindow, phrygian))self.w_mode.setItemText(3, _translate(MainWindow, lydian))self.w_mode.setItemText(4, _translate(MainWindow, mixolydian))self.w_mode.setItemText(5, _translate(MainWindow, minor))self.w_mode.setItemText(6, _translate(MainWindow, locrian))self.w_mode.setItemText(7,_translate(MainWindow,major pentatonic))self.w_mode.setItemText(8,_translate(MainWindow,minor pentatonic))self.w_bass.setItemText(0, _translate(MainWindow, None))self.w_bass.setItemText(1, _translate(MainWindow, 1))self.w_bass.setItemText(2, _translate(MainWindow, 2))self.w_bass.setItemText(3, _translate(MainWindow, 3))self.w_bass.setItemText(4, _translate(MainWindow, 4))self.w_bass.setItemText(5, _translate(MainWindow, 5))self.w_bass.setItemText(6, _translate(MainWindow, 6))self.w_bass.setItemText(7, _translate(MainWindow, 7))self.w_accompany.setItemText(0, _translate(MainWindow, 1))self.w_accompany.setItemText(1, _translate(MainWindow, 2))self.w_accompany.setItemText(2, _translate(MainWindow, 3))self.w_accompany.setItemText(3, _translate(MainWindow, 4))self.w_accompany.setItemText(4, _translate(MainWindow, 5))self.w_accompany.setItemText(5, _translate(MainWindow, 6))self.w_key.setCurrentText(_translate(MainWindow, C))self.w_key.setItemText(0, _translate(MainWindow, C))self.w_key.setItemText(1, _translate(MainWindow, D))self.w_key.setItemText(2, _translate(MainWindow, E))self.w_key.setItemText(3, _translate(MainWindow, F))self.w_key.setItemText(4, _translate(MainWindow, G))self.w_key.setItemText(5, _translate(MainWindow, A))self.w_key.setItemText(6, _translate(MainWindow, B))self.label.setText(_translate(MainWindow, Chord progression))self.w_play.setText(_translate(MainWindow, GO))self.label_7.setText(_translate(MainWindow, repeat))self.w_repeat.setText(_translate(MainWindow, 1))self.w_bpm.setText(_translate(MainWindow, 120))self.w_chord_progression.setText(_translate(MainWindow,4321))self.label_6.setText(_translate(MainWindow, bpm))self.label_5.setText(_translate(MainWindow, key))self.label_3.setText(_translate(MainWindow, intensity))self.label_2.setText(_translate(MainWindow, Time signalture))self.label_4.setText(_translate(MainWindow, mode))self.label_8.setText(_translate(MainWindow, accompany))self.label_9.setText(_translate(MainWindow, bass))self.checkBox.setText(_translate(MainWindow, silent))self.menusetting.setTitle(_translate(MainWindow, Menu))self.menuhelp.setTitle(_translate(MainWindow, Help))self.menuAbout.setTitle(_translate(MainWindow, About))self.actionsetting.setText(_translate(MainWindow, setting))self.actionexit.setText(_translate(MainWindow, exit))self.actiondocument_2.setText(_translate(MainWindow, document))self.actionabout.setText(_translate(MainWindow, about))2将控件绑定功能信号与槽的绑定
通过MainCode实现的继承关系如图所示其中Impromptu类为可运行的脚本Ui_MainWindow为PyQt5。 #完成基础页面布局后对事件设定触发并定义触发的函数
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox
from PyQt5.QtCore import QCoreApplication
from my import v4
#import _thread
#import threading
import all1
play False
class MainCode(all1.Impromptu, QMainWindow, v4.Ui_MainWindow):def __init__(self): #初始化super().__init__()QMainWindow.__init__(self)v4.Ui_MainWindow.__init__(self)#super().setupUi(self)self.setupUi(self)self.w_play.clicked.connect(self.go)self.w_key.activated[str].connect(self.set_key)self.w_mode.activated[str].connect(self.set_mode)self.w_bass.activated[str].connect(self.set_bass)self.w_accompany.activated[str].connect(self.set_accompany)self.w_time_signalture.activated[str].connect(self.set_time_signalture)self.actionexit.triggered.connect(QCoreApplication.instance().quit)self.actiondocument_2.triggered.connect(self.document)self.actionsetting.triggered.connect(self.setting)self.actionabout.triggered.connect(self.about)def document(self): #定义文本text this is ducomentQMessageBox.information(self, Message, text, QMessageBox.Ok)def setting(self): #定义设置text this is settingQMessageBox.information(self, Message, text, QMessageBox.Ok)def about(self): #定义关于text author: dongmie1999\n2020.4QMessageBox.information(self, Message, text, QMessageBox.Ok)def set_key(self, text): #定义设置键self.key textdef set_mode(self, text): #定义设置模式self.mode textdef set_bass(self, text): #定义设置贝斯if text None:self.sw_bass Falseelse:self.sw_bass Trueself.bass_type int(text)def set_accompany(self, text): #定义设置伴奏self.accompany_type int(text)def set_time_signalture(self, text): #定义设置时间self.time_signalture textdef go(self): #定义行进try:self.bpm int(self.w_bpm.text())except ValueError:text bpm should be an positive integer.\nrecommend: 70~150QMessageBox.information(self, Message, text, QMessageBox.Ok)returntry:if not 0 int(self.w_repeat.text()) 20:raise ValueErrorexcept ValueError:text repeat should be an positive integer.\nrecommend: 1~5QMessageBox.information(self, Message, text, QMessageBox.Ok)returnself.intensity int(self.w_intensity.value()/100)try: #用级数表示和弦for t in self.w_chord_progression.text():if 0 int(t) 8:passelse:text Input should be a series fo numbers.\nEach number must be between 1~7.\n \Example: 4321 or 4536251 or 1645QMessageBox.information(self, Message, text, QMessageBox.Ok)returnself.chord_progression self.w_chord_progression.text()except ValueError: #和弦名称self.chord_progressionself.w_chord_progression.text().split(,)#print(self.checkBox.checkState())if self.checkBox.checkState():self.silent Trueelse:self.silent Falseprint(Song making...)self.write_song()self.mid.save_midi()print(Done. Start to play.)#for n in range(self.repeat):#获取条目文本#str_n File index{0}.format(n)#添加文本到列表控件中#self.listFile.addItem(str_n)#实时刷新界面#QApplication.processEvents()#睡眠1秒#time.sleep(1)#thread.start_new_thread(self.mid.play_it())self.mid.play_it()if __name__ __main__: #主函数app QApplication(sys.argv)md MainCode()md.show()#t1 threading.Thread(targetmd.show())#t2 threading.Thread(targetmd.go())#t1.start()#t1.join()#if play:#print(play)#t2.start()#t2.join()#play Falsesys.exit(app.exec_())系统测试
GUI界面选择的和弦级数都是调内和弦。在Impromptu中使用self.chord_progression [Cmaj7Am7 F E7] 可以使用调外和弦给歌曲引入更丰富的和声。
运行主程序后显示GUI界面如图所示。用户可选择的歌曲信息有主音、调式、bpm、拍号、钢琴伴奏类型、贝斯伴奏类型、和弦进行、重复次数和即兴的强度另外还有右下角音色的切换(普通/安静)。 由于即兴的特点每次运行产生的音频都不同此处展示C大调下和弦进行为4321重复次数为1贝斯和钢琴伴奏类型均为类型1的歌曲可视化结果如图3所示。钢琴伴奏位于中音区(C34) 。即兴旋律可视化结果如图4所示即兴旋律位于高音区(C4C5) 。贝斯伴奏可视化结果如图5所示即兴旋律位于低音区(C1~C2)。 图3 钢琴伴奏可视化 图4 即兴旋律可视化 图5 贝斯伴奏可视化 工程源代码下载
详见本人博客资源下载页 其它资料下载
如果大家想继续了解人工智能相关学习路线和知识体系欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线所有资料免关注免套路直接网盘下载》 这篇博客参考了Github知名开源平台AI技术平台以及相关领域专家DatawhaleApacheCNAI有道和黄海广博士等约有近100G相关资料希望能帮助到所有小伙伴们。