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

Swift中如何利用MIDIInputPortCreateWithProtocol的srcConnRefCon区分多MIDI设备

区分CoreMIDI中多个BLE MIDI设备的正确方式

核心问题分析

你当前的代码错误在于在接收回调里执行了MIDIPortConnectSource操作——这个函数是用来建立端口和MIDI源的连接的,应该在初始化阶段调用,而不是收到MIDI数据时。另外,你对srcConnRefCon的类型转换逻辑有误,导致无法正确获取到对应的MIDI设备端点(MIDIEndpointRef)。

正确实现步骤

要通过srcConnRefCon区分设备,关键是在连接MIDI源时,将该源的MIDIEndpointRef作为自定义引用传递给MIDIPortConnectSource,之后在接收回调里直接还原这个引用即可。

1. 创建MIDI输入端口

首先创建输入端口,回调里只需要处理数据和解析srcConnRefCon:

var inputPort: MIDIPortRef = 0
let createStatus = MIDIInputPortCreateWithProtocol(
    client,
    "MidiMonitor Input Port" as CFString,
    MIDIProtocolID._1_0,
    &inputPort
) { midiEventList, srcConnRefCon in
    // 解析MIDI数据
    let eventPacket = midiEventList.pointee.packet
    let timeStamp = eventPacket.timeStamp
    let midiData = eventPacket.words.0
    
    // 从srcConnRefCon还原MIDIEndpointRef
    guard let srcRefPtr = srcConnRefCon else { return }
    let sourceEndpoint = srcRefPtr.load(as: MIDIEndpointRef.self)
    
    // 获取设备名称
    let displayName = self.getDisplayName(sourceEndpoint)
    print("MIDI Received From Source: \(displayName)")
    
    // 传递数据给代理
    self.delegate?.didReceiveMidiData(
        midiEventPacket: eventPacket,
        timeStamp: timeStamp,
        midiData: midiData,
        srcConnRefCon: sourceEndpoint
    )
}

guard createStatus == noErr else {
    print("Failed to create MIDI input port: \(createStatus)")
    return
}

2. 连接所有可用的MIDI源(包括BLE设备)

在初始化阶段(比如设备连接成功后),遍历所有MIDI输入源,将每个源的MIDIEndpointRef作为refCon传入连接函数:

func connectAllMIDISources() {
    let sourceCount = MIDIGetNumberOfSources()
    for index in 0..<sourceCount {
        let sourceEndpoint = MIDIGetSource(index)
        var endpointPtr = UnsafeMutableRawPointer(bitPattern: Int(sourceEndpoint))
        
        let connectStatus = MIDIPortConnectSource(
            inputPort,
            sourceEndpoint,
            endpointPtr
        )
        
        if connectStatus == noErr {
            print("Connected to MIDI source: \(getDisplayName(sourceEndpoint))")
        } else {
            print("Failed to connect to source: \(connectStatus)")
        }
    }
}

// 辅助函数:获取设备显示名称
func getDisplayName(_ endpoint: MIDIEndpointRef) -> String {
    var name: Unmanaged<CFString>?
    MIDIObjectGetStringProperty(endpoint, kMIDIPropertyDisplayName, &name)
    return name?.takeRetainedValue() as String? ?? "Unknown Device"
}

错误码解释

你之前看到的错误码对应含义:

  • -50:参数错误(你在回调里使用了无效的MIDIEndpointRef调用MIDIPortConnectSource)
  • -10832(kMIDIErrorAlreadyConnected):端口已经和该源建立过连接,重复调用导致错误

关键注意事项

  • 当BLE MIDI设备连接/断开时,需要监听MIDINotification,及时调用MIDIPortConnectSource或MIDIPortDisconnectSource更新连接状态
  • srcConnRefCon是你在连接时传入的自定义指针,必须保证其指向的对象在回调执行期间有效(这里用MIDIEndpointRef是安全的,因为它是CoreMIDI管理的引用)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 00:04:57