Skip to content

Feature/effect state per rig#102

Open
danmigdev wants to merge 13 commits into
Tunetown:mainfrom
danmigdev:feature/effect-state-per-rig
Open

Feature/effect state per rig#102
danmigdev wants to merge 13 commits into
Tunetown:mainfrom
danmigdev:feature/effect-state-per-rig

Conversation

@danmigdev

Copy link
Copy Markdown

Assign different effect slots per rig. The same button always controls the right effect, regardless of how slots are organized on the Kemper.

The problem it solves

In the Kemper, each rig distributes its effects across slots (A, B, C, D, X, MOD, DLY, REV).
With PySwitch, each button controls a specific slot — for example button 1 always controls slot A.
The problem arises when different slots hold different types of effects depending on the rig:

Slot A Slot B Slot C Slot X
Rig 1 Compressor Chorus Delay Reverb
Rig 2 Distortion Compressor Chorus Delay
Rig 3 Wah Delay Compressor Reverb

Button 1 (Slot A): activates Compressor on Rig 1, but Distortion on Rig 2 and Wah on Rig 3.

With EFFECT_STATE_PER_RIG you can specify a default slot and then overrides for specific rigs.
When you change rig, the button automatically points to the correct slot, updating the LED and
display in real time.

Button 1 Button 2 Button 3 Button 4
Default Slot A Slot B Slot C Slot X
Rig 2 Slot B ← Slot A ← Slot C Slot X
Rig 3 Slot C ← Slot B Slot A ← Slot X
Rig 4 None ← Slot B Slot A Slot X

Setting a slot to None disables the button for that rig: the LED turns off and the display
is cleared, indicating that no effect is assigned to that button on the current rig.

jcthalys and others added 13 commits February 23, 2026 22:49
- Add CYAN color to colors.py (was missing, used for Compressor/Gate)
- Fix effect type number ranges to match Kemper MIDI spec (Appendix B)
- Add 4 missing categories: Tremolo, Rotary, Vibrato, Slicer/Autopanner
  (previously all misidentified as Chorus)
- Fix all LED colors to match official Kemper Profiler Manual:
  Compressor/Gate=Cyan, Looper=Pink, Chorus family=Blue,
  Dual/Pitch Delays=Light Green, Booster=Red
- Fix Delay range (145-166) and Reverb range (177-193) for 14-bit
  decoded NRPN values
- Unknown type values now return CATEGORY_NONE instead of CATEGORY_REVERB
Adds a new action EFFECT_STATE_PER_RIG that works like EFFECT_STATE
but allows assigning a different Kemper effect slot per rig. When the
active rig changes, the button automatically controls the slot defined
in the rig_overrides mapping, falling back to the default slot_id.

- content/lib/pyswitch/clients/kemper/actions/effect_state_per_rig.py:
  KemperEffectEnablePerRigCallback tracks RIG_ID via MIDI and routes
  LED/display updates and MIDI CC sends to the correct slot per rig.
- web/htdocs/definitions/actions.json: register EFFECT_STATE_PER_RIG
- web/htdocs/definitions/meta.json: add rig_map parameter type entry
- web/htdocs/js/ui/parser/ActionProperties.js: add rig_map UI widget
  (Bank/Rig/Slot table with add/remove rows, round-trip serialization)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Self-contained HTML page covering:
- Problem explanation with visual slot diagrams
- Device installation (file copy path)
- Web editor patch installation
- Manual inputs.py configuration with rig_overrides syntax
- Web editor UI walkthrough with UI mockup
- Absolute rig ID formula and reference table
- Practical configuration examples

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- None slot support: button disabled for specific rigs (LED off, label cleared)
- Web editor: fix rig_map parameter type registration in meta.json
  (added category/target so action appears in Effects list)
- Web editor: fix ActionProperties onChange scope bug
- Web editor: fix rig_map round-trip deserialization (parseInt on quoted keys)
- Web editor: fix ParameterMeta.getDefaultValue for rig_map type
- Web editor: register effect_state_per_rig.py in PySwitchRunner module list
- Web editor: bump to 2.4.9.16
- serve.py: local dev server replacing Apache+PHP (Ctrl+C fix, connection reset handling)
- docs: translate effect_state_per_rig.html to English
- Bump firmware version to 2.4.9

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ies-and-colors' into feature/effect-state-per-rig
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SwitchController now reads "color" and "brightness" from switch config dict
- Default brightness changed from 0.5 to 0 (LEDs off by default)
- Web editor: added LED Color and LED Brightness fields in switch settings panel
- ParserInput: added color()/setColor()/brightness()/setBrightness() methods
- ParserTreeElement: added removeArgument() method

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… logic for EFFECT_STATE_PER_RIG

- inputs.py: re-apply configured brightness after action init loop for switches
  where no action drives the LEDs, preventing ledBrightnessOff from leaving
  the switch lit at startup
- wrap_adafruit_led.py: render (0,0,0) as solid black instead of transparent
  so switches appear dark in the web emulator when brightness is 0
- effect_state_per_rig.py: add multi-slot (list) support with AND logic —
  LED shows ON only when all slots are ON; color/label derived from first slot
- ActionProperties.js / parser-action-properties.css: rig_map UI supports
  multiple slots per rig row
- ParameterList.js / InputSettings.js: add validate callback support and
  brightness range validation for the LED Brightness input
- list-browser.css: add medium-width variant for popups
- test_input_controller_switch.py: update expected default brightness to 0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ault

When slot_id=None the button is disabled for all rigs that have no entry in
rig_overrides, avoiding the need to explicitly list every rig with None.

- effect_state_per_rig.py: normalize rig_overrides before super().__init__,
  resolve a stand-in parent slot when slot_id is None, reuse parent mappings
  to avoid duplicate MIDI registrations, return None from _current_slots()
  when no override matches and default slot is None
- meta.json: add per-entity slot_id override for EFFECT_STATE_PER_RIG with
  "None (disabled by default)" as first option, leaving other actions unchanged

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… A-E

- Rewrite content/inputs.py and content/display.py from scratch for a
  5-switch EFFECT_STATE_PER_RIG setup (switches 1-2 disabled, 3-5 per-rig
  effects) plus rig select on switches A-E with bank up/down on hold
- Use literal integer keys in rig_overrides dicts so the web UI parser
  can read them (parseInt fails on variable names like _RIG_CLEN)
- Add 26 unit tests for KemperEffectEnablePerRigCallback covering all
  per-rig slot assignments and multi-slot AND-logic toggle behavior
- Fix web UI rig_map remove button: move ✕ inside slotsContainer so it
  is always visible; fix dynamic slot insertion order so + and ✕ stay
  at the bottom; style button in neutral gray

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ants on Apply

- Normalize rig_overrides keys from string to int in __init__ so that
  "0" matches the int rig ID from the Kemper MIDI mapping (fixes switches
  remaining disabled when the web UI generated quoted keys)
- RemoveAssignmentTransformer: new CST transformer to delete a named
  top-level assignment from the module body
- set_splashes() now removes orphaned DisplayLabel constants from
  display.py that are no longer referenced in the Splashes children tree
- PySwitchRunner: load RemoveAssignmentTransformer into Pyodide
- Test: add TestRigOverrideKeyNormalization (5 tests) for both int
  and string keys, mixed keys, and disabled-rig edge cases

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

2 participants