MIDI2CI
Discovery Module
MIDI-CI device discovery and capability inquiry with automatic lifecycle management.
CIManager
High-level actor for automatic MIDI-CI device discovery. Handles Discovery Inquiry broadcasts, response parsing, and device timeout detection.
public actor CIManager
Initialization
// Basic initialization
let transport = try CoreMIDITransport(clientName: "MyApp")
let ciManager = CIManager(transport: transport)
// With custom configuration
let config = CIManagerConfiguration(
discoveryInterval: 10.0,
deviceTimeout: 30.0,
autoStartDiscovery: true
)
let ciManager = CIManager(transport: transport, configuration: config)
Properties
| Property | Type | Description |
muid | MUID | This manager's unique identifier |
events | AsyncStream<CIManagerEvent> | Stream of discovery events |
discoveredDevices | [DiscoveredDevice] | All discovered devices |
peCapableDevices | [DiscoveredDevice] | Devices supporting Property Exchange |
Methods
| Method | Description |
start() | Start the CI manager and begin receiving |
stop() | Stop the CI manager |
startDiscovery() | Begin periodic Discovery Inquiry broadcasts |
stopDiscovery() | Stop periodic broadcasts |
device(for:) | Get device by MUID |
destination(for:) | Get MIDI destination for a device |
makeDestinationResolver() | Create resolver closure for PEManager |
Usage Example
let ciManager = CIManager(transport: transport)
try await ciManager.start()
// Listen for device events
for await event in ciManager.events {
switch event {
case .deviceDiscovered(let device):
print("Found: \(device.displayName)")
print(" MUID: \(device.muid)")
print(" PE Support: \(device.supportsPropertyExchange)")
case .deviceLost(let muid):
print("Lost device: \(muid)")
case .deviceUpdated(let device):
print("Updated: \(device.displayName)")
default:
break
}
}
CIManagerConfiguration
public struct CIManagerConfiguration: Sendable
| Property | Type | Default | Description |
discoveryInterval | TimeInterval | 5.0 | Seconds between Discovery Inquiry broadcasts |
deviceTimeout | TimeInterval | 15.0 | Seconds before a device is considered lost |
autoStartDiscovery | Bool | true | Auto-start discovery when start() is called |
respondToDiscovery | Bool | true | Respond to incoming Discovery Inquiries |
categorySupport | CategorySupport | .propertyExchange | Capabilities to advertise |
deviceIdentity | DeviceIdentity | .default | Device identity to advertise |
maxSysExSize | UInt32 | 0 | Max SysEx size (0 = no limit) |
CIManagerEvent
public enum CIManagerEvent: Sendable
| Case | Associated Value | Description |
deviceDiscovered | DiscoveredDevice | New device found |
deviceLost | MUID | Device timed out or invalidated |
deviceUpdated | DiscoveredDevice | Existing device replied again |
discoveryStarted | — | Discovery broadcasts started |
discoveryStopped | — | Discovery broadcasts stopped |
DiscoveredDevice
Represents a device discovered via MIDI-CI.
public struct DiscoveredDevice: Sendable, Identifiable, Hashable
| Property | Type | Description |
muid | MUID | Device's unique identifier |
identity | DeviceIdentity | Manufacturer, family, model, version |
categorySupport | CategorySupport | Supported MIDI-CI categories |
maxSysExSize | UInt32 | Maximum SysEx message size |
supportsPropertyExchange | Bool | True if PE is supported |
displayName | String | Human-readable device name |
CategorySupport
public struct CategorySupport: OptionSet, Sendable {
public static let protocolNegotiation: CategorySupport
public static let profileConfiguration: CategorySupport
public static let propertyExchange: CategorySupport
public static let processInquiry: CategorySupport
}
// Check device capabilities
if device.categorySupport.contains(.propertyExchange) {
// Device supports PE
}