Hi NewIgnis,
Great set of questions.
I shipped rev 149 just now that fixes the four that actually needed code. Detail per question:
1. “How do I set what pot impacts the first and what pot impacts the second lane?”
Two things have to align before any pot fires on a tile:
(a) Pick the active control set. into the 3 horizontal sections (controlSetId 1 / 2 / 3). The 12 physical pots only address the currently-active set.
Slot ranges per set:
- Set 1:
slotId 0 .. 23 — active when the top-left button is pressed (default at boot)
- Set 2:
slotId 24 .. 47 — active when the middle-left button is pressed
- Set 3:
slotId 48 .. 71 — active when the bottom-left button is pressed
Verified mapping for set 1 on firmware 4.1.4:
slotId = 1, top row full-width → bottom-left pot, ev.id = 6
slotId = 7, bottom row full-width → top-left pot, ev.id = 0
That field is the only place that controls pot ↔ lane binding:
lanes = {
[1] = { name = "NOTES", ..., potEvId = 6, ... }, -- tile at slotId 1, set 1
[2] = { name = "VELOCITY", ..., potEvId = 0, ... }, -- tile at slotId 7, set 1
}
Rev 149 renames the old encEdit field to potEvId (clearer name) but keeps the old name as a backward-compat alias. The lane also has an optional targetLane field if you want a different cross-dispatch (e.g., top-pot drives top-lane rather than its column-opposite).
2. “Steps 1..12 active, want full 1..16 with virtual param for the length”
Three things make this work, all in lane config:
lane.cells = { v1, v2, ..., v16 } — the initial value table, 16 entries (0..127). Edit this to ship a default pattern.
lane.initialMuted = { [3] = true, [7] = true, ... } (new in rev 149) — the initial mute table, listing which step indices start muted on preset load. Useful for shipping a default rhythmic pattern.
- Double-click the pot at runtime to activate/deactivate the currently selected step. The underlying value is preserved (muted = emit 0, stored value kept; unmute restores).
For the active step count itself (your “1..16”), the widget exposes the virtual parameter PARAM_COMMON_RANGE (= 33) — rev 149 listens to it via parameterMap.onChange, so drop a fader on another page mapped to virtual:33 on device 1 and the live step count moves with it. Default is now 16 (all active).
3. Mute pass-through vs total step length — confirming what you want
Just to be sure I’m building the right thing — two distinct concepts exist in the widget, and they map to two of your questions:
- Mute (per-step) — Q2 territory. Step N stays in range visually (shown as
!), keeps its stored value, emits 0 over MIDI. Toggled with double-click on the pot or pre-set via initialMuted. Useful for skipping a step inside the pattern without losing it.
- Length (
commonRange) — this question. Steps beyond commonRange render with a CANVAS background and a dim dot, are NOT part of the sequence anymore, and shouldn’t be played. Driven by virtual param 33.
Are these two concepts you want both, or is what you actually need just one of them (a single “number of active steps” knob, no per-step mute)? The current widget does both because the spec was ambiguous; if you only need the length, I can simplify the UX (drop the double-click mute entirely).
4. “paramBase is the lowest virtual param of a row, +1 per step”
Exactly. Lane 1 (paramBase=0) → virtual params 1..16. Lane 2 (paramBase=16) → 17..32. Step N of lane L writes to virtual param lane.paramBase + N on device 1.
5. “Tried to add lanes — no new lane appeared”
Pre-rev-148 the state tables (selectedStep, dragging, muted, laneMode, potState) and preset.onLoad were hardcoded for indices 1 and 2 only, and the cross-dispatch forced (sourceId == 1) ? 2 : 1. Rev 149 iterates over #lanes everywhere and adds a per-lane targetLane field (default = self), so adding lane 3+ now needs only:
- A 3rd custom tile in the JSON. Pick a
slotId from the ranges in Q1 — and remember it determines which control set the tile lives in.
- A new entry in the
lanes table with the matching potEvId.
- (optional) Set
targetLane if you want it to drive a different lane.
6. “What does encEdit do (renamed potEvId in rev 149)”
It’s the ev.id the firmware dispatches to this tile’s pot. Used as a filter in potLane: events with a different ev.id are ignored. The name was misleading — potEvId is what it actually means.
7. “How to define the position of a lane (page, row)”
Two places:
- JSON
tiles[].slotId (0..71 per page on MK2) — sets which slot on the page the tile occupies. Slot range determines which control set the tile lives in (see Q1). Pages are separate JSON pages[] entries.
- Lua
c:setBounds({x, y, w, h}) in preset.onLoad — the actual painted area in pixels. The widget defaults to {0, (i-1)*100, 1016, 100} for full-width lanes stacked vertically.
8. “What does laneMode do?”
Per-lane state machine, two states: "navigate" (pot turns step the selection 1..16) and "edit" (pot turns change the selected step’s value). A pot click toggles between the two; a double-click toggles the selected step’s mute state. The current state is shown as a “NAV” / “EDIT” pill in the lane header.
9. “Horizontal vs vertical value bar option”
Added in rev 148. Set lane.gaugeOrientation = "v" for a thin vertical bar on the right edge of each cell; default "h" keeps the original horizontal bar at the bottom.
10. “External fader changes don’t update the widget”
Fixed in rev 148. The widget now implements function parameterMap.onChange(valueObjects, origin, midiValue) which catches external changes to PARAM_COMMON_RANGE and to the per-step virtual params and repaints. The handler filters origin == LUA so it doesn’t loop on the widget’s own parameterMap.set writes.
Grab the updated preset: electraone-widgets/widgets/note-list-16/demo.preset.json at main · roomi-fields/electraone-widgets · GitHub
The lane configuration fields are now documented in the widget’s README. Holler if rev 149 doesn’t address your case exactly — happy to iterate.
Romi