【mido之架子鼓编曲】



前言

midi是基于事件的通用音乐表现格式,是计算机音乐的基础数据结构。mido为用于解析和生成Midi文件的python库,本文以mido库来生成常见的架子鼓节奏。


一、mido基本操作

官方示例:

from mido import Message, MidiFile, MidiTrack

mid = MidiFile() # 创建一个MidiFile对象
track = MidiTrack() # 创建一个(或多个)MidiTrack对象
mid.tracks.append(track) # 将track添加到MidiFile对象中

track.append(Message('program_change', program=12, time=0)) # 添加Message对象
track.append(Message('note_on', note=64, velocity=64, time=32)) # 添加note_on 事件
track.append(Message('note_off', note=64, velocity=127, time=32)) # 添加note_off 事件

mid.save('new_song.mid') # 保存mid文件

基本概念

message

message:mido提供的消息类,包含很多的属性和方法。
其第一个参数为messagetype,列举最常见的3个:
note_on:音符的开始事件
note_off:音符的结束事件
control_change:更改乐器
参数note:音符的音高。60代表中央C,每增加12,音高升高一个八度
参数velocity:音符的音量,取值在0-127之间
time:音符的演奏时间,这里要重点留意,因为它不是单纯的每个音符的持续时间。
官方解释:In MIDI file tracks, it is used as delta time (in ticks), and it must be a non-negative integer.
意思是它是一个增量时间,代表上一个音符结束后到此音符的间隔时间。这个时间以tick为单位,而在mido的默认配置中,1拍中有480个tick。所以要想生成一个长度为1拍的音符,应该设置其time值为480,而不是1。后面在同时按下多个音符的时候再举例说明

meta message

MetaMessage是mido中另一个重要的类,是用于track的一些基本设置
time_signature是拍号设置,numerator 为一小节几拍,denominator 为几分音符,如3/4的设置为一小节3拍,4分音符为1拍
set_tempo是用于设置音乐的节奏快慢,由于这里tempo的单位不是BPM(Beat Per Minute),故一般配合bpm2tempo来使用
key_signature是用于设置音乐的调式的,C为C大调,若是小调的话仅需要在后面添加小写字母m,如Cm表示C小调

二、架子鼓mido编曲实现

1.基本设置

为了方便操作,定义了一个鼓的演奏类DrusmPlay

from mido import Message, MidiFile, MidiTrack, bpm2tempo, MetaMessage

class DrusmPlay:
    def __init__(self, track):
        self.bpm = 80
        self.track = track
        self.tempo = bpm2tempo(self.bpm)
        self.meta_time = 480
        # 一拍的时间,用于Message中time的值。用480*n来表示
        self.track.append(MetaMessage('set_tempo', tempo=self.tempo, time=0))
        # 设置节奏快慢
        self.track.append(MetaMessage('time_signature', numerator=4, denominator=4))
        # 拍号设置

2.midi音色对应表

用一个字典来保存对应鼓的note,后面用**是我个人觉得在架子鼓演奏中较常用的音色

self.drum_dict = {
            'acoustic_bass': 35,  # 大鼓
            'bass1': 36,  # 低音鼓 **
            'side_stick': 37,  # 边击
            'acoustic_snare': 38,  # 小鼓(松) **
            'hand_clap': 39,  # 拍手
            'electric_snare': 40,  # 小鼓(紧)
            'low_floor_tom': 41,  # 通鼓(最低) **
            'closed_hi-hat': 42,  # 立镲(闭) **
            'high_floor_tom': 43,  # 通鼓(低) **
            'pedal_hi-hat': 44,  # 踩镲
            'low_tom': 45,  # 通鼓(中低) **
            'open_hi-hat': 46,  # 立镲(开) **
            'low-mid_tom': 47,  # 通鼓(中) **
            'hi-mid_tom': 48,  # 通鼓(中高) **
            'crash_cymbal1': 49,  # 低砸音镲 **
            'high_tom': 50,  # 通鼓(高) **
            'ride_cymbal1': 51,  # 厚吊镲(低) **
            'chinese_cymbal': 52,  # 锣
            'ride_bell': 53,  # 厚吊镲(中)
            'tambourine': 54,  # 铃鼓
            'splash_cymbal': 55,  # 小吊镲
            'cowbell': 56,  # 牛铃
            'crash_cymbal2': 57,  # 薄吊镲(高) 高砸音镲
            'vibraslap': 58,  # 振音梆盒
            'ride_cymbal2': 59,  # 厚吊镲(高)
            'hi_bongo': 60,  # 邦戈鼓(高)
            'low_bongo': 61,  # 邦戈鼓(低)
            'mute_hi_bongo': 62,  # 康加鼓(高闭)
            'open_hi_bongo': 63,  # 康加鼓(高开)
            'low_conga': 64,  # 康加鼓(低)
            'high_timbale': 65,  # 边鼓(高)
            'low_timbale': 66,  # 边鼓(低)
            'high_agogo': 67,  # 拉丁打铃(高)
            'low_agogo': 68,  # 拉丁打铃(低)
            'cabasa': 69,  # 喀吧萨
            'maracas': 70,  # 沙锤
            'short_whistle': 71,  # 哨子(短)
            'long_whistle': 72,  # 哨子(长)
            'short_guiro': 73,  # 刮板(短)
            'long_guiro': 74,  # 刮板(长)
            'claves': 75,  # 响棒
            'hi_wood_block': 76,  # 梆盒(高)
            'low_wood_block': 77,  # 梆盒(低)
            'mute_cuica': 78,  # 拉鼓(闭)
            'open_cuica': 79,  # 拉鼓(开)
            'mute_triangle': 80,  # 三角铁(闭)
            'open_triangle': 81  # 三角铁(开)
        }

3.基本节奏的添加

接下来来实现一个基本的“动次打次”节奏型的演奏,4小节,每小节4拍,8个8分音符来组成:

    def dongcidaci(self):
        for i in range(4):
            # 写4小节

            # 第一个八分音符:bass鼓和crash_cymbal同时击下
            self.track.append(
                Message('note_on', note=self.drum_dict['bass1'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_on', note=self.drum_dict['crash_cymbal1'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['bass1'], velocity=64, time=round(self.meta_time * 0.5),
                        channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['crash_cymbal1'], velocity=64, time=0, channel=9))
            # 留意crash_cymbal1的note_off事件,time是0,代表前一个音符结束也同时结束

            # 第二个八分音符:闭镲
            self.track.append(
                Message('note_on', note=self.drum_dict['closed_hi-hat'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['closed_hi-hat'], velocity=64, time=round(self.meta_time * 0.5),
                        channel=9))

            # 第三个八分音符:军鼓和闭镲同时击下
            self.track.append(
                Message('note_on', note=self.drum_dict['acoustic_snare'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_on', note=self.drum_dict['closed_hi-hat'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['acoustic_snare'], velocity=64,
                        time=round(self.meta_time * 0.5), channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['closed_hi-hat'], velocity=64, time=0, channel=9))

            # 第四个八分音符:闭镲
            self.track.append(
                Message('note_on', note=self.drum_dict['closed_hi-hat'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['closed_hi-hat'], velocity=64, time=round(self.meta_time * 0.5),
                        channel=9))

            # 第五个八分音符:bass鼓和closed_hi-hat同时击下
            self.track.append(
                Message('note_on', note=self.drum_dict['bass1'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_on', note=self.drum_dict['closed_hi-hat'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['bass1'], velocity=64, time=round(self.meta_time * 0.5),
                        channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['closed_hi-hat'], velocity=64, time=0, channel=9))
            # 留意crash_cymbal1的note_off事件,time是0,代表前一个音符结束也同时结束

            # 第六个八分音符:闭镲
            self.track.append(
                Message('note_on', note=self.drum_dict['closed_hi-hat'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['closed_hi-hat'], velocity=64, time=round(self.meta_time * 0.5),
                        channel=9))

            # 第七个八分音符:军鼓和闭镲同时击下
            self.track.append(
                Message('note_on', note=self.drum_dict['acoustic_snare'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_on', note=self.drum_dict['closed_hi-hat'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['acoustic_snare'], velocity=64,
                        time=round(self.meta_time * 0.5), channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['closed_hi-hat'], velocity=64, time=0, channel=9))

            # 第八个八分音符:闭镲
            self.track.append(
                Message('note_on', note=self.drum_dict['closed_hi-hat'], velocity=64, time=0, channel=9))
            self.track.append(
                Message('note_off', note=self.drum_dict['closed_hi-hat'], velocity=64, time=round(self.meta_time * 0.5),
                        channel=9))

4.生成mid文件

生成并保存mid文件

if __name__ == "__main__":
    mid = MidiFile()
    track = MidiTrack()
    mid.tracks.append(track)

    dp = DrusmPlay(track)
    dp.dongcidaci()
    mid.save('drums.mid')

三、评估

评估方法:用MuseScore写一段group truch的节奏,用于与上面生成的mid进行对比。

musescore打谱

先用musescore打一段4小节4拍的谱:
在这里插入图片描述

用musescore对比

用musescore打开刚刚生成的drums.mid文件,会自动转换成曲谱:
在这里插入图片描述
可以看到,两段曲谱是一致的。

LMMS对比

也可以通过LMMS软件打开两段mid来对比
在这里插入图片描述

四、总结

本文尝试了mido来生成鼓的基本节奏,可以作为计算机混音,编曲,转录的基础。
后续工作:
1.进一步抽象更多的节奏型,简化输入
2.鼓谱转录的相关工作

参考:
https://blog.csdn.net/TruedickDing/article/details/101780003
https://blog.csdn.net/TruedickDing/article/details/102014762
https://blog.csdn.net/weixin_43572492/article/details/84987309
https://blog.csdn.net/X_i_n_w_e_i/article/details/104434139

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值