如何用Music21检测MIDI文件中的转调?现有代码仅识别初始调
检测MIDI文件中的转调方法
你当前用midi_data.analyze('key')得到的是整个MIDI文件的全局调式分析,自然无法识别中途的转调。要检测转调,核心思路是把MIDI文件拆分成更小的片段(比如按小节、按固定时长),对每个片段单独做调式分析,再通过对比片段间的调式变化来定位转调位置。
具体实现步骤(以按小节分割为例)
- 解析MIDI文件后,遍历其中的每个小节;
- 对每个小节的音乐内容单独进行调式分析;
- 记录每个小节的调式,对比相邻小节的调式差异,判断转调发生的位置。
示例代码
import music21 as m21 # 解析MIDI文件 midi_data = m21.converter.parse("your_midi_file.mid") # 遍历所有小节,记录每个小节的调式 previous_key = None for idx, measure in enumerate(midi_data.parts[0].measures(1, None)): # 取第一声部的所有小节 # 分析当前小节的调式 current_key = measure.analyze('key') # 跳过空小节或调式不明确的情况 if not current_key: continue # 对比前一个小节的调式,判断转调 if previous_key and current_key.name != previous_key.name: print(f"在第{idx+1}小节发生转调:从{previous_key.name}转到{current_key.name}") previous_key = current_key # 如果需要全局初始调式,仍可以保留全局分析 global_key = midi_data.analyze('key') print(f"全局初始调式:{global_key.name}")
优化建议
- 过滤短暂离调:如果只是单个小节的调式变化,可能是临时离调而非真正转调,可以设置连续2-3个小节调式一致才判定为转调;
- 按时长分割:如果MIDI没有明确的小节划分,可以用
midi_data.splitAtQuarterLength()按固定节拍长度分割片段(比如每4拍一个片段); - 多声部合并分析:如果MIDI有多个声部,可以把所有声部的音符合并后再分析片段调式,避免单声部的局部偏差。
内容的提问来源于stack exchange,提问作者pycat
相关产品推荐
相关产品推荐

