Skip to content

Rebuild config parsing and state ownership - #239

Open
sastraxi wants to merge 8 commits into
mainfrom
fix/longpress-unbind-config
Open

Rebuild config parsing and state ownership#239
sastraxi wants to merge 8 commits into
mainfrom
fix/longpress-unbind-config

Conversation

@sastraxi

@sastraxi sastraxi commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

This PR rebuilds the config path and the ownership of runtime state related to per-pedalboard and global hardware configuration. The old code had three faults:

  1. Config parsing and changes to application state occurred together.
  2. The file format and the runtime state shared the same types.
  3. Controller bindings stayed alive after a pedalboard change.

How to review

Read the files in this order. The first three are new.

# File What it does
1 pistomp/config/schema_v1.py Holds the file format. Parses, validates, and merges two layers.
2 pistomp/config/adapt_v1.py Holds the built-in defaults. Makes model types from file types.
3 pistomp/config/model.py Holds the frozen types that the application reads.
4 pistomp/current.py Current owns the bindings of one board. close() releases them.
5 pistomp/controller_manager.py bind() builds the bindings and the context rows onto the Current.
6 pistomp/hardware.py reinit() applies one resolved config. It does not merge layers.
7 pistomp/handler.py MIDI learn writes param.binding, then builds the board again.

Changes

  • Add msgspec. One declaration gives both the Python types and the JSON schema.
  • Split the config into three layers. Each layer is a pure function from one type to another.
  • Make the model types frozen. No code path changes a config after the load.
  • Move the merge out of Hardware.reinit().
  • Give Current the bindings of one board. The code that binds also closes.
  • Make reinit() total. A control that the config does not name goes back to its base binding.
  • Exclude the NAV encoder by type. Its id is a screen position, not a config key.
  • Refuse encoder id: 0 in the schema.
  • Delete pistomp/config.py and the string tokens that it used.
  • Update docs/architecture.md and GUIDE.md.

Fixes

  • A footswitch went dead after you unlearn it in MOD-UI. A plugin-bound switch has a ParamEffect PRESS row and no CC-toggle row. When the learned row went away, the switch had no PRESS row. MIDI learn now builds the board again, so the default row comes back. This needs Broadcast MIDI unlearn to all clients mod-ui#9 to be observable.
  • An unbound footswitch stayed lit. Footswitch.unbind_from_parameter() now resets toggled.
  • A pedalboard that cleared a section kept the controls of the board before it. The controls now go back to the base config.
  • The package blend re-exported its submodules. This made an import cycle: pistomp.controllerpistomp.configblendpistomp.controller. The re-exports are gone.

Files you can skip

These files have three lines or fewer of mechanical change, mostly Token.VOLUMEControlType.VOLUME:

GUIDE.md, blend/input_controller.py, blend/snapshot.py, blend/types.py, emulator/controls.py, emulator/hardware_v2.py, modalapistomp.py, pistomp/analogmidicontrol.py, pistomp/encoder_controller.py, plugins/base.py, pyproject.toml, tests/integration/conftest.py, tests/v3/conftest.py, tests/v3/nav_helpers.py, tests/v3/test_audio_midi_panel.py, tests/v3/test_footswitch_chords.py, tests/v3/test_notes_panel.py, tests/v3/test_startup.py

@sastraxi
sastraxi requested a review from rreichenbach August 22, 2026 21:17
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