Architecture Overview

How MIDI2Kit's modules work together and the design principles behind the library.

Module Overview

┌─────────────────────────────────────────────────────────────┐ │ Your Application │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ MIDI2Kit │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ CIManager │──│ PEManager │ │ CIManagerPEExtension│ │ │ │ (Discovery)│ │ (Property │ │ (Convenience) │ │ │ └─────────────┘ │ Exchange) │ └─────────────────────┘ │ │ └─────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ┌─────────────────────┼─────────────────────┐ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ MIDI2CI │ │ MIDI2PE │ │ MIDI2Core │ │ Discovery │ │ Property │ │ UMP Types │ │ Messages │ │ Exchange │ │ MUID │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ └─────────────────────┼─────────────────────┘ ▼ ┌─────────────────┐ │ MIDI2Transport │ │ (MIDITransport │ │ Protocol) │ └─────────────────┘ │ ┌───────────────┴───────────────┐ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ CoreMIDITransport│ │ MockMIDITransport│ │ (Production) │ │ (Testing) │ └─────────────────┘ └─────────────────┘ │ ▼ ┌───────────┐ │ CoreMIDI │ │ (Apple) │ └───────────┘

Layer Architecture

Layer 1: Foundation (MIDI2Core)

Zero dependencies. Contains pure data types and utilities:

Layer 2: Transport (MIDI2Transport)

Abstraction layer for MIDI I/O:

Layer 3: Protocol (MIDI2CI, MIDI2PE)

MIDI-CI protocol implementation:

Layer 4: High-Level API (MIDI2Kit)

User-facing convenience layer:

Data Flow

Outgoing (Send)

Application │ │ peManager.get("DeviceInfo", from: muid) ▼ PEManager │ Build PE Get Inquiry message │ Allocate Request ID │ Set up timeout ▼ CIMessageBuilder │ Build SysEx bytes ▼ MIDITransport.send() │ ▼ CoreMIDI / Mock

Incoming (Receive)

CoreMIDI / Mock │ │ MIDIReceivedData ▼ MIDITransport.received (AsyncStream) │ ▼ CIManager / PEManager │ Parse message type │ Route to handler ▼ CIMessageParser │ Extract fields │ Validate MUID ▼ Handler │ Discovery: Update device list, emit event │ PE Reply: Assemble chunks, resume continuation ▼ Application (via async/await or event stream)

Design Decisions

Actor-based Concurrency

Both CIManager and PEManager are actors, providing:

Protocol-based Transport

The MIDITransport protocol enables:

Destination Resolver Pattern

PEManager uses a resolver closure to decouple from CIManager:

Event Streams vs. Delegates

We use AsyncStream instead of delegates because:

Single Source of Truth

Responsibilities are clearly separated: