Наблюдайте уведомление о подключении устройства MIDI на iOS - PullRequest
0 голосов
/ 01 мая 2020

Есть ли API, который будет уведомлять меня, когда MIDI-устройство будет подключено к iOS устройству? Я пытался найти его среди API-интерфейсов CoreMidi, но мне это не удалось. Я могу только перечислить все подключенные устройства в данный момент.

Я хотел бы избежать опроса, если это возможно, поэтому это было бы полезно.

1 Ответ

0 голосов
/ 12 мая 2020

Да, вы можете использовать MIDIClient API. В частности, вот простая, автономная программа, которая будет печатать сообщения при добавлении, удалении устройств или изменении их свойств:

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)
}

Несколько замечаний:

  • Из Из всех системных API Apple, CoreMIDI может быть просто худшим из Swift. Это чистый C API, интенсивно использующий указатели, типы CoreFoundation, процедуры обратного вызова, структуры, типы которых известны только во время выполнения и т. Д. c. Вы видите, что здесь используется Unsafe(Raw)Pointers, перепрограммирование памяти и т. Д. c. Я думаю, что все еще имеет смысл просто использовать его из Objective- C и делать это в моих собственных проектах.
  • Не все MIDI-устройства фактически представлены как MIDI-устройства (ie. MIDIDeviceRef ). Некоторые используют драйвер, который создает виртуальные конечные точки, и они просто отображаются как (несвязанные) конечные точки источника и назначения. Вы должны выяснить, как справиться с этим самостоятельно. Устройства Native Instruments являются одним из распространенных примеров такого поведения.
  • Вы можете проверить MIKMIDI , что делает все это намного проще. В частности, вы просто должны:
var midiDevicesObserver: NSKeyValueObservation?
let deviceManager = MIKMIDIDeviceManager.shared
midiDevicesObserver = deviceManager.observe(\.availableDevices) { (dm, _) in
    print("Available MIDI devices changed: \(dm.availableDevices)")
}

или использовать также доступные MIKMIDIDeviceWasAddedNotification и связанные уведомления. Он также обрабатывает автоматическое объединение пар «источник / конечная точка» в устройства, позволяет вам задавать свойства устройства KVO (name, et c.) И кучу других вещей.

Отказ от ответственности: я основной автор и сопровождающий МИКМИДИ.

...