在 iOS 上观察 MIDI 设备连接通知

Mar*_*und 1 ios coremidi swift

当 MIDI 设备连接到 iOS 设备时,是否有 API 会通知我?我一直试图在 CoreMidi API 中找到它,但没有成功。我只能在给定时刻列出所有连接的设备。

如果可能,我想避免投票,所以这将是有益的。

And*_*sen 5

是的,您可以使用MIDIClientAPI。具体来说,这是一个简单的、自包含的程序,它将在添加、删除设备或更改其属性时打印消息:

import Cocoa
import CoreMIDI

var client = MIDIClientRef()
let clientName = "MyMIDIClient" as CFString
let err = MIDIClientCreateWithBlock(clientName, &client) { (notificationPtr: UnsafePointer<MIDINotification>) in
    let notification = notificationPtr.pointee
    switch notification.messageID {
        case .msgSetupChanged: // Can ignore, really
            break

        case .msgObjectAdded:
            let rawPtr = UnsafeRawPointer(notificationPtr)
            let message = rawPtr.assumingMemoryBound(to: MIDIObjectAddRemoveNotification.self).pointee
            print("MIDI \(message.childType) added: \(message.child)")

        case .msgObjectRemoved:
            let rawPtr = UnsafeRawPointer(notificationPtr)
            let message = rawPtr.assumingMemoryBound(to: MIDIObjectAddRemoveNotification.self).pointee
            print("MIDI \(message.childType) removed: \(message.child)")

        case .msgPropertyChanged:
            let rawPtr = UnsafeRawPointer(notificationPtr)
            let message = rawPtr.assumingMemoryBound(to: MIDIObjectPropertyChangeNotification.self).pointee
            print("MIDI \(message.object) property \(message.propertyName.takeUnretainedValue()) changed.")

        case .msgThruConnectionsChanged:
            fallthrough
        case .msgSerialPortOwnerChanged:
            print("MIDI Thru connection was created or destroyed")

        case .msgIOError:
            let rawPtr = UnsafeRawPointer(notificationPtr)
            let message = rawPtr.assumingMemoryBound(to: MIDIIOErrorNotification.self).pointee
            print("MIDI I/O error \(message.errorCode) occurred")

        default:
            break
    }
}

if err != noErr {
    print("Error creating MIDI client: \(err)")
}

let rl = RunLoop.current
while true { 
    rl.run(mode: .default, before: .distantFuture)
}
Run Code Online (Sandbox Code Playgroud)

一些注意事项:

  • 在所有 Apple 系统 API 中,CoreMIDI 可能是 Swift 中最糟糕的一个。它是一个纯 C API,大量使用指针、CoreFoundation 类型、回调过程、类型仅在运行时才知道的结构等。你在这里看到的使用Unsafe(Raw)Pointers、重新绑定内存等。我认为它仍然使更多从 Objective-C 中使用它是有意义的,并在我自己的项目中使用它。
  • 并非所有 MIDI 设备实际上都作为 MIDI 设备(即MIDIDeviceRef)出现。有些使用创建虚拟端点的驱动程序,而那些只显示为(不相关的)源和目标端点。您必须自己弄清楚如何处理这些问题。Native Instruments 的设备是这种行为的一个常见示例。
  • 您可以查看MIKMIDI,它使所有这一切变得更加容易。具体来说,您只需执行以下操作:
var midiDevicesObserver: NSKeyValueObservation?
let deviceManager = MIKMIDIDeviceManager.shared
midiDevicesObserver = deviceManager.observe(\.availableDevices) { (dm, _) in
    print("Available MIDI devices changed: \(dm.availableDevices)")
}
Run Code Online (Sandbox Code Playgroud)

或使用也可用MIKMIDIDeviceWasAddedNotification和相关的通知。它还可以自动将源/端点对合并到设备中,允许您使用 KVO 设备属性(名称等),以及一堆其他东西。

免责声明:我是 MIKMIDI 的主要作者和维护者。