Skip to content

feat(midi): MIDI CC control surface for live performance#73

Merged
kfox merged 1 commit into
mainfrom
feat/midi-control-of-everything
Jul 8, 2026
Merged

feat(midi): MIDI CC control surface for live performance#73
kfox merged 1 commit into
mainfrom
feat/midi-control-of-everything

Conversation

@kfox

@kfox kfox commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds c64cast/midi_control.py, a process-wide MIDI control surface for live performance: scene jumps, style-cycle, transport (pause/resume/skip), and live effect/generator parameter sweeps, driven by MIDI CC/note/program-change messages.
  • Latency-first design: discrete actions reuse the existing Playlist Event-flag pattern (new Playlist.request_jump() generalizes skip_event); continuous CC sweeps use a new LIVE_PARAMS registry on FrameEffect/GenerativeSource for a direct, unlocked setattr() with no Event/frame-boundary indirection — the cheapest path in the system. No coalescing anywhere (unlike midi_scene.py), since this module never writes to the DMA socket.
  • New [midi_control] config section (MidiControlCfg) following the existing [control] process-wide pattern; ships a sensible default cc_map out of the box (16-pad scene-jump bank, transport, example knob bank); ensemble targeting by MIDI channel.
  • Fixes a latent doctor.py bug found along the way: print_report's category_order silently dropped any Diagnostic category it didn't already know about (including the new midi_control one) from the printed report, while still counting it in the summary totals.

Test plan

  • make check (ruff, mypy --strict, pyright, full test suite — 1953 tests) green
  • make schema regenerated, drift tests pass
  • 49 new unit tests: tests/test_midi_control.py (dispatch, channel targeting, crash guards, port selection, lifecycle), Playlist.request_jump() tests in tests/test_playlist.py, LIVE_PARAMS tests in tests/test_generative.py, print_report category-drift regression tests in tests/test_doctor.py
  • HW-verified on a real Ultimate 64 with a MIDI controller

Adds a process-wide midi_control.py service (scene jumps, style-cycle,
transport, live effect/generator param sweeps) driven by MIDI, so a
performer can control a running playlist in real time from a controller.
Every action routes through the cheapest correct mechanism for its
latency class — Playlist Events for discrete actions, a new
request_jump() primitive generalizing skip_event for scene jumps, and
direct unlocked setattr() via a new LIVE_PARAMS registry on
FrameEffect/GenerativeSource for continuous CC sweeps — with no
coalescing, since this module never writes to the DMA socket directly.

Ships a sensible default [midi_control].cc_map out of the box (16-pad
scene-jump bank + transport + an example knob bank) and targets
ensemble systems by MIDI channel. Verified end-to-end on real Ultimate
64 hardware with a KeyLab mkII 49: skip/cycle_style/toggle_pause/jump
and a live knob-driven param sweep all confirmed working.

Also fixes a doctor.py bug found along the way: print_report's
category_order omitted any category not already known, so a
Diagnostic in an uncovered category (like the new midi_control one)
would silently vanish from the printed report while still counting
toward the ok/warn/error totals.
@kfox kfox merged commit d96cb78 into main Jul 8, 2026
6 checks passed
@kfox kfox deleted the feat/midi-control-of-everything branch July 8, 2026 00:20
@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.91241% with 66 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.61%. Comparing base (4c0c297) to head (b4608d8).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
c64cast/config.py 37.83% 22 Missing and 1 partial ⚠️
c64cast/midi_control.py 87.64% 12 Missing and 9 partials ⚠️
c64cast/cli.py 0.00% 15 Missing ⚠️
c64cast/doctor.py 60.00% 3 Missing and 1 partial ⚠️
c64cast/playlist.py 91.66% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #73      +/-   ##
==========================================
- Coverage   79.65%   79.61%   -0.05%     
==========================================
  Files          76       77       +1     
  Lines       15403    15676     +273     
  Branches     2315     2373      +58     
==========================================
+ Hits        12269    12480     +211     
- Misses       2607     2657      +50     
- Partials      527      539      +12     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant