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

Music21基于MIDI通道10移除打击乐时如何修正音符时序问题

问题根因

时序异常是因为你的代码遗漏了三个核心处理逻辑:

  1. 调用midiTracksToStreams将MIDI轨道转换为流对象时,没有传入原MIDI文件的ticksPerQuarterNote(每四分音符对应的tick数)参数,导致时间刻度换算错误,直接引发音符时序错位。
  2. 通道号判断存在偏差:MIDI规范中日常提及的「10号打击乐通道」是1-based计数,而代码层面读取到的通道编号是0-based计数,实际对应的索引值为9,你写的event.channel == 10匹配不到正确的打击乐通道。
  3. 轨道过滤逻辑有隐性风险:如果存在单轨道混合多通道的情况,直接删除整轨会误删同轨的非打击乐声部。

修复方案

方案1:基于你现有MidiFile处理逻辑修复

import music21

path = 'lld.midi'
m = music21.midi.MidiFile()
m.open(path)
m.read()
m.close()

tracks = []
for track in m.tracks:
    keep_track = True
    for event in track.events:
        # 仅对带channel属性的MIDI消息做判断,跳过全局元事件
        if hasattr(event, 'channel') and event.channel == 9:
            keep_track = False
            break
    if keep_track:
        tracks.append(track)

# 转换时传入原文件的时间刻度参数,保证时序正确
s = music21.midi.translate.midiTracksToStreams(
    tracks, 
    ticksPerQuarter=m.ticksPerQuarterNote,
    quantizePost=False
)
s.write('midi', 'no-percussion.midi')

方案2:基于converter.parse的更稳妥实现

你之前用converter.parse读写的逻辑本身没有时序问题,直接在流层级过滤打击乐声部更简单,出错概率更低:

import music21

path = 'lld.midi'
score = music21.converter.parse(path, 
    forceSource=False, 
    quantizePost=False,
).stripTies(inPlace=True)  

# 移除所有绑定打击乐通道的声部
for part in score.parts:
    if part.getInstrument().midiChannel == 9:
        score.remove(part)

score.write('midi', 'no-percussion.midi')

内容的提问来源于stack exchange,提问作者duhaime

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 09:24:04