如何从MIDI文件中获取标记(Marker)及对应小节数?
获取MIDI标记及对应小节数的实现方法
你可以通过以下两种方式实现同时获取MIDI标记和对应的小节数:
方法一:纯music21实现(推荐)
music21本身提供了直接解析Marker对象并计算小节数的能力,无需额外依赖mido,处理时间签名、速度变化等场景更准确:
from music21 import converter # 加载目标MIDI文件 archivo_midi = 'Song.mid' midi_stream = converter.parse(archivo_midi) # 遍历展开后的所有音乐元素,筛选Marker类型 for element in midi_stream.flat: if element.isClassOrSubclass('Marker'): etiqueta = element.text # 通过offset计算对应的小节数 numero_compas = midi_stream.measureNumberFromOffset(element.offset) print(f"Etiqueta: {etiqueta}, 小节数: {numero_compas}")
关键说明
midi_stream.flat:将嵌套的音乐流展开,确保能遍历到所有层级的Marker对象measureNumberFromOffset():自动根据元素的时间偏移量(以四分音符为单位)计算小节数,已处理时间签名变更、速度变化等复杂情况
方法二:结合mido与music21(适配原有代码)
如果需要保留原有mido遍历消息的逻辑,可以通过累计tick数转换为时间偏移量,再用music21计算小节数:
from music21 import converter import mido archivo_midi = 'Song.mid' mid = mido.MidiFile(archivo_midi) midi_stream = converter.parse(archivo_midi) ticks_per_beat = mid.ticks_per_beat cumulative_ticks = 0 for msg in mid: # 累计所有消息的相对时间(tick单位) cumulative_ticks += msg.time if msg.type == 'marker': etiqueta = msg.text # 将tick转换为music21的四分音符时间偏移量 offset = cumulative_ticks / ticks_per_beat # 获取对应小节数 numero_compas = midi_stream.measureNumberFromOffset(offset) print(f"Etiqueta: {etiqueta}, 小节数: {numero_compas}")
关键说明
cumulative_ticks:累计所有MIDI消息的相对时间,确保标记的时间位置准确- 转换tick为offset时,依赖MIDI文件的
ticks_per_beat参数,将原始tick单位转为music21兼容的四分音符单位
内容的提问来源于stack exchange,提问作者abeh
相关产品推荐
相关产品推荐

