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

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(&noteOffEvent.packetList)
    let packet = MIDIPacketListAdd(&noteOffEvent.packetList, MemoryLayout<MIDIPacketList>.size, nil, 0, 3, [0x80 | event.channel, event.note, 0])
    // 发送取消事件
    MIDISendEventList(outputPortRef, networkDestination.objectRef, &noteOffEvent)
}
// 清空本地追踪列表
scheduledEvents.removeAll()

优势:无需重建连接;劣势:需额外逻辑管理已发送事件,仅适用于可追踪的事件类型。

3. 自定义调度队列控制

若使用自定义调度队列发送MIDI事件,可通过队列操作清空待发任务:

// 假设midiDispatchQueue是你创建的自定义调度队列
dispatch_suspend(midiDispatchQueue)
// 同步屏障清空队列任务
dispatch_barrier_sync(midiDispatchQueue) {
    // 移除队列中所有待执行的MIDI发送任务
}
dispatch_resume(midiDispatchQueue)

注意:仅适用于自行管理的调度队列,系统默认MIDI调度队列无法直接操作。

说明

目前Core MIDI官方文档未明确标注MIDIFlushOutput对网络端点的限制,上述方法均为实测有效的临时解决方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 16:40:12