Skip to content

Tablet-friendly faders, JAM tab, XY presets, and Focus-view favorites - #1

Open
dorneanu wants to merge 12 commits into
littletools404:mainfrom
dorneanu:feature/tablet-faders-custom-midi
Open

Tablet-friendly faders, JAM tab, XY presets, and Focus-view favorites#1
dorneanu wants to merge 12 commits into
littletools404:mainfrom
dorneanu:feature/tablet-faders-custom-midi

Conversation

@dorneanu

Copy link
Copy Markdown

Summary

Tablet/phone-friendly touch controls, plus a new JAM tab for pinning your own pads/faders (SP-404 params, raw MIDI to a second device, or captured bus scenes), an XY presets panel, and a handful of smaller UX improvements — all built and tested against real Roland reference material (SP-404 MK2 manual, MC-101 MIDI implementation chart), not guesswork.

What's new

Bigger, tablet/phone-friendly faders

  • Full-width filled-bar faders (relative drag, fine-tune pull-out) instead of thin floating pills — much easier to grab on a touchscreen.
  • Optional horizontal fader layout (Setup) for wide/landscape tablets, where a sideways drag has more travel to work with.
  • Light/dark theme toggle.

JAM tab — your own pinned controls

  • Three kinds of control: an SP-404 bus param (stays put regardless of which effect is loaded on that bus), raw MIDI (any channel/CC/Note/PC to any connected output — e.g. a second synth), or a captured bus scene (a whole bus's state, momentarily recalled on hold and always reverting to whatever was playing before, including the effect itself).
  • Edit mode: drag to reorder, swipe left to delete, or multi-select to batch-set a MIDI channel / delete several at once.
  • PRESETS: factory templates built from real MIDI implementation charts — ships with an MC-101 4-track × Sound/Filter/Mod/FX template (device's own knob order), and raw CC controls are now two-way: turning the actual hardware knob updates the app, from any connected MIDI input.
  • Rotary knob style (Setup) as an alternative to bars: balance-pot style, pointer straight up at the center value, tilts right/left toward 127/0.
  • CLEAR / batch-delete / swipe-delete all use instant-action + timed undo instead of a confirm dialog (some iOS Web MIDI wrapper browsers silently stub confirm()/prompt() to do nothing).

Focus view additions

  • SAVE button captures the bus you're looking at as a JAM bus-scene in one tap.
  • Scene sidebar: any bus scenes for the active bus appear as small buttons next to the faders, no trip to the JAM tab needed.
  • Favorite-effect chips right under the header — one-tap effect switching for starred effects, skipping the picker entirely. Always lands with EFX off (loading an effect is for tweaking, not punching it in live).

XY presets

  • Templates: curated axis pairs for specific effects (Isolator LOW×HIGH, Super Filter CUTOFF×RESONANCE, Tape Echo TIME×FEEDBACK, Phaser RATE×DEPTH, Wah MANUAL×PEAK, Resonator BRIGHT×FEEDBACK), built from real parameter names — picking one only offers buses that actually carry that effect, switches to it if needed, and assigns both axes.
  • Your combos: save your own current X/Y assignment (including cross-bus pairs set up manually) under an editable name, recall or delete it later.

Effect picker

  • RECENT and FAVORITES sections now get their own jump-bar shortcuts, matching the category shortcuts they always sat above without one.

Export/Import

  • Now covers Snapshots + JAM (including bus scenes) + XY combos in one JSON blob, so a full setup can move between devices (e.g. edited on a laptop browser, brought to a phone).

Testing

Every feature above was exercised end-to-end via browser automation against a live preview (not just written and assumed correct): drag interactions with real pointer events, edit/select mode gestures, undo windows, cross-theme and cross-orientation rendering, and a full view-by-view console-error sweep after each change. Screenshots in this description are taken from those runs.

No SysEx is used; the app still never sends anything on load (stored state is display-only until the first gesture).

cyneox and others added 9 commits July 29, 2026 08:10
Focus/Overview faders:
- Replace thin track + floating pill with full-width filled bars, shared
  between Focus view, Overview strips, and JAM tiles via one component
- Optional horizontal fader layout for wide/landscape tablets (Setup),
  scoped so it never bleeds into JAM's narrow grid tiles
- Drag sensitivity decoupled from a control's rendered size so small JAM
  tiles stay precise instead of twitchy

JAM tab: user-programmable pinned controls, 4 columns on phone widths
- Bus param source: pins one of a bus's 6 control slots regardless of
  which effect is loaded (TouchOSC/Faderfox-style fixed layout)
- Raw MIDI source: any channel/CC/Note/PC to any connected output, so a
  second device (e.g. MC-101) can be driven from the same page
- Bus scene source: captures a bus's full state (effect + 6 values +
  on/off) into a pad; momentary hold always restores exactly what was
  live before pressing (including the effect itself) on release, and
  forces EFX on while held so a bus captured off is still audible
- SAVE button and a scene sidebar on the Focus view itself, so scenes for
  the bus you're looking at can be captured/recalled without a JAM trip
- Edit mode with drag-to-reorder; CLEAR wipes the grid
- Presets: one-tap templates built from verified MIDI implementation
  charts (ships an MC-101 4-track x Filter/Mod/FX/Sound template)
- Destructive actions (CLEAR, Import) use an instant-act-then-UNDO
  pattern instead of window.confirm(), which some Web MIDI wrapper
  browsers on iOS silently stub to false without ever prompting
- Export/Import extended to cover JAM alongside Snapshots, for moving a
  whole setup between devices

Light theme (Setup toggle), full token pass; LCD-style readouts stay a
fixed dark screen with light digits in both themes, like a real display.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Swipe a tile left in EDIT mode to arm delete (instant + 6s undo, same
pattern as CLEAR). New SELECT mode lets you multi-check tiles and either
batch-apply a MIDI channel to all selected raw-MIDI controls or delete
them all at once.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Setup > "JAM style" toggles all JAM fader-type tiles between bars
(default) and hardware-style rotary knobs (conic-gradient arc + rotating
pointer). Purely a paint-layer choice on top of the existing drag engine
- both DOM trees are always built, CSS shows whichever is active, so
drag/wheel/double-tap/fine-tune behavior is unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The pointer bar rested pointing down (6 o'clock) while the conic-gradient
arc used a 0deg-is-up reference, so the two were offset and the knob
didn't point where the arc implied. Switched to a single full clockwise
sweep from 12 o'clock (0 = straight up, unfilled) with both pieces using
the same reference, so they always agree.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Setup-style panel (Setup > XY tab > PRESETS) with two sections:
- Templates: six curated axis pairs (Isolator LOW×HIGH, Super Filter
  CUTOFF×RESONANCE, Tape Echo TIME×FEEDBACK, Phaser RATE×DEPTH, Wah
  MANUAL×PEAK, Resonator BRIGHT×FEEDBACK) built from each effect's real
  parameter names. Picking one offers only the buses that actually carry
  that effect, switches the chosen bus to it if needed, then assigns both
  axes by parameter name lookup.
- Your combos: save the current X/Y assignment under an editable name,
  recall or delete it later. Persisted alongside the rest of state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…fix Export/Import gap

- Export/Import was missing state.xyPresets (added when the XY presets
  feature landed but never wired into the JSON blob) - now included with
  the same sanitize + undo-on-import pattern as snapshots/JAM.
- The effect picker's RECENT and FAVORITES sections now get their own
  jump-bar shortcuts (RE/FA), matching the category shortcuts they always
  sat above without one.
- New compact favorite-effect chip strip in Focus view, right under the
  header: one-tap effect switching for starred effects on the bus you're
  looking at, without opening the picker. No icon (redundant - everything
  in this strip is a favorite by definition), truncated labels, horizontally
  scrollable. Coexists cleanly with the scene sidebar and horizontal-fader
  mode (tested both).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…r; add bidirectional raw MIDI

- Focus favorite chips now force EFX off after switching effect - loading
  a favorite is for tweaking, not for punching in live (reuses the
  existing sendSw() helper).
- JAM knobs switched from a full 360deg sweep to a balance-pot style:
  pointer rests straight up at the center value (64), tilts right toward
  127, left toward 0 - matches the "bal" display convention already used
  elsewhere and is a lot more legible for relative-drag continuous values.
- MC-101 JAM preset now builds knobs in the device's own physical
  left-to-right order (SOUND, FILTER, MOD, FX) instead of alphabetical.
- JAM raw CC controls are now two-way: incoming CC on any connected input
  (not just the one selected as the primary SP-404 input) updates the
  matching control's value, so a second device's own hardware knobs (e.g.
  an MC-101 on channels 11-14) stay in sync with the app. Echo-suppressed
  the same way bus-linked controls already are (Midi.activeCCs while a
  finger holds it, Midi.echoLog for our own sends bouncing back) - the
  latter required teaching sendToPort() to log echoes, which it never did.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
+-60deg left barely any visible fill even at 0/127. +-135deg (the same
270deg-total sweep real pots use, just re-centered so 12 o'clock is the
midpoint instead of the sweep's start) fills most of the ring at the
extremes, reading as "maxed out" the way a real knob does.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dorneanu

Copy link
Copy Markdown
Author

I saw your tool here: https://www.reddit.com/r/sp404mk2/comments/1v6am5e/i_built_a_free_opensource_web_midi_controller_for/

Feel free to share your thoughts. I admit the MC101 presets might be to specific; we could still add more presets for other vendors as well.

cyneox and others added 3 commits July 31, 2026 08:16
Same {fx, cc[6], on} x5 shape as a Snapshot's buses array, but entered
directly instead of captured from live state, and not capped at 8. Setup:
Snap panel > "Open Recipes" > "+ New Recipe" - pick an effect per bus,
and the value fields that appear are labeled with that effect's real
parameter names/units. Typed values go through a new ccFromDisp()
(inverse of the existing dispFromCc()) so a card's own units - dB, ms, %,
note names, "L12"/"R12"/"CTR" for pan, "80:20" or "80/20" for a balance
split - convert straight to the right underlying CC, matching whatever
the app itself would display for that value. Tap a recipe to load it onto
all 5 buses via the existing applyFullState(), same as a Snapshot.

Also wired into Export/Import alongside snapshots/JAM/XY combos.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- New "Library" button in the top status bar opens the Recipes panel
  directly from any view, instead of only reachable through Snap.
- Ships one factory recipe, "House Chord Synth" (electronoir.gumroad.com):
  a serial-mode Overdrive -> Chorus -> Chromatic PS -> SX Reverb chain,
  transcribed from the card's own printed values via ccFromDisp so they
  land exactly as the card intends rather than hand-rounded. Backfilled
  on load for storage saved before this recipe existed (even just an
  empty recipes:[] from opening the panel once), so it shows up
  regardless of whether recipes:[] was already persisted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
"Quack" Bass, Risers, Bass Destroyer, Techno Kick Fattener, Top Loops
Sauce - transcribed the same way as House Chord Synth, via ccFromDisp so
each card's own printed values (Hz, dB, note-synced rates, enum names,
balance splits) land on the exact right CC rather than being hand-rounded.
Verified against several of the harder cases by hand (enum reverse-lookup
for reverb type/damp frequencies, continuous synced-rate conversion for
Phaser/Tremolo) - every value matched the source card exactly.

Refactored into a general FACTORY_RECIPES array + buildFactoryBus()
helper instead of one bespoke function, and generalized the backfill in
loadState() to inject whichever factory recipes are missing (not just a
single hardcoded id), so future additions backfill the same way.

Also extended ccFromDisp() to handle the continuous {hi,lo,u} sync-rate
form (Phaser/Flanger/Wah/Tremolo RATE when synced) - only the discrete
array form was supported before, and two of these new recipes need it.

A few source cards give a range for a field ("10 to 20") rather than one
number, clearly meant as a live-tweak/automation target - those use the
range's midpoint as a starting value.

Co-Authored-By: Claude Sonnet 5 <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