AudioKit解析单轨Format1 MIDI文件失败,如何绕过该限制?
解决AudioKit处理格式1单轨道MIDI文件的轨道丢失问题
方案1:批量预处理修改MIDI文件格式
直接把格式1的单轨道MIDI改成格式0(单轨道标准格式),从根源上规避AudioKit的判断逻辑。用midicsv工具批量处理很方便:
- 转MIDI为CSV:
midicsv input.mid output.csv - 打开CSV文件,把第一行的格式字段从
1改成0。比如原第一行是0, 0, Header, 1, 1, 480,修改后为0, 0, Header, 0, 1, 480 - 转CSV回MIDI:
csvmidi output.csv fixed.mid
方案2:绕过AudioKit的轨道过滤逻辑
扩展MIDIFileTrack暴露初始化器
如果项目允许修改AudioKit源码或使用模块内部扩展,给MIDIFileTrack加个公开初始化器:
extension MIDIFileTrack { public init?(chunk: MIDIFileChunk) { self.init(chunk: chunk) } }
之后直接跳过默认的tracks属性,自己处理所有轨道:
let midiFile = try MIDIFile(url: midiURL) let allTracks = midiFile.trackChunks.compactMap { MIDIFileTrack(chunk: $0) } // 这里不会丢弃任何轨道,不管文件格式是1还是0
用反射读取私有事件数据
如果不能修改AudioKit源码,用Swift反射提取轨道事件:
let midiFile = try MIDIFile(url: midiURL) for chunk in midiFile.trackChunks { let mirror = Mirror(reflecting: chunk) guard let events = mirror.children.first(where: { $0.label == "events" })?.value as? [MIDIFileChunkEvent] else { continue } // 手动转换MIDIFileChunkEvent为MIDIEvent let midiEvents = events.compactMap { event -> MIDIEvent? in switch event { case .noteOn(let data): return .noteOn(data.noteNumber, velocity: data.velocity, channel: data.channel, time: data.time) case .noteOff(let data): return .noteOff(data.noteNumber, velocity: data.velocity, channel: data.channel, time: data.time) // 按需补充其他事件类型(如控制变化、程序变更等) default: return nil } } // midiEvents就是当前轨道的所有事件,可自行处理 }
方案3:给AudioKit提交修复PR
AudioKit当前逻辑假设格式1的第一个轨道是tempo轨道,但忽略了格式1却只有单轨道的非标准情况。可以修改tracks属性的判断条件,只有当轨道数大于1时才丢弃第一个:
public var tracks: [MIDIFileTrack] { var tracks = trackChunks if format == 1, tracks.count > 1 { // 仅多轨道时丢弃第一个 tracks = Array(tracks.dropFirst()) } return tracks.compactMap({ MIDIFileTrack(chunk: $0) }) }
这个改动既保留了原有逻辑的兼容性,又能正确处理单轨道的格式1文件。
内容的提问来源于stack exchange,提问作者user82395214
相关产品推荐
相关产品推荐

