使用Python的mido库无法读取MIDI文件正确速度信息如何解决?
解决MIDI文件正确速度读取问题
核心排查方向
MuseScore能识别正确速度,说明速度信息肯定在文件里,大概率是你没遍历到所有轨道的消息,或者忽略了非标准的速度控制方式。以下是具体的Python实现方案:
1. 遍历所有轨道的set_tempo元消息
很多MIDI文件会把速度信息放在非首轨道(比如专门的标记轨道),或者存在多个速度变更事件。用mido遍历所有轨道的所有消息,筛选出所有set_tempo消息:
import mido def get_actual_tempo(midi_path): mid = mido.MidiFile(midi_path) default_tempo = 500000 # 对应120 BPM actual_tempo = None # 遍历所有轨道的所有消息 for track in mid.tracks: for msg in track: if msg.type == 'set_tempo': if msg.tempo != default_tempo: actual_tempo = msg.tempo # 转成BPM输出 print(f"找到实际速度: {mido.tempo2bpm(actual_tempo)} BPM") return actual_tempo # 如果所有set_tempo都是默认值,再确认一遍 if not actual_tempo: for track in mid.tracks: for msg in track: if msg.type == 'set_tempo': print(f"仅找到默认速度: {mido.tempo2bpm(msg.tempo)} BPM") return msg.tempo return default_tempo # 调用示例 get_actual_tempo("your_midi_file.mid")
2. 检查MIDI控制变更(CC)消息
部分MIDI文件会用控制号114的CC消息来调整速度(范围0-127,对应0-200%的基准速度),MuseScore会识别这类控制:
def check_cc_tempo(midi_path, base_bpm=120): mid = mido.MidiFile(midi_path) for track in mid.tracks: for msg in track: if msg.type == 'control_change' and msg.control == 114: speed_ratio = msg.value / 127 actual_bpm = base_bpm * speed_ratio print(f"通过CC消息识别速度: {actual_bpm:.2f} BPM") return actual_bpm return None # 调用示例 check_cc_tempo("your_midi_file.mid")
3. 极端情况:检查文本元消息
少数文件会把速度信息放在文本标记里(比如marker或text类型的元消息),可以额外排查:
def check_text_tempo(midi_path): mid = mido.MidiFile(midi_path) keyword = ["BPM", "速度"] for track in mid.tracks: for msg in track: if msg.type in ['text', 'marker']: for kw in keyword: if kw in msg.text: print(f"文本中找到速度相关信息: {msg.text}") return msg.text return None # 调用示例 check_text_tempo("your_midi_file.mid")
注意事项
ticks_per_beat是MIDI文件头的固定参数,不会随速度变化,你可以直接用mid.ticks_per_beat获取。- 如果以上方法都没找到,建议用十六进制编辑器查看MIDI文件的元数据段,重点找
FF 51 03开头的字节(set_tempo消息的标识),后面的3个字节就是微秒每拍的数值。
内容的提问来源于stack exchange,提问作者snaldi
相关产品推荐
相关产品推荐

