- Moved .settings-nav out of .overlay-body so it stays pinned below
the header when scrolling
- Buttons bumped to 12px font, 8px 16px padding, 38px min-height
- Added gap, padding, background and border-bottom to nav strip
Adds a scrollable row of section tabs at the top of the settings
overlay: Network · Audio · Interface · Bluetooth · System.
Each tab scrolls smoothly to its section and highlights as active.
Changed DEFAULT_PORT to 80 so the UI is accessible at
http://pedal.local/ directly (no port needed).
Killed orphaned old port-80 instance that was running stale code.
- Changed both tab bar ⚙ and status bar ⚙ buttons to open the
inline Settings overlay (openOverlay('Settings')) with data loads
instead of navigating to /settings (old Bootstrap page)
- The overlay was already fully built — HTML, CSS, JS loaders were all
present, just never wired up
Both the tab bar ⚙ Settings button and the status bar ⚙ button
in the v2 UI now redirect to /settings instead of opening an
inline overlay. The full settings page has the left sidebar nav
with category views.
All static asset references now include ?v={{ version }} to force
browser to reload on deploy instead of serving cached versions.
Increment TEMPLATE_VERSION in server.py on each deploy.
The React tab bar's Settings button previously showed a minimal inline
component. Now it navigates to /settings which has the full settings
page with left sidebar navigation and category views.
Replaced horizontal tab bar with a left sidebar navigation
that feels like separate pages:
- Left nav with icons + labels (Connection, Audio, 4CM Routing,
Network, Bluetooth, About)
- Active category highlighted in accent color
- Each category has its own URL via hash (#connection, #audio, etc.)
- Back/forward browser navigation via popstate handler
- Stacked layout on mobile (sidebar becomes scrollable row)
- FXBlock was missing block_id field (and __post_init__ auto-generator)
causing AttributeError on /settings and /api/presets endpoints.
- Rebuilt Helix Vite UI from ui/ source (index-jhtO2NOz.js,
index-D3aC6klh.css). Replaces older dist files.
Commit faa7bdb was on a local branch that got orphaned during
git reset --hard origin/main. Cherry-picked back its UI changes:
- New Vite build: index-DI0gBBIR.css + index-LMuhdreF.js
- Updated SVG icons for effects (amplifier, analyzer, dial, etc.)
- prefers-reduced-motion in index.html
- Updated bank/presets icons
Two bugs:
1. **Deadlock in set_audio_profile() (root cause of timeout)**
jack_client.stop() was called BEFORE killing the JACK server.
jack.Client.deactivate() is a synchronous call that blocks until
the JACK RT callback thread acknowledges. When ALSA reconfigures
(period/rate change), the RT thread can stall and deactivate()
hangs permanently. Reversed order: kill JACK server first (via
killall jackd) to force-kill the RT thread, then clean up the
Python client. Same fix applied to device hot-swap path.
2. **Pipeline crash after period change**
_CombFilter.buf and _AllpassFilter.buf were fixed-size arrays
at BLOCK_SIZE (256). If JACK restarts with a different period
(e.g. 512), self.buf[:] = block throws a shape mismatch in the
RT callback -> audio dies permanently. Made internal buffers
dynamically resize to match input block size.
- FastNAMHost now initialized with block_size from audio config's
latency profile (e.g. 512 for stable, 256 for standard)
- Prevents sample-alignment mismatch between JACK period and
NAM engine internal buffer size at boot
- Add FastNAMHost.set_block_size() — reloads current model with
new block_size, keeping the engine in sync with JACK's period
- Wire into POST /api/audio/profile so NAM engine restarts with
correct frame count when switching between standard/low/stable
- Prevents sample-alignment drift when JACK period changes but
NAM engine stays at old block_size (was causing passthrough)
- Remove serial.SerialException from except clause since 'serial'
is not defined when import serial fails, causing UnboundLocalError
- Catch only ImportError and OSError
- GET /api/audio/profiles — list available profiles with params
- GET /api/audio/profile — current profile + jack_running + xrun_count
- POST /api/audio/profile {profile: 'standard'|'low'} — switch profile,
restart JACK server + JACK audio client atomically
- Adds audio_system + jack_audio refs to WebServerDeps
- Rollback on JACK restart failure
- Changed delay time from 0.35ms to 350ms for audible delay
- Increased reverb mix 0.25→0.35 and decay 0.35→0.4
- Increased delay mix 0.25→0.35 and feedback 0.2→0.3
- Both reverb and delay now enabled+active by default (bypass=false)
Complete rewrite of _build_nam_model and _build_wavenet to handle:
- SlimmableContainer (A2): pick submodel by quality, recurse into WaveNet
- WaveNet: proper dilated convs with causal padding, 1x1 layer1x1 post-conv
- Linear: simple pass-through with gain/bias
Weight import matches NAM export order:
rechannel -> per-layer(conv w+b, input_mixer w, layer1x1 w+b) -> head_rechannel w+b -> optional head -> head_scale
Also fixes MOCK_PRESETS in frontend to match actual factory preset names.
The PyPI 'nam' package (v0.0.3) is Neural Additive Models for tabular
data — completely different from Neural Audio Model (guitar amp modeling).
Implemented a local _init_from_nam() that builds a WaveNet NAM model
from the Core ML .nam JSON format. Uninstalling the wrong package.
restore_state() loads the last state from disk but doesn't call
activate() on the pipeline, so the NAM model was never loaded
on boot and no audio passed through. Added select() call with
the restored bank/program values so the pipeline loads the
preset chain including the NAM model.
Reordered UI_DIST_DIR candidates so pi-multifx-pedal-ui/dist (the
correct Helix-style pedal UI) is checked first. The old priority
put src/web/ui-dist first, which allowed wrong-build deploys to
mask the real UI.
Also add UI_DIST_DIR env var to systemd service for explicit path.
Two issues found and fixed in the deployed UI bundle:
1. String.fromCharCode(64+y) where y is 0-based bank index
→ 64+y gives 64+0=64 = '@' for bank 0
→ Fixed: 65+y gives 65+0=65 = 'A' for bank 0
2. e.bank||1 where falsy 0 falls through to 1
→ Shows 'Bank 1' for bank 0, 'Bank 2' for bank 1
→ Fixed: e.bank||0 so 0 renders as 'Bank 0'
Source code (frontend-react/src/App.jsx) was already clean —
the bug was in a transport/song mode feature that was built
from uncommitted changes then reverted.
Bank 12 (Blues) with 4 factory presets covering 9 legendary blues artists:
- Preset 0: Texas Flood (SRV) — TS808 + Fender Super Reverb
- Preset 1: Mannish Boy (Muddy Waters) — Fender Bassman cranked w/ slapback
- Preset 2: The Thrill (B.B. King) — Twin Reverb clean w/ comp
- Preset 3: Still Got the Blues (Gary Moore) — Marshall crunch w/ delay
Includes docs/blues-genre-research.md with full gear deep-dives, NAM
model sourcing guide (Tone3000 URLs), chain architectures, and
parameter value rationale for all 9 artists (SRV, B.B. King, Albert King,
Freddie King, Muddy Waters, Buddy Guy, Gary Moore, Joe Bonamassa,
John Mayer).