如何用Mido实现与MIDIUtil等效的MIDI文件创建?
用Mido实现等效MIDIUtil的MIDI生成功能
下面是和你提供的MIDIUtil代码完全等效的Mido实现,同时包含调号设置的示例:
from mido import MidiFile, MidiTrack, Message, MetaMessage # 配置参数 degrees = [60, 62, 64, 65, 67, 69, 71, 72] # MIDI音符编号 channel = 0 time = 0 # 初始时间(拍数) duration = 1 # 音符时长(拍数) tempo = 60 # BPM volume = 100 # 音量(0-127) ticks_per_beat = 480 # Mido默认PPQ,可自定义 # 1. 创建MIDI文件对象(格式1,对应MIDIUtil的默认格式) mid = MidiFile(type=1, ticks_per_beat=ticks_per_beat) # 2. 创建音轨并添加到文件 track = MidiTrack() mid.tracks.append(track) # 3. 设置速度(将BPM转换为微秒/拍,MIDI标准单位) microseconds_per_beat = 60000000 // tempo track.append(MetaMessage('set_tempo', tempo=microseconds_per_beat, time=0)) # 4. 设置拍号(对应原代码的4/2拍,clocks_per_click=24) track.append(MetaMessage('time_signature', numerator=4, denominator=2, clocks_per_click=24, notated_32nd_notes_per_beat=8, time=0)) # 5. 设置调号(示例:C大调,对应key=0;小调可加'm',如'Am'或key=-3) track.append(MetaMessage('key_signature', key='C', time=0)) # 6. 添加音符(note_on和note_off消息组合) for i, pitch in enumerate(degrees): # 计算音符起始和结束的tick时间 start_tick = (time + i) * ticks_per_beat end_tick = start_tick + duration * ticks_per_beat # 发送note_on消息(时间差相对于上一条消息) track.append(Message('note_on', channel=channel, note=pitch, velocity=volume, time=start_tick - track[-1].time if track else start_tick)) # 发送note_off消息(时间差为时长对应的tick) track.append(Message('note_off', channel=channel, note=pitch, velocity=volume, time=end_tick - start_tick)) # 7. 保存MIDI文件 mid.save('midifile.mid')
关键步骤说明:
- 创建MIDI对象:
MidiFile(type=1)对应MIDI格式1(包含速度轨和音轨,和MIDIUtil默认一致),ticks_per_beat是每拍的脉冲数,默认480,可按需调整。 - 设置速度:MIDI用微秒/拍作为速度单位,通过
60000000 // tempo转换BPM到该单位,用set_tempo元消息添加。 - 设置拍号:
time_signature元消息的参数对应MIDI标准:numerator:拍号分子denominator:分母的2次幂(比如4/4拍填4,3/8拍填3)clocks_per_click:每点击的时钟数,原代码用24直接对应
- 添加音符:MIDI需要
note_on和note_off消息成对出现,time参数是相对于上一条消息的时间差(tick数),所以要计算好时间间隔。 - 设置调号:
key_signature元消息可直接传入调名(如'C'、'G#'、'Am')或数字(0=C大调,-1=F大调,-3=A小调等)。 - 保存文件:调用
mid.save()方法直接保存到指定路径。
内容的提问来源于stack exchange,提问作者Philip Bergwerf
相关产品推荐
相关产品推荐

