MIDIMonitor
lists every MIDI source and prints and draws each message: connect a controller, touch each knob and pad, and see what it sends (MIDIInput.messages())
- Run
swift run --package-path Examples Example-Integration-MIDIMonitor- Imports
OllinMIDI- Source
- Examples/Integration/MIDIMonitor/Sketch.swift
import Ollin
import OllinMIDI
/// A live MIDI monitor. It listens to every connected MIDI device and shows
/// everything that arrives, so you can plug in a controller and discover what each
/// parameter, pad, and key sends just by touching it.
///
/// swift run Example-Integration-MIDIMonitor
///
/// Devices plugged in while it's running connect automatically. The companion
/// `MIDILoopback` example needs no hardware; this one is for real gear. See
/// `Docs/Integration/MIDI.md` for the full walkthrough.
@main
final class MIDIMonitor: Sketch {
lazy var midi = MIDIInput()
var log: [String] = [] // recent messages, newest last
var lastValue: Double = 0 // last scalar seen (0…1), for the pulse
var lastSeenFrame = -999
override func setup() {
do { try midi.start() }
catch { print("could not start MIDI input: \(error)") }
let names = midi.availableSources().map(\.name).joined(separator: ", ")
print("Listening to MIDI sources: \(names.isEmpty ? "(none yet — plug one in)" : names)")
noStroke()
}
override func draw() {
background(Color(white: 0.08))
// Drain everything received since the last frame: print it and keep a
// rolling on-canvas log.
for message in midi.messages() {
let line = message.description
print(line)
log.append(line)
if log.count > 22 { log.removeFirst(log.count - 22) }
if let value = message.value { lastValue = Double(value) / 127 }
else if let velocity = message.velocity { lastValue = Double(velocity) / 127 }
lastSeenFrame = frameCount
}
// A pulse, so motion is obvious when you wiggle a parameter or hit a pad.
let live = frameCount - lastSeenFrame < 30
fill(live ? Color(red: 0.55, green: 0.5, blue: 0.95) : Color(white: 0.3))
drawCircle(width - 120 * scale, 90 * scale, (18 + lastValue * 70) * scale)
// Header.
let names = midi.availableSources().map(\.name).joined(separator: ", ")
fill(Color(white: 0.95))
textSize(30 * scale)
drawText("MIDI monitor", 40 * scale, 70 * scale)
fill(Color(white: 0.5))
textSize(20 * scale)
drawText(names.isEmpty ? "no devices yet — plug one in" : names, 40 * scale, 105 * scale)
// The rolling message log.
textSize(22 * scale)
var y = 170.0 * scale
if log.isEmpty {
fill(Color(white: 0.4))
drawText("waiting for MIDI… turn a knob or press a key", 40 * scale, y)
}
fill(Color(white: 0.8))
for line in log {
drawText(line, 40 * scale, y)
y += 30 * scale
}
}
}