Python 为什么干净的Midi文件播放方式不同?(与mido一起)

Python 为什么干净的Midi文件播放方式不同?(与mido一起),python,midi,mido,Python,Midi,Mido,我编写了一个程序,它接收一个MIDI文件,然后使用Mido,它通过删除特定类型的元数据、重复消息等来清理数据。它还计算了累积时间(因为每个MIDI消息中的时间都是增量时间)。然后用它创建一个新的mido文件(从头开始),我将所有这些消息附加到一个曲目中(因此基本上合并了曲目),并按累计时间对它们进行排序。然后相应地调整增量时间(请记住,每个新的midi曲目从累积时间0开始)。我意识到这似乎毫无意义(因为我正试图构建一首更清晰的歌曲),但目的是获得更好的数据,然后再做其他事情 我已经将代码分为两部

我编写了一个程序,它接收一个MIDI文件,然后使用Mido,它通过删除特定类型的元数据、重复消息等来清理数据。它还计算了累积时间(因为每个MIDI消息中的时间都是增量时间)。然后用它创建一个新的mido文件(从头开始),我将所有这些消息附加到一个曲目中(因此基本上合并了曲目),并按累计时间对它们进行排序。然后相应地调整增量时间(请记住,每个新的midi曲目从累积时间0开始)。我意识到这似乎毫无意义(因为我正试图构建一首更清晰的歌曲),但目的是获得更好的数据,然后再做其他事情

我已经将代码分为两部分。第一个执行所有过滤并构建一个大列表,其中每个子列表中的第一项是消息本身,每个子列表中的第二项是累积时间(如上所述,这是按累积时间排序的)。代码的第二部分调整此列表中每个项目的增量时间,然后将列表中的所有消息按顺序(使用更正的增量时间)附加到从头创建的轨迹上。然后使用pygame播放此曲目

我似乎遇到的主要问题是时间/节奏。重建的曲目要么播放得太快,要么播放得太慢。在一些文件(例如波希米亚狂想曲文件)的情况下,工具部分似乎也分离和混乱

这是分解和列出建筑规范:


进口米多
导入pygame
all_mid=['MARGY-scale.mid']
#检查midi文件是否为类型2(如果是,则删除)-这不太可能,但可能发生在旧站点上
def移除_类型_2(midi):
如果midi.type==2,则返回True,否则返回False
#删除不必要的元数据类型
def过滤器元类型(msg):
accept=[“设置节奏”、“时间签名”、“键签名”]
如果msg.type中的accept else为False,则返回True
#删除重复的节拍,并仅在特定的累计时间内保持最后一个指定的节拍
def remove_extra_tempo(消息、msgwithtempos、当前时间):
如果不是msgwithtempos:#如果列表为空
附加([msg,当前时间])
其他:
对于范围内的i(len(msgwithtempos)):
msgwithtempo=msgwithtempos[i]
如果msgwithtempo[1]==当前时间:#则检查重复项
msgwithtempo.remove(msgwithtempo)
附加([msg,当前时间])
返回msgwithtempos
def do_shit(mid,all_messages):#对每首曲目(然后是message)执行以下操作
msgwithtempos=[]
对于i,枚举中的轨迹(中间轨迹):
当前时间=0
打印(f“Track{i}:{Track.name}”)
对于轨道中的消息:
当前时间+=消息时间
如果msg.type==“sysex数据”:
通过
elif msg.is_meta:
如果过滤器类型(msg):
如果msg.type==“设置节奏”:
msgwithtempos=删除额外的节奏(msg,msgwithtempos,当前时间)
其他:
所有\u消息。追加([msg,当前\u时间])
其他:
所有\u消息。追加([msg,当前\u时间])
返回所有_消息,msgwithtempos
def main():#对于每个midi文件,请执行以下操作
所有_列表=[]
对于范围(0,len(all_mid))中的i:
所有_消息=[]
mid=mido.MidiFile(全部\u mid[i])
如果没有,请删除类型2(mid):
所有消息,msgwithtempos=do_shit(中间,所有消息)
最终消息=所有消息+msgwithtempos
最终消息=已排序(最终消息,键=λx:x[1])
所有\u列表。追加(最终\u消息)
打印(所有列表)
返回所有_列表
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
这是重建代码:

导入mido
导入pygame
导入轨道
def播放游戏(歌曲):
pygame.init()
pygame.mixer.music.load(歌曲)
length=pygame.time.get_ticks()
pygame.mixer.music.play()
而pygame.mixer.music.get_busy():
pygame.time.wait(长度)
def打印消息(mid):
对于i,枚举中的轨迹(中间轨迹):
打印(f“Track{i}:{Track.name}”)
对于轨道中的消息:
打印(msg)
def main():
#从音乐曲目中获取midi文件列表
输出=调整轨道。主()
列表1=输出[0]
#创建一个空白的midi文件并向其添加曲目
mid=mido.MidiFile()
track=mido.MidiTrack()
mid.tracks.append(曲目)
对于范围内的i(len(列表1)):
message=list1[i][0]
打印(message.type)
如果i==0:
message.time=0
其他:
message.time=list1[i][1]-list1[i-1][1]
打印(信息)
track.append(消息)
mid.save('new_song.mid'))
打印消息(mid)
玩游戏(新歌,中)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
示例文件:

波希米亚狂想曲:

河流在你心中流动:

谢谢

编辑:

这似乎是一个空白MIDI创建的问题,并且随着我创建的代码从一个简短的MIDI文件手动复制,并且在播放时它们仍然听起来错误(较慢)。


进口米多
导入pygame
def播放游戏(歌曲):
pygame.init()
pygame.mixer.music.load(歌曲)
length=pygame.time.get_ticks()
pygame.mixer.music.play()
而pygame.mixer.music.get_busy():
pygame.time.wait(长度)
def main():
mid=mido.MidiFile()
track=mido.MidiTrack()
mid.tracks.append(曲目)
track.append(mido.MetaMessage('set_tempo',tempo=500000,time=3840))
track.append(mido.MetaMessage('end\u of_track',time=0))
track=mido.MidiTrack()
mid.tracks.append(曲目)
track.append(中间消息('note_on',channel=0,note=60,velocity=100,time=0))
track.append(中间消息('note_on'),