- Extract MIDI-out into a shared partial src/midiout.js (one copy, no drift); both
editors @BUILD:include it. The page wires three transport hooks: midiOutStart(t0)
in start(), midiOutStop() in stop(), midiOutClock(ahead) at end of scheduler();
engine.js calls onMeterHit() per hit.
- Clock-out: a "clock" checkbox (default on) appears with the port picker. When on:
MIDI Start (0xFA) at the downbeat, 24-PPQN clock (0xF8) scheduled across the audio
look-ahead window (timestamped, tracks tempo/ramp, stays tight), Stop (0xFC) on
stop. Guarded against starve-looping at extreme tempos.
- Mirror the feature into editor.html (PM_E-1): header .devctrl pills, the include,
_wireMidi port refresh, transport hooks, listener, and the _isDevicePort fix
(recognizes PM_G-1 Grid etc.).
Conformance suite still green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
engine.js: add an opt-in per-hit hook in scheduleMeterTick — onMeterHit(sound,
time, lvl) — called only if a page defines it (no-op everywhere else). Lets a
page emit MIDI per scheduled hit, in lockstep with the audio scheduler.
pm_e-2.html: a "🎛 MIDI out" header toggle + output-port picker. When on, each
groove hit is sent as a GM drum Note-On (channel 10; note from SOUND_GM e.g.
kick*->36, snare*->38, hat*->42; velocity by accent/normal/ghost) to the chosen
port via output.send([..], ts) with a timestamp derived from the hits audio time
(performance.now() + (time - audioCtx.currentTime)*1000) for tight sync; a note-off
follows 60ms later. Port list prefers a non-PM output (the external gear) and
refreshes on MIDI connect/disconnect. Independent of the local synth + Device
audio; goes green (blue) when on. Web MIDI (Chrome/Edge/Firefox).
Conformance suite still green (engine.js change is in the scheduler, not the codec).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Landing (index.html):
- Remove the PM_E-1 (editor.html) viewport; default the live viewport to PM_E-2.
- Repoint the vp-bar + the "design in the editor" link to pm_e-2.html. editor.html
still exists, just not featured on the landing.
PM_E-2 editor (pm_e-2.html) - the device-connection badge + Device-audio toggle:
- Group both in the header as matching .devctrl pills, side by side.
- Clear tooltips spelling out exactly what each does: the badge only REPORTS the
USB-MIDI link (green + name when a PM device is plugged in); Device audio is an
on/off switch that routes a connected device through the computer speakers and
does not require a device to toggle.
- Device-audio button now shows on/off state via colour (green when on), matching
the badge, instead of the .primary class (which clashed with the pill style).
- Fix _isDevicePort: it only matched pico/circuitpython/pimoroni/varasys, so the
native Rust devices ("PM_G-1 Grid" etc.) were never recognized -> the badge
stayed "no device" even when connected. Now matches pm_g/pm_k/pm_x/grid/polymeter.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
editor.html + pm_e-2.html called _ensureMidi() (requestMIDIAccess{sysex:true}, which always
prompts) on page load. Gate it behind a permission query — only auto-reconnect if MIDI is
already granted (querying does not prompt); otherwise wait for the user to click the connect
badge / Device-audio button. (editor-beta.html already had no on-load MIDI call.)