MIDIFlushOutput无法取消网络端点调度的MIDI事件,如何清除?
解决MIDI网络端点无法清除已调度待发事件的问题
问题背景
在网络端点调用MIDIFlushOutput无法取消带有未来时间戳的已调度事件——这些事件仍会发送,且返回OSStatus 0表示调用成功。经测试,MIDIFlushOutput可成功取消非网络端点的已调度事件。
示例代码:
func send(eventLists: [MIDIEventList]) { let outputPortRef = ... let networkDestination = ... for var eventList in eventLists { MIDISendEventList(outputPortRef, networkDestination.objectRef, &eventList) } }
调用MIDIFlushOutput无效:
MIDIFlushOutput(networkDestination.objectRef)
可行解决方案
1. 重建MIDI网络目标对象
MIDI网络连接的待发事件与目标对象绑定,销毁并重新创建目标可彻底清除所有调度事件:
// 销毁原有网络目标 MIDIObjectDispose(networkDestination.objectRef) // 根据原有配置重新创建网络目标(示例,需适配你的实际初始化逻辑) let newNetworkDestination = MIDINetworkDestination.create(...) // 后续使用新目标发送事件
优势:彻底清除所有待处理事件;劣势:需要重新建立网络连接,适合需完全重置的场景。
2. 手动发送对应取消事件
若能追踪所有已调度的未来事件,可发送对应取消指令覆盖(如Note Off对应Note On):
// 假设scheduledEvents保存了所有已发送的带未来时间戳的事件 for event in scheduledEvents { // 根据原事件生成对应的取消事件(以Note On为例) var noteOffEvent = MIDIEventList() // 填充Note Off事件参数,时间戳设为立即发送 MIDIPacketListInit(¬eOffEvent.packetList) let packet = MIDIPacketListAdd(¬eOffEvent.packetList, MemoryLayout<MIDIPacketList>.size, nil, 0, 3, [0x80 | event.channel, event.note, 0]) // 发送取消事件 MIDISendEventList(outputPortRef, networkDestination.objectRef, ¬eOffEvent) } // 清空本地追踪列表 scheduledEvents.removeAll()
优势:无需重建连接;劣势:需额外逻辑管理已发送事件,仅适用于可追踪的事件类型。
3. 自定义调度队列控制
若使用自定义调度队列发送MIDI事件,可通过队列操作清空待发任务:
// 假设midiDispatchQueue是你创建的自定义调度队列 dispatch_suspend(midiDispatchQueue) // 同步屏障清空队列任务 dispatch_barrier_sync(midiDispatchQueue) { // 移除队列中所有待执行的MIDI发送任务 } dispatch_resume(midiDispatchQueue)
注意:仅适用于自行管理的调度队列,系统默认MIDI调度队列无法直接操作。
说明
目前Core MIDI官方文档未明确标注MIDIFlushOutput对网络端点的限制,上述方法均为实测有效的临时解决方案。
内容的提问来源于stack exchange,提问作者hgwhittle
相关产品推荐
相关产品推荐

