You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 20:50:06