Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions esp32/tasks/LNK-029.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
id: LNK-029
title: "Research: mixer FX-slot introspection + multi-slot / multi-param tempo control"
status: todo
assignee: null
priority: medium
tags: [link-firmware, osc, fx, mixer, research, needs-triage]
depends_on: [LNK-005]
created_at: 2026-07-04
updated_at: 2026-07-04
---

## Goal

Scope what the device could do with mixer FX beyond today's single hardcoded
target. Today (LNK-005) we send BPM → `/fx/<slot>/par/01 ,f` (delay-time param)
to **one** configured slot, send-only, assuming the slot holds a delay. This
ticket researches four questions before any implementation:

1. **What can we read from the mixer about the FX slots?**
2. **What other parameters make sense to tempo-control?**
3. **How to handle multiple tempo-syncable effects at once** (e.g. a delay in one
slot and another effect with its own tap-tempo/rate in another)?
4. **Should we control more than one FX slot?**

Output is a findings doc + a design recommendation, **not** code.

## What we already know (grounding)

- `/fx/N/type ,i` — the loaded **algorithm** per slot, index `[0,60]`
(`docs/xr18-xair-osc-cheatsheet.md`). This is the key introspection hook.
- `/fx/N/par/MM ,f` — per-algorithm parameters, `MM = 01..64`. Which `MM` is the
tempo/delay-time param **depends on the algorithm** (par/01 happens to be delay
time for the delay algorithms we target now).
- We are currently **send-only** and never read `/fx/N/type` — so we're blind to
what's actually loaded and just assume par/01.
- XR18 has 4 FX slots, X32 has 8 (`config_model_slot_max`).
- The receive/subscribe plumbing exists (`osc_in`, xremote — LNK-013), so reading
back mixer state is feasible, we just don't use it for FX.

Scope note: this ticket is **X32-family only** (XR18/X32). Behringer **Wing** is a
different control protocol and is tracked separately in **LNK-030** (later).

## Research questions

### Q1 — FX-slot introspection
- Read `/fx/N/type` for each slot → know the algorithm. Can we also get a
human-readable name, or only the index? Build the **index → algorithm** table
for XR18 and X32 (they may differ).
- For each tempo-relevant algorithm, which `par/MM` is the tempo/delay-time param,
and what are its **units/encoding** (normalized float → ms? a note-division
enum? a raw ms value?). Does the XR/X32 FX expose a "tempo sync on/off" or a
"division" param we should set instead of writing a raw time?
- Can/should we **subscribe** (xremote) so we track slot type changes live and
avoid writing a delay-time to a slot the user just changed to reverb?

### Q2 — which params are worth controlling
- Catalog tempo-syncable params across algorithms: delay time (delays), LFO rate
(chorus/flanger/phaser), reverb pre-delay, tremolo/auto-pan rate, gate/ducker
timing. Note which are musically useful to lock to Link tempo vs noise.
- Non-tempo params worth a look while we're here? (probably out of scope — keep
this ticket tempo-focused, list others as future.)

### Q3 — multiple tempo-syncable effects at once
- If a user has a delay in slot 1 and, say, a tremolo/tap-tempo effect in slot 3,
both want the tempo. The device is the tempo authority — we'd write each slot's
tempo param directly (overriding the mixer's own tap-tempo). Confirm that's the
right model vs trying to drive the mixer's tap-tempo input.
- Different targets may want **different note divisions** (1/4 vs 1/8-dotted vs
1/2). Implies a per-target division/multiplier, not one global BPM→ms.
- Encoding differs per algorithm (ms float vs division enum) — the per-target
mapping must carry the algorithm's param index + unit conversion.

### Q4 — multi-slot control
- Extend config from a single `fx_slot` to a set of targets: each `{slot,
enabled, division, (auto-detected type → param index + unit)}`.
- Config/UI implications: the web + touch UIs, NVS schema, and validation grow
from one slot to N. How much of the mapping can be **auto-derived** from
`/fx/N/type` so the user just picks slots + divisions?
- Rate-limit / OSC-flood concerns when writing several params on every tempo
change (reuse LNK-011 bpm_publisher send-policy).

## Deliverables (this is research)

- [ ] `index → algorithm` tables for XR18 and X32, annotated with the tempo param
index + unit/encoding for each tempo-relevant algorithm.
- [ ] Recommendation: **auto-detect** FX type via `/fx/N/type` (+ optional
subscribe) vs **manual** per-slot config — with the tradeoffs.
- [ ] A proposed config/UI/NVS shape for N targets with per-target note division.
- [ ] A note on the tap-tempo question (write params directly vs drive tap input).
- [ ] Follow-on implementation tickets filed from the findings.

## Notes

- Rides on LNK-005 (current FX delay send), LNK-011 (send policy), LNK-013
(`osc_in`/xremote read-back), and the phase/tempo pipeline validated in LNK-020.
- Reference: `docs/x32-osc-protocol.md`, `docs/xr18-xair-osc-cheatsheet.md`,
`docs/xr18-geq-osc.md`. Hardware to probe: the XR18 (and X32 if available) via
`osc_in` dumps of `/fx/N/type` and `/fx/N/par/*` while loading different
algorithms.
- Keep any resulting unit-conversion math (BPM + division → ms/enum) in a pure,
host-tested module, same pattern as the rest of the firmware.
76 changes: 76 additions & 0 deletions esp32/tasks/LNK-030.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
id: LNK-030
title: "Research: Behringer Wing support (different OSC protocol) for tempo/FX control"
status: todo
assignee: null
priority: low
tags: [link-firmware, osc, fx, mixer, wing, research, needs-triage]
depends_on: [LNK-005, LNK-029]
created_at: 2026-07-04
updated_at: 2026-07-04
---

## Goal

Assess what it takes to support the **Behringer Wing** as a mixer target for
tempo/FX control, the way we support XR18/X32 today. The Wing is **not** an
X32-family device — different control protocol — so this is its own research
track, deliberately **later** than the X32/XR18 FX work in LNK-029. Output is a
findings doc + a `MODEL_WING` feasibility recommendation, **not** code.

## Why separate from LNK-029

LNK-029 (X32/XR18 FX-slot introspection + multi-slot tempo control) assumes the
**X32-family address tree** (`/fx/N/par/MM`, ports 10023/10024). The Wing uses a
different address/param model, so its findings won't port. It's also farther down
the roadmap — keep it from blocking the X32/XR18 work. Reuse LNK-029's *method*
(introspect FX type → map tempo param → fan out to N targets with per-target note
division), just re-answered for the Wing.

## What we know today (grounding)

- Model support is XR18/X32 only: `MODEL_XR18=1`, `MODEL_X32=2`
(`app_config.h`); `config_model_port` → X32:10023 / XR18:10024;
`config_model_slot_max` → X32:8 / XR18:4.
- The OSC layer (`osc_out`/`osc_in`) is X32-dialect-specific. Adding a Wing means
either parameterizing that layer or adding a **separate Wing OSC dialect
module** behind the existing `tempo_source`→OSC seam.

## Research questions

- **Protocol dialect.** The Wing speaks its own control protocol (OSC-style plus a
text/`$`-style command channel) with a different address tree, node/param model,
and encoding. Confirm: control UDP port(s); whether plain OSC suffices or the
node protocol is required; how FX params are addressed and encoded
(name-addressed nodes vs numeric par indices; value units).
- **FX topology.** Confirm the Wing's FX slot count and effect set (more slots and
a different "premium" effect set than X32's verb/delay), which effects are
tempo-syncable, and how each tempo param is expressed (ms vs beat-division vs a
sync/tap node).
- **Introspection.** Does the Wing expose richer read-back (effect type/name per
slot, param metadata) than X32's `/fx/N/type`? If so, auto-detection may be
*cleaner* on Wing.
- **Firmware integration.** What `MODEL_WING` needs: a new model id + port in
`config_model_port`/`config_model_slot_max`, and how much of LNK-029's Q1–Q4
(introspection, param catalog, multi-slot fan-out, per-target divisions) is
reusable vs Wing-specific. Estimate: parameterize `osc_out`/`osc_in` vs a new
dialect module.
- **Discovery/connection.** Confirm a Wing is reached the same way as the X32
(user-set mixer IP) or needs different discovery.

## Deliverables (this is research)

- [ ] Wing control port(s) + address/encoding model documented (with real dumps
from a Wing if one is available).
- [ ] Wing FX topology: slot count, tempo-syncable effects, tempo-param encoding.
- [ ] Introspection capability assessment (vs X32 `/fx/N/type`).
- [ ] `MODEL_WING` feasibility + integration recommendation: parameterize the
existing OSC layer vs a separate Wing dialect module behind the seam; how
much of LNK-029 is reusable.
- [ ] Follow-on Wing implementation ticket(s) filed from the findings.

## Notes

- Do the X32/XR18 research (LNK-029) first; use its structure as the template.
- Needs a Wing on the bench (or its documented protocol) to dump `/fx` state.
- Keep any tempo→param unit math in a pure, host-tested module, same as the rest.
Loading