使用python-mido转换Ableton Live 11导出MIDI的时间戳与BPM计算问题
问题解答:Ableton导出MIDI文件调制轮数据时间转换错误问题
问题原因解释
1. 参数误用:混淆了两个完全不同的MIDI参数
你之前的计算逻辑错误核心是误用了time_signature元消息里的clocks_per_click参数,该参数的作用是定义节拍器每一次点击对应的MIDI时钟滴答数,仅用于节拍器同步场景,和MIDI文件内事件的时间刻度转换毫无关系。
你应该使用的是**MIDI文件头自带的ticks_per_beat(每四分音符脉冲数,简称PPQN)**参数,这个参数是所有标准MIDI文件都内置的属性,不需要读取任何轨道内的元消息即可获取。
2. 计算逻辑错误
你代码里的quarter_note_seconds = beat_seconds / 4是完全错误的:BPM的定义就是「每分钟的拍数」,通用MIDI规范里的拍默认对应四分音符,因此beat_seconds = 60 / bpm本身就是单个四分音符的秒数,不需要额外除以4。
你之前代入24得到正确结果,只是两个错误叠加后刚好和测试文件的场景匹配,属于巧合,不具备通用性。
正确的时间转换方案(无需依赖set_tempo元消息)
因为你已经可以通过参数传入正确的BPM值,只需要按以下逻辑计算即可:
import mido # 读取MIDI文件 mid = mido.MidiFile('目标MIDI文件路径.mid') # 从文件头直接读取ticks_per_beat ticks_per_beat = mid.ticks_per_beat # 你传入的BPM参数 input_bpm = 120 # 单个四分音符对应的秒数 quarter_note_sec = 60 / input_bpm # 单个MIDI tick对应的秒数 tick_sec = quarter_note_sec / ticks_per_beat current_total_sec = 0 mod_wheel_table = [] for track in mid.tracks: for msg in track: # 累加当前消息的时间偏移 current_total_sec += msg.time * tick_sec # 筛选调制轮控制消息(控制器编号固定为1) if msg.type == 'control_change' and msg.control == 1: mod_wheel_table.append([current_total_sec, msg.value])
最终输出的mod_wheel_table就是秒级时间戳+调制轮数值的二元列表,可直接导出为两列表格使用。
内容的提问来源于stack exchange,提问作者Joël Tuberosa
相关产品推荐
相关产品推荐

