从 MIDI 轨道弹出消息

Posted

技术标签:

【中文标题】从 MIDI 轨道弹出消息【英文标题】:Popping Messages from MIDI Tracks 【发布时间】:2020-04-19 21:25:56 【问题描述】:

我有类型 0 的 MIDI 文件,包含只有 269 个元消息的轨道,我想保留标题块和文件末尾的最后一个。

for i, msg in enumerate(mid.tracks[0]):
    if i > 10 or i < len(mid.tracks[0])-1:
        if msg.is_meta:
            mid.tracks[0].pop(i)

上面的代码,没有这样做。事实上,它恰好删除了一半的消息(其中 135 条),它还删除了开头和结尾,我必须运行它几次才能让它接近 10 条元消息!

library 说:

pop([index]) → item -- 删除并返回索引处的项目(默认最后一个)。 如果列表为空或索引超出范围,则引发 IndexError。

我也尝试了另一种方法,但同样,每次只删除一半。所以我需要多次运行循环以使其接近我想要的大小:

while len(mid.tracks[0])>16:
    for i, msg in enumerate(mid.tracks[0]):
        if msg.is_meta and hasattr(msg, 'data'): 
            if len(msg.data) == 7:
                mid.tracks[0].remove(msg)

for i, msg in enumerate(mid.tracks[0]):
    if msg.is_meta:
        print(i, msg)

请问我做错了什么?

【问题讨论】:

您真的不应该在对象的循环内修改对象。当您致电pop(i) 时,您会遇到麻烦。也许创建一个“删除”列表并单独删除它们。 好像是随机弹出的!我就是这么做的。并编辑了 OP。谢谢你的回答。 您能否也对此发表评论:***.com/questions/61305523/…。我真的很感激。 【参考方案1】:

这样的事情可能会更快。请注意,代码可能与您的数据不完全匹配。如果您发布 mid.tracks[0] 的值,我可以为您提供更好的结果。

t = mid.tracks[0] # shorthand to simplify code
keep = t[:10] + t[-1:] # get first ten and last one
# keep only the non-meta ones
result = [msg for msg in keep if not msg.is_meta]

注:根据评论修改。

【讨论】:

你的第二行:TypeError: can only concatenate list (not "MetaMessage") to list! 尝试t[-1:] 而不是t[-1]。如果没有,请尝试[t[-1]]。这完全取决于你的mid.tracks[0] 对象到底是什么。也许您可以发布对象的转储?

以上是关于从 MIDI 轨道弹出消息的主要内容,如果未能解决你的问题,请参考以下文章

读取 MIDI 文件

BLE MIDIMIDI 文件格式分析 ( MIDI 轨道分析 | MIDI 轨道头 | MIDI 轨道长度 | delta-time 间隔 )

BLE MIDIMIDI 文件格式分析 ( MIDI 轨道分析 | MIDI 轨道头 | MIDI 轨道长度 | delta-time 间隔 )

MIDI 通道轨道相关

BLE MIDIMIDI 文件格式分析 ( MIDI 文件头解析 | MIDI 文件头标识 | MIDI 文件头长度 | MIDI 文件格式 | MIDI 轨道个数 | 基本时间 )

BLE MIDIMIDI 文件格式分析 ( MIDI 文件头解析 | MIDI 文件头标识 | MIDI 文件头长度 | MIDI 文件格式 | MIDI 轨道个数 | 基本时间 )(代码