Skip to content

Button lights test build on v37 (do not merge) - #3

Closed
steponme82 wants to merge 49 commits into
mainfrom
lights-v37-test
Closed

steponme82 wants to merge 49 commits into
mainfrom
lights-v37-test

Conversation

@steponme82

Copy link
Copy Markdown
Owner

Only here to make GitHub build a test firmware: OpenPocket v37 with the button lights (isod89#17 rebased on v37). Do not merge, it gets closed once the build is downloaded.

🤖 Generated with Claude Code

isod89 and others added 30 commits November 3, 2026 20:18
…#1, BlackBox boot loop); installer rescue mode

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…es (issue #1); show the reset source

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…ets survive

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
… USB-MIDI SysEx

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…s stock settings slowed the DSP and crackled)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…(bit-exact), NAM A1 reference, fitters

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
… gear

The amps (TWIN, AC15 TB, JCM900, JCM2000, MARK IV, SHIRLEY, PRO MOD, 5150), the drives (TS9, KLON, M77 OD,
SWEDE HM-2) and the V30 cabinet have their table numbers fitted to NAM captures on real DI guitar
(docs/FITTED-MODELS.md, results table there). Same engine and CPU (+3 % on average, the heaviest preset lighter).
The other amps / drives / cabs are removed; 7 cabinets remain.

- presets saved before v34 move to the nearest new type at boot (store format 3, px_type_v34); test for format 2
- factory presets on the new types; six renamed (their old amp is gone)
- levels re-calibrated (px_trim.h); fitters read the new float tables (exponents, comments)
- docs: README, SOUNDS-AND-CONTROLS, AUDIO-SDK; credits for the captures and the DI recordings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
… drive / cab

The old type names (RECTIFIED, MUFF PI, 4x12 H30...) map to the same types the pedal picks for its own saved
presets (px_type_v34); each change is listed in the import notes. Test added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…y and reverb lines (89 KB of RAM freed)

- reverb: 8-line feedback delay network (Hadamard, decay set per line at low frequencies and at 4 kHz, 4 slowly
  modulated lines, early reflections, Dattorro's input diffusers) and Dattorro's plate; 22.05 kHz, one 16-bit ring.
  Decay times now match DECAY; less ringing in long tails; levels matched to v34; tails fade out at the last bits
- delay: 16-bit line, TIME up to 2 s (0-80 = 20..1000 ms, 80-100 = 1..2 s), cubic reads (also chorus, flanger,
  vibrato, rotary); the read position no longer wraps through a float
- presets saved before v35 keep their delay time: store format 4 converts at boot, the editor converts files
  without "v": 35; factory presets converted
- engine 247 KB in the 336 KB pool (v34: 332 KB); CPU on the PC +4.5 % on average (reverb presets +100,
  delay + reverb presets up to +200)
- tests: format 3 store, v34 preset file import; docs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…ackages on localhost

tools/serve_offline.ps1: a small local server (PowerShell's HttpListener, localhost only, docs\ only) that opens
the installer in Chrome or Edge; Web MIDI works on localhost, so no internet is needed. The .bat builds the packages
when docs\firmware has none, and falls back to WSL's Python server if PowerShell cannot open the port.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
- levels measured as loudness (BS.1770) on DI guitar (tools/calib_levels.py -> px_trim.h): each amp's level over
  GAIN (noon -23 LUFS for all, +-3 dB over the knob), cabinets, every block type unity at noon; the 52 v35 presets
  spanned -53..-10 LUFS, the 24 new ones sit at -23.0 +-0.2 (tools/level_presets.py)
- preset LEVEL: GT's 3rd setting "PRESET LVL" (-15..+15 dB); store format 5 and the editor set 0 dB on older presets
- soft output limiter instead of the hard clip; SLOW SWELL look-ahead (no attack before the swell)
- 24 factory presets round the fitted amps near noon, gentle gates on the hissy cleans; 25..52 USER slots
- screen: PLAY (number and name large, amp / cab, chain in colour, selected block) and EDIT (block band, model,
  5 settings with value + bar); fonts 26 / 58 px; ui_text.h shared with tests/uisim.c, which checks every page
- delay TIME shown in ms on the pedal; calib3.c replaced by calib_levels.py

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
- battery: the chip's VBAT/4 and LDO5V/4 PMU channels scaled by the bandgap (as the JieLi SDK does), read every
  2 s with the mux and test bus put back; top centre of PLAY (icon + %, USB), volts on the tuner page
- the output fades to silence while the tuner is open (5 ms ramp)
- VOL box: v35's 48 px cut "VOL 100" to "VOL 10" (v36: 66 px); EDITED moved next to the cab
- docs/WHATS-NEW-v34-v36.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…ISH-SOURCE.bat

GitHub's main had stopped at v29 + two README edits made on the site (the bundle could not be put on top), so the
source of v30..v36 was never public. The publish script now clones GitHub's main, merges the bundle's history in
(-X ours, never forced), makes the files exactly this folder's, commits, pushes, and sets the tag on that commit
(moved when it pointed at an old main). Release notes include docs/WHATS-NEW-*.md. PUBLISH-SOURCE.bat: source only;
PUBLISH-GITHUB.bat offers it when the build fails. README: the site edits (banner, editor link) carried over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…, taken from the folder

Files left over from older versions in the folder (docs/ui-v23.png, tests/engine/calib3.c...) are not published again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…r keeps the PowerShell server; CI read-only

build.bat uses the container (tools/op.mjs) when Node and Docker are running, else WSL as in v36.
INSTALL-OFFLINE.bat needs nothing installed again (tools/serve_offline.ps1), with tools/serve.py and WSL as fallbacks.
The workflow gets permissions: contents: read. The .bat files use CRLF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…dels from the web editor

- engine/px_nam.c: NAM A2-Lite in fixed point (Q20 activations, Q24 weights, 64-bit sums), checked against
  tools/nam_a2.py (about 99 dB SNR on every factory model, tests/test_nam.py). On the pedal a layer is one
  hand-written pi32v2 routine (hardware loop, 5 instructions per 3 multiply-adds), checked against the C one at boot.
- AMP type 9 "NAM" (MODEL, GAIN, BASS, MID, TREBLE): 12 factory models trained for the pedal at 44.1 kHz
  (tools/train_a2.py, from GPL-3.0 community captures and DI guitar), 16 user slots in flash (0xC0000, kept by updates).
- Web editor: NAM models panel, A2 .nam files (TONE3000...) checked, levelled and sent (editor protocol 2:
  NAM_LIST, NAM_WRITE, NAM_COMMIT, NAM_ERASE).
- 24 factory presets rebuilt on the NAM models, levelled to -23 LUFS; USER slots start from NAM TWIN.
- Audio path in RAM (40 KB code window); NAM rings in the POOL region, 88 KB of ordinary RAM left.
- Docs: NAM.md, WHATS-NEW-v37.md, EDITOR-PROTOCOL (protocol 2), README, SOUNDS-AND-CONTROLS, AUDIO-SDK, BUILDING.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…h, only the NAM layer routine in RAM

A direct call between the flash code (0x02xxxxxx) and the RAM code (0x01C0xxxx) is out of the call instruction's
+-4 MiB: putting the audio path in .ram_text gave 478 such calls (the linker named only the first). The engine and
the math functions are in the flash again, as in v36 (RAM layout back to v36: 24 KB RAM code, 96 KB RAM); the NAM
layer routine stays in RAM, called through a pointer, and calls nothing. tools/check_calls.py, run by
firmware/build.sh before linking, refuses any such call and names it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
The NAM presets overload the second core (223 % of real time). The boot bench screen (BENCH_AT_BOOT, on in this
build only) now measures, on the pedal: cycles per instruction kind (fused load+multiply-add, load, register
multiply-add, two interleaved fused MACs), from RAM and from the flash, data in RAM and in POOL; cycles per
multiply-add of one NAM layer, hand routine and C; whether the hand routine passed its check; and whole presets
(NAM alone, two NAM presets, the same with the fitted 5150).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…(a weight for 4 frames, paired) + post

On the pedal the first engine took 223 % of real time. This CPU has no data cache in front of the SRAM, a taken
branch costs about 8 cycles and it issues a 32-bit multiply-add together with a 16-bit load. The stock firmware
runs the same A2-Lite network in real time by batching (read from its code: rows gathered per frame, dot products
with a weight read once for several frames). Now, by our own code: per layer, gather each frame's inputs into one row
(3 words a move), the 3 weight rows against 4 rows at a time in the hardware loop with multiply-adds paired with
loads (5 issues per 4 multiply-adds), then LeakyReLU (predicated), the head sum and the residual straight into the
next layer's ring. Rings interleaved [time][channel], same memory (83.4 KB). The hand routines are checked against
the C ones at boot. Same accuracy against the float reference (83 to 100 dB). The boot bench (still on in this
build) measures the new layer cost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
… each part of a NAM layer)

First pedal measurements (rewritten engine): the hand routines pass their check, a load costs 2.4 cycles and a
multiply-add with its load 4.4 (no data cache), one layer 7.2 cycles per multiply-add, NAM alone 149 %. The bench
now shows: load, 64-bit load, 3-word load, store, multiply-add, multiply-add paired with a load, fused, two
multiply-adds; then the dot, gather and post parts of a layer separately.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…at start-up

Second pedal measurements: a 64-bit multiply-add costs 3.4 cycles (2.2 when two are independent), a load 2.4 (a
paired one is free), a dot product 4.0 cycles per multiply-add, the gather 13 cycles a tap, the post 115 cycles a
frame. Read from the stock firmware: its NAM dot products are commands to the AC79's vector unit (control 0xAA1,
q = 24, x step = the row, z step 12 bytes), started without waiting, beside the CPU. The register layout is the one
in JieLi's AC79 SDK (apps/common/jl_math, Apache-2.0). Now the 3 rows of a layer (and the head row) are one vector
command each, if the start-up check finds the unit answering and within 1 of the C result; else the CPU routines.
The bench screen shows the unit's state and its cost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…the NAM data should sit

Third pedal measurements: the vector unit answers (within 1 of C) but costs 4.8 cycles a multiply-add: it reads
weight and input from the same SRAM at about 2.4 cycles a word, as the CPU does. The stock firmware keeps NAM buffers
in an 8 KB block of fast memory: the data-cache ways used as RAM (the data cache sits in front of the flash only).
This build frees seven of them at boot (0x01F28000..0x01F2F000), with melodee's routine (Kerem Kilic, GPL-3.0:
registers checked, the whole bank tested, everything restored on a failure), and the bench measures loads, the CPU
dot, the vector dot and the post with their data there and in the ordinary RAM.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…e vector unit?

Fourth pedal measurements: the cache RAM is no faster (a load 2.4 cycles there too), so it is taken out again.
Every route measured costs about 4 cycles a multiply-add (CPU) or 4.8 (vector unit): one processor cannot run
the NAM with the rest of the chain. The bench now runs CPU0's dot alone, then with CPU1 running the same dot on its
own data, then beside a long vector command, to see whether they share a bottleneck (the SRAM) or add up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…-up timing of the modes

The block is cut in two halves: the vector unit computes one half's dot products
while the CPU gathers or posts the other (a queue of commands, kicked by the CPU's
work). post2 moves z, hs and x by 3 words an instruction and pairs the residual's
weight loads with its multiply-adds. At start-up the pedal times the three modes
(CPU, unit in turn, both) on a factory model and keeps the fastest. The PC test runs
mode 2 with a simulated unit finishing commands late at random: output identical.
Bench screen: the unit's cost a command by shape, post vs post2, the modes' times.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…ucts in mode 2

The post2 check overwrote an area the gather check compared after it: every hand
routine was refused (C used). Now post2 is checked in areas whose check is done.
The vector unit costs about 4.7 cycles a multiply-add on the pedal (diagnostic 6),
like the CPU: in modes 3 and 4 the CPU computes 4 or 8 frames of each half itself
while the unit does the rest; start-up timing picks among 5 modes. Bench screen:
the unit's cost by where x and the weights sit (POOL or RAM).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
The vector unit costs 4.8 cycles a multiply-add, like the CPU, wherever its data
sits (diagnostic 7): it is limited by its reads. Its weights can be 16-bit: each
row gets a shift from its largest weight and the CPU's 32-bit row is the 16-bit one
shifted, so both agree; used if its start-up check passes (65..85 dB below the
signal, far below each model's own error).
Two cores: CPU1 takes the first 12 or 16 frames of each 32-frame block through all
layers and never waits (earlier frames never need later ones); CPU0 the rest,
waiting on one counter before each layer. With a NAM amp in a two-core mode the
audio block runs on CPU0 and CPU1 helps the network. Start-up timing picks among 9
modes. The PC test runs them all with a simulated unit and a simulated second core
that moves only while the first waits: output identical to the CPU's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
The 16-bit weights for the vector unit are gone: its check failed and they were no
faster (4.79 against 4.83 cycles a multiply-add: diagnostic 8).
rdot: each output of a layer for 4 frames straight from the history ring (a tap's 4
frames are 12 words side by side), a weight read once for 4 frames, multiply-adds
paired with loads, by hand (checked against C at start-up). The gather, a quarter of
the CPU's NAM time, is gone from the CPU paths (one core, and both cores' shares);
the post reads the layer input from the ring too. The head the same way. The X rows
remain for the vector unit's modes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
isod89 and others added 19 commits November 6, 2026 20:58
…d, rdot or gather timed

Diagnostic 9: rdot alone was no faster than gather + the hardware-loop dot (168 against
158% on one core), and the CPU sharing the unit's dot products slows both (B4 124
against B0 109%): the unit and the CPU read the same RAM.
Now the unit's inputs (X rows, a copy of the weights: 13 KB) sit in seven data-cache
ways turned into RAM at boot (px_cacheram.h, melodee's routine, back from diagnostic 4),
checked by the start-up test; rdot for 6 taps is unrolled (no branch per tap); the
start-up timing picks rdot or gather for the CPU's layers, then the mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
Diagnostic 10: the unit gives wrong results from cache RAM (its check failed), and
rdot (unrolled) and gather cost the same (160 against 161%). The stock firmware's NAM
driver works like mode B (the unit on most frames of each chunk, a CPU kernel on the
rest, a 3-chunk pipeline, 70-frame blocks, X rows packed at their own length).
One earlier measurement gave the unit 1.5 cycles a multiply-add, the others 4.8: this
bench finds which part of the command shape (loops, steps, one address, values, the
CPU polling, the X row stride) makes the difference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
… its load

Diagnostic 11: the vector unit costs 4.65..4.85 cycles a multiply-add whatever the
shape (loops, steps, one address, values, polling, X row stride): the 1.5 measured
once was an artefact. So the CPUs carry the network; their routines pair each
multiply-add with a load whose value the next multiply-add uses. This bench measures
a pair with and without that wait, with 1, 2 and 4 accumulators: if the wait is the
cost, routines that load two steps ahead will be faster.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
Diagnostic 12: a multiply-add paired with a load costs 3.2..3.5 cycles when the next
multiply-add uses the value loaded (as all the hand routines did), 2.2 when it does
not. rdq (tools/gen_rdq.py) computes a layer's rows for 4 frames straight from the
ring, unrolled for 6, 15 and 16 taps, each x value loaded 4 steps before its use and
each weight 2 (x in r3 r4 r6 r7, the weight in r5, the taps' pointers in r1 and r2 by
turns). Checked against C at start-up; the timing picks rdq, rdot or gather.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
Diagnostic 13: rdq is in use (150% on one core, against 161), two cores 80%, NAM
alone 85%, the full presets 107 and 115%. CPU0 also carries the input, the head and
the waits, so two more two-core modes give CPU1 20 or 24 of the 32 frames; and the
bench measures each effect of presets 18 and 01 alone, to see what the rest of the
chain costs beside the network.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…tone filters over the block

Diagnostic 14: two cores 80% (CPU1 taking 20 or 24 frames is slower: 96, 113), and
each effect alone: drive 22%, cabinet 11-12%, reverb 12%, compressor 4%, gate 3%.
This pedal's FPU waits about 9 cycles for each result, and the engine ran every block
for one sample before the next sample, its filters' coefficients and state read and
written in memory each time.
Now the engine runs each block over all the samples of the call, one block after the
other (each sample's operations unchanged: the 24 factory presets and the 8 fitted
amps render bit for bit as before on the PC); the cabinet's filters, the drive's
oversampling (up, the drive stage by stage, down) and the NAM tone stack run over the
whole block with their state in registers (bq_block, drive_block).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
Diagnostic 15: block by block helped (drive 22 -> 18%, cabinet 11 -> 9%, presets 104
and 108%), but each filter is still a chain of operations that wait for each other.
bq_block2 runs two filters in series over the block interleaved (the first on sample
k, the second on sample k-1), so their two feedback loops overlap: the cabinet's
filters, the drive's oversampling filters and tone filters, the NAM tone stack. Same
operations per filter: the factory presets render bit for bit as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
… before a NAM amp

Diagnostic 16: two filters at a time changed nothing (presets 104 and 108%). This
FPU's operations are what cost: the cabinet's filters and the drive's oversampling
filters now run in integer arithmetic (signal Q26, coefficients Q29, direct form I,
64-bit sums; a hand loop of 2 samples a turn, checked against C at start-up), about
75 dB from the float filters on the 16-bit renders (their quantisation). A drive before
a NAM amp runs at x2 instead of x4 (filter set C; Sam's choice: the network itself
does not alias). PX_FX_FLOAT=1 renders with the float filters. The bench shows each
effect with integer and with float filters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…hout the vector unit, float filters again

The bench shows where the CPU alone spends the network's time (input, tap tables,
kernel, rests, post, head) and times post3 against post2. post3 computes the three
LeakyReLU products side by side and loads the residual's weights two multiply-adds
ahead; it is checked against C at start-up and used only if faster. Post runs over
the whole block in one call unless the vector unit needs kicking. The cabinet and
drive filters are float again (the integer ones were not faster on the pedal).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
… the effects pipelined on two cores

Each NAM history ring has its first 3 frames mirrored after its end, so a tap's 4
frames read straight from any position and the tap pointers only move on by 4 frames
per group (the bench measured the tap tables at 22% of real time on one core).

With a NAM amp on two cores the audio block is a pipeline (px_engine_part: PRE, NAM,
POST): CPU1 runs the effects after the amp on the previous block while CPU0 runs the
effects before it on this block, then both run the network. One block (2.9 ms) more
latency; tests/engine/pipe_test.c checks the output is the one-core output one block
later, bit for bit, on every factory NAM preset. The bench times both presets
pipelined; the safety bypass allows 93% in this mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
pxn_rdl6/15/16_asm (tools/gen_rdq.py --rdl) run rdq over every group of a layer's
block in one call: the tap table on the stack (one load per tap instead of two), the
tap pointers moved on in the routine (back by the ring's length past its end), no call,
job setup or vector-unit kick per group. Checked against C at start-up (outputs and
the job's pointers after, with taps passing the end) and timed against rdq; the PC
tests run the same path with the C routine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…he other way round

In the two-core pipeline CPU1 runs the effects after the amp first and often comes to
the network late. Now it goes straight on (pxn_serve) taking the last frames of each
32-frame block, waiting per layer for CPU0, which takes the first frames, never waits,
and takes up to 12 more frames in the first blocks by how late CPU1 came before.
The PC test simulates CPU1 running each layer as early as allowed or only when waited
for, with the split changing from block to block: the output is the CPU's alone, and
a deliberately early helper makes it differ.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
…r for a NAM preset on both cores

The pipelined two-core NAM path now runs every factory preset in real time (69-90%
of the budget, the network alone 66%). Docs: the load figures, the pipeline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
A Browse TONE3000 button in the NAM models panel opens TONE3000's tone browser in a
pop-up (OAuth 2.0 + PKCE, prompt=select_tone, A2 .nam captures only); docs/t3k.html
hands the answer back. The editor then shows the tone (title, gear, format, creator)
and its A2 models, and loads one into the user slot chosen beside it. Needs the app's
publishable key (T3K_CLIENT_ID in docs/pxt3k.js); without it the button says so.
The page test simulates TONE3000 (pop-up, PKCE check, tone, models, download with the
token) and loads its model into a user slot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFaxqW3CpFrLCvqoteTUv9
The BlackBox's button lights hang on a 74HC595 on port C (DS PC8, shift
clock PC5, latch PC6), as the stock firmware drives it. PC7 is the
lights' enable, low = on. OpenPocket held PC7 high as a screen line, so
the lights stayed dark whatever the 595 held.

- px_leds.h: the 595 driver. leds_init loads the all-off byte with the
  lights disabled, then drives PC7 low, in the stock order.
- px_lights.h: what they show, once per main-loop pass. AMP, MOD, DLY,
  REV and CAB light while their block is on, FX while any block of its
  group is on (ui.h UI_FXB, shared with the FX button), HOME blinks in
  the tuner. The byte is written only when it changes. Off during an
  update (px_usb.h PX_LIGHTS_OFF).
- led_probe.h (LED_PROBE 1): the LED map build that read the bit order
  on a BlackBox: 0 HOME, 1 FX, 2 AMP, 3 MOD, 4 DLY, 5 REV, 6 CAB.
- tests/lpsim.c and tests/lightsim.c: a 595 model with its enable on
  PC7; both run from tests/run_tests.sh.

Confirmed on a BlackBox. Not tried on a Pocket X yet: the same firmware
runs there and the stock routine is the same, but its bit order may
differ.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@steponme82 steponme82 closed this Nov 7, 2026
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