Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
bddb272
v30: set the power supplies at start as the stock firmware does (issu…
isod89 Nov 4, 2026
129b6a4
v31: turn the long-press reset off at start, as the stock firmware do…
isod89 Nov 4, 2026
c76e8c8
loader: never erase the preset store during an update; test that pres…
isod89 Nov 4, 2026
0d02e43
v32: web preset editor (live editing, 52 presets, export/import) over…
isod89 Nov 4, 2026
cd6a627
v33: leave the power supplies at the boot loader's levels again (v30'…
isod89 Nov 4, 2026
8ae04f4
tests: v33 identity
isod89 Nov 4, 2026
f76e288
docs: PINR at power-on, Pocket X 08 / BlackBox 09
isod89 Nov 4, 2026
3308f90
fitting tools: amp / drive / cab tables in floats with a PX_FIT hook …
isod89 Nov 5, 2026
3107bd1
v34: 8 amps, 4 drives and the 4x12 V30 fitted to captures of the real…
isod89 Nov 5, 2026
229babd
editor: preset files from v32 / v33 import onto the nearest v34 amp /…
isod89 Nov 5, 2026
e013a14
v35: new reverbs (FDN + Dattorro plate), delay up to 2 s, 16-bit dela…
isod89 Nov 5, 2026
ffd4f6b
Offline installer: INSTALL-OFFLINE.bat serves the installer and the p…
isod89 Nov 5, 2026
2d66afd
v36: pro levels, 24 levelled factory presets, a new PLAY / EDIT screen
isod89 Nov 5, 2026
cc055eb
v36: battery gauge, tuner mute, VOL 100 display; what's new since v33
isod89 Nov 5, 2026
591ba2f
Publishing: GitHub main = this folder's files, with the history; PUBL…
isod89 Nov 5, 2026
f48d8ee
Publishing: only the version's files (the bundle's list) go to GitHub…
isod89 Nov 5, 2026
86dbc61
Merge GitHub main (pull request #7: portable container build)
isod89 Nov 6, 2026
8e4539e
Windows: build.bat falls back to WSL without Docker; offline installe…
isod89 Nov 6, 2026
5fa8e4d
OpenPocket v37: neural amp models (NAM A2-Lite) on the pedal, user mo…
isod89 Nov 6, 2026
cd64aba
v37: fix the link (relocation truncated): the engine back in the flas…
isod89 Nov 6, 2026
6529afe
v37 diagnostic: NAM bench screen at boot (the pedal showed BYP 223%)
isod89 Nov 6, 2026
4553306
NAM engine rewritten for this CPU: blocks of 32 frames, gather + dot …
isod89 Nov 6, 2026
30fb08d
v37 diagnostic: bench screen v2 (cost of each instruction kind and of…
isod89 Nov 6, 2026
c1bbfe8
NAM: dot products on the chip's vector unit (the FFT block), checked …
isod89 Nov 6, 2026
8dc8635
v37 diagnostic 4: cache RAM (seven data-cache ways as RAM) and where …
isod89 Nov 6, 2026
2bc1a65
v37 diagnostic 5: does the NAM work scale over the second core and th…
isod89 Nov 7, 2026
db06489
v37 diagnostic 6: NAM on the vector unit beside the CPU, post2, start…
isod89 Nov 7, 2026
b872e3f
v37 diagnostic 7: fix the start-up check, the CPU shares the dot prod…
isod89 Nov 7, 2026
c3f4fdb
v37 diagnostic 8: NAM on two cores, 16-bit weights for the vector unit
isod89 Nov 7, 2026
3808475
v37 diagnostic 9: NAM layers read straight from their rings (no gather)
isod89 Nov 7, 2026
4701e1b
v37 diagnostic 10: the vector unit reads from cache RAM, rdot unrolle…
isod89 Nov 7, 2026
c0eb48c
v37 diagnostic 11: the vector unit's speed by command shape
isod89 Nov 7, 2026
290f09f
v37 diagnostic 12: what a paired multiply-add costs when it waits for…
isod89 Nov 7, 2026
d73b13d
v37 diagnostic 13: rdq, the layer routines with each value loaded ahead
isod89 Nov 7, 2026
e7ec912
v37 diagnostic 14: CPU1 taking 20 or 24 frames, each effect's cost
isod89 Nov 7, 2026
64efcb3
v37 diagnostic 15: the engine block by block; drive, cabinet and NAM …
isod89 Nov 7, 2026
eee34cf
v37 diagnostic 16: filters two at a time
isod89 Nov 7, 2026
22f5dcd
v37 diagnostic 17: integer cabinet and drive filters, the drive at x2…
isod89 Nov 7, 2026
cb9497d
v37 diagnostic 18: NAM time per part, post3, post in whole blocks wit…
isod89 Nov 7, 2026
2808bb3
v37 diagnostic 19: tap pointers moved on without position arithmetic,…
isod89 Nov 7, 2026
b019aa9
v37 diagnostic 20: a NAM layer's groups of 4 frames in one call (rdl)
isod89 Nov 7, 2026
af1a65a
v37 diagnostic 21: every factory preset timed as the audio interrupt …
isod89 Nov 7, 2026
9d672f3
v37 diagnostic 22: CPU1 serves the network after its effects, roles t…
isod89 Nov 7, 2026
3a44f74
v37: the benchmark screen off at boot again, '2C' in the status corne…
isod89 Nov 7, 2026
0b32e1b
editor: browse TONE3000 and load an A2 model from it (their Select flow)
isod89 Nov 7, 2026
8ef4605
editor: OpenPocket's TONE3000 publishable key
isod89 Nov 7, 2026
07d12ad
OpenPocket v37: merge the version history
isod89 Nov 7, 2026
b428642
OpenPocket v37: the source of the release
isod89 Nov 7, 2026
9e4f821
Button lights on the BlackBox: they follow the blocks (issue #8)
steponme82 Nov 6, 2026
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
4 changes: 2 additions & 2 deletions .claude/skills/verify/features/editor-page.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Editor page (docs/editor.html)

## Sub-features
52 presets (load, save, save as, move, factory reset), the current sound (blocks, types, parameters, order by dragging, name), JSON export/import, live follow of changes made on the pedal (WATCH), unsaved-change prompts, phone layout.
52 presets (load, save, save as, move, factory reset), the current sound (blocks, types, parameters, order by dragging, name), JSON export/import, live follow of changes made on the pedal (WATCH), unsaved-change prompts, phone layout; v37: the NAM models panel (A2 `.nam` files into the 16 user slots, `docs/pxnam.js`, protocol 2).

## How to get to it (user POV)
Open the editor from the installer page, Connect, edit.

## Driving it with Playwright
`sh .claude/skills/verify/scripts/pages.sh`; `tests/test_editor_page.mjs` talks to `build/edsim` (the real `px_editor.h` and `px_store.h`) through a fake Web MIDI. End state: every line `ok`, `editor page test passed`, `build/editor/editor_1..6*.png`. Protocol only (no browser): `node tools/op.mjs test` runs `tests/test_editor.mjs`.
`sh .claude/skills/verify/scripts/pages.sh`; `tests/test_editor_page.mjs` talks to `build/edsim` (the real `px_editor.h` and `px_store.h`) through a fake Web MIDI. End state: every line `ok`, `editor page test passed`, `build/editor/editor_1..6*.png` (`editor_6_nam.png`: the NAM panel). Protocol only (no browser): `node tools/op.mjs test` runs `tests/test_editor.mjs`.

## Gotchas
- Protocol is in `docs/EDITOR-PROTOCOL.md`; a change to a command needs both `px_editor.h` and `docs/pxedit.js`.
Expand Down
7 changes: 7 additions & 0 deletions NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ OpenPocket is GPL-3.0-only (`LICENSE`), except the parts below, which keep their
| `loader/` (update loader) | felucca-bsp `loader/`, changed for the Pocket X flash layout | MPL-2.0 |
| `docs/pxota.js`, `docs/pxpkg.js`, `tools/pxpkg.py`, `tools/mkloader.py`, `tools/lz4blk.py` | adapted from [Felucca](https://github.com/hugelton/Felucca)'s web installer and build tools (as used by CLIPPER and SLOOP) | GPL-3.0 |
| `firmware/sdk/` (I2S and DAC drivers as LLVM bitcode, SPL, cfg files) | JieLi AC79 SDK V1.2.0 (fw-AC79_AIoT_SDK) | Apache-2.0 (`LICENSES/Apache-2.0.txt`) |
| `firmware/px_cacheram.h` (data-cache ways as RAM, for the NAM network's vector-unit buffers) | [melodee](https://github.com/keremimo/melodee) `firmware/hal/fm1_cache.h`, Kerem Kilic (Ellic Studio), after the AC79 SDK's cache way setup | GPL-3.0 |
| `firmware/fonts.h` (bitmaps generated from Inter) | [Inter](https://rsms.me/inter/), Rasmus Andersson | SIL OFL 1.1 (`LICENSES/OFL-1.1-Inter.txt`) |

The factory NAM models (`engine/px_nam_factory.h`, v37) are A2-Lite networks trained by OpenPocket from Neural Amp
Modeler community captures ([pelennor2170/NAM_models](https://github.com/pelennor2170/NAM_models), GPL v3; authors
in `docs/NAM.md`) played with DI guitar from [Alec-Wright/Automated-GuitarAmpModelling](https://github.com/Alec-Wright/Automated-GuitarAmpModelling)
(GPL v3). The NAM A2 architecture is from Neural Amp Modeler (Steven Atkinson, MIT); `engine/px_nam.c`,
`tools/nam_a2.py` and `tools/train_a2.py` are written for OpenPocket from the published architecture.

Sound models: the names refer to the gear that inspired each voicing (circuit analyses published by ElectroSmash,
Electric Druid, R.G. Keen / GEOFEX, Rob Robinette, Duncan's Tone Stack Calculator; speaker data sheets; manufacturers'
manuals). All trademarks belong to their owners; OpenPocket is not affiliated with Donner, M-VAVE or any gear maker.
Expand Down
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
!!! THIS PROJECT IS A PROOF OF CONCEPT, DONT EXPECT FULL FUNCTION AND SOUND QUALITY !!!

Install here: https://isod89.github.io/openpocket/ (Donner Pocket X; M-VAVE BlackBox: v31 has the fix for issue #1, being tested)
NEW WEB EDITOR: https://isod89.github.io/openpocket/editor.html · What's new since v33: [docs/WHATS-NEW-v34-v36.md](docs/WHATS-NEW-v34-v36.md)
NEW WEB EDITOR: https://isod89.github.io/openpocket/editor.html · **v37: neural amp models (NAM A2), load your own from TONE3000**: [docs/WHATS-NEW-v37.md](docs/WHATS-NEW-v37.md) · since v33: [docs/WHATS-NEW-v34-v36.md](docs/WHATS-NEW-v34-v36.md)

**Open-source guitar multi-effects firmware for the Donner Pocket X and the M-VAVE BlackBox.**
Written from scratch for the pedal's own chip (JieLi AC791N, two cores), installable from the browser.
Expand All @@ -12,11 +12,15 @@ Written from scratch for the pedal's own chip (JieLi AC791N, two cores), install

## What it does

- **12-block chain, 77 models**, in any order you like (double-click PUSH to move a block; the order is saved with
- **12-block chain, 78 models**, in any order you like (double-click PUSH to move a block; the order is saved with
the preset): GATE, COMP, PITCH, SPECIAL FX, SYNTH, DRIVE, AMP, CAB, EQ, MOD, DELAY, REVERB
- **Synths, keyboards and other guitars** from a normal guitar (no MIDI pickup): organ, church organ, string machine,
choir, mono synth with pitch tracking and a resonant ladder filter, PWM synth, bass synth, 12-string, acoustic,
sitar (bridge buzz + sympathetic strings), baritone
- **Neural amp models (v37)**: the AMP block's NAM type runs Neural Amp Modeler **A2** networks on the pedal: 12
factory models trained for it (Twin, AC15, Super 59, Dirty Shirley, JCM900, JCM2000, JVM, Mark IV, Pro Mod, 5150,
6505+) and 16 user slots you fill from the web editor with A2 captures (TONE3000...). All 24 factory presets use
them. Details: [docs/NAM.md](docs/NAM.md)
- **8 amps fitted to captures of the real ones** (v34): Twin Reverb, AC15 Top Boost, JCM900, JCM2000, Mark IV,
Dirty Shirley, Pro Mod, 5150. A computer sets the engine's numbers (tube stages oversampled ×4, tone stack, power
amp, sag) so that it matches a Neural Amp Modeler capture of each amp on real guitar playing; same CPU cost as a
Expand All @@ -25,7 +29,7 @@ Written from scratch for the pedal's own chip (JieLi AC791N, two cores), install
Greenback, T75, Alnico Blue, Jensen, Cream, DI) with a MIC position
- **Pro levels (v36)**: every amp, block and preset at the same loudness (-23 LUFS, measured on real guitar);
24 factory presets round the fitted amps, 28 USER slots; a PRESET LVL per preset; soft output limiter
- What changed since v33: [docs/WHATS-NEW-v34-v36.md](docs/WHATS-NEW-v34-v36.md)
- What changed: [v37](docs/WHATS-NEW-v37.md), [since v33](docs/WHATS-NEW-v34-v36.md)
- **New screen (v36)**: a PLAY page readable from a distance (preset number and name, amp, chain in colour) and an EDIT
page with big values and bars
- **8 reverbs rebuilt in v35**: an 8-line feedback delay network with early reflections and moving lines (no
Expand Down
27 changes: 27 additions & 0 deletions docs/AUDIO-SDK.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,30 @@ Driver setup: `iis_open` IIS_PORTA, channel_in = BIT(1), channel_out = BIT(0), m
- Screen: PLAY (number and name large, amp / cab, the chain in colour, the selected block) and EDIT (the block on its
colour, model, 5 settings with value + bar), new Inter fonts (26 and 58 px). `tests/uisim.c` draws every page on
the PC and checks that each full page paints every pixel.

## v37: NAM A2-Lite, user models
- AMP type 8, NAM: a Neural Amp Modeler A2-Lite network (3 channels, 23 dilated layers, LeakyReLU, 16-tap head;
1871 weights, about 1,730 multiply-adds a sample) in fixed point, `engine/px_nam.c` ([NAM.md](NAM.md)). Activations
Q20, weights Q24, 64-bit sums shifted by a constant. Against the float reference (`tools/nam_a2.py`): 83 to 100 dB
signal to error on the factory models (`tests/test_nam.py`).
- This CPU has no data cache in front of the SRAM, a taken branch costs about 8 cycles, and it issues two
instructions together (a 32-bit multiply-add with a 16-bit load). A first version (a loop over taps per frame,
16-frame chunks) measured 223 % of real time on the pedal. Now: blocks of 32 frames, layer by layer. Gather: each
frame's inputs to the layer into one row of X (`[u, 1.0, taps x 3 channels]`, 3 words a move), from the layer's
ring (interleaved [time][channel], (kernel - 1) x dilation + 32 frames). Dot: the layer's 3 weight rows against 4 X
rows at a time (`pxn_dot3x4_asm`: a weight read once for 4 frames, 4 multiply-adds paired with 4 loads, 5 issues,
in the hardware loop). Post: LeakyReLU (predicated, no branch), the head sum, the residual 1x1 written straight
into the next layer's ring. The head is a 50-long row (bias, 16 taps x 3) over the head's ring. The hand routines
are in the flash with their callers; `px_nam_check()` compares them with the C ones at boot (pattern with both
signs, rows of 20 and 47, with and without the residual) and keeps C on any difference.
- Memory: the rings (83.4 KB) in the POOL region beside the engine, the model (weights converted, 8 KB) and the
block buffers (7 KB) in RAM. A direct call between the flash (0x02xxxxxx) and the RAM code (0x01C0xxxx) is out of
the call instruction's +-4 MiB: `tools/check_calls.py`, run by `firmware/build.sh` before linking, refuses any such
call and names it (a first v37 build put the audio path in RAM: the linker refused 478 calls, naming only one).
- User models: 16 slots of 8 KiB at 0xC0000 (`firmware/px_models.h`), written by the editor (protocol 2); the update
loader keeps that range (`loader/ldr_core.c`, `LDR_NAM_LO/HI`). The weights are read from the flash (SPI, with the
audio held) when a preset picks the model.
- Level: every model plays at the same loudness: a trim per model (-20 LUFS on `docs/nam_di.wav`, measured by the
editor for user models and by `tools/mk_nam_factory.py` for the factory ones), then one constant that puts NAM +
1x12 at GAIN noon at the fitted amps' -23 LUFS.
- 24 factory presets rebuilt on the 12 factory NAM models, levelled by `tools/level_presets.py`; USER slots: NAM TWIN.
8 changes: 7 additions & 1 deletion docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ Apple silicon and other ARM machines Docker emulates it (Rosetta or QEMU); you c

`make NATIVE=1 build` skips Docker and uses a toolchain installed on the machine (`sh firmware/setup.sh` installs it in
`~/.jieli`; Linux x86-64 only). `tests/run_tests.sh` also runs directly on macOS and Linux with only a C compiler, Node and
Python 3.
Python 3. Its NAM check (`tests/test_nam.py`, the fixed-point network against the float reference) also needs NumPy
and is skipped without it (the container has none).

The NAM factory models (`engine/px_nam_factory.h`, v37) are generated, not hand-written: `tools/train_a2.py` trains each
A2-Lite network from a capture (needs `pip install jax optax numpy scipy`, about 15 minutes a model on two CPU cores),
then `tools/mk_nam_factory.py LIST.txt DIR docs/nam_di.wav` writes the header with each model's level trim
([NAM.md](NAM.md)).

The `.bat` files `makeimage.bat` and `render.bat` only check that Node is installed and call `tools/op.mjs`. `build.bat` does the same when Node and Docker are there, and otherwise builds in WSL (`build.bat docker` or `build.bat wsl` forces one way). `INSTALL-OFFLINE.bat` needs nothing installed: it serves `docs\` with PowerShell (`tools/serve_offline.ps1`), and falls back to Python (`tools/serve.py`) or WSL only if PowerShell cannot open a port. `tests/test_op.mjs` (part of `make test`) checks the Docker command lines, the friendly errors and `make clean` without Docker, using a fake `docker`. `PUBLISH-GITHUB.bat` and `PUBLISH-SOURCE.bat` (PowerShell
`tools/publish_github.ps1`) are the maintainer's release tool and still need Windows; nothing else does.
Expand Down
37 changes: 35 additions & 2 deletions docs/EDITOR-PROTOCOL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# OpenPocket editor protocol (SysEx over USB-MIDI)

The web editor (`docs/editor.html`, `docs/pxedit.js`) talks to the pedal with this protocol. The firmware side is
`firmware/px_editor.h`; `tests/edsim.c` runs the same code on a PC for the tests. Protocol version 1 (OpenPocket v32).
`firmware/px_editor.h`; `tests/edsim.c` runs the same code on a PC for the tests. Protocol version 2 (OpenPocket v37; version 1: v32 to v36,
the same without the NAM commands 19..22).

## Framing

Expand Down Expand Up @@ -42,8 +43,40 @@ The 12 blocks, by index: 0 GATE, 1 COMP, 2 PITCH, 3 SFX, 4 DRIVE, 5 AMP, 6 CAB,
| 16 SAVE | slot | slot, rc. Saves the current sound into the slot, writes the flash, the slot becomes the current one (as the pedal's SAVE) |
| 17 WATCH | on (0/1) | on. While on, the pedal pushes `STATE` (cmd 5) when the sound, the slot or the focused block changes on the pedal; it stops by itself 5 s after the last request |
| 18 PING | — | DSP load % (0..127), flags (bit 0: bypass, bit 1: second core) |
| 19 NAM_LIST | — | factory models (12), user slots (16), then per model (factory first, then the user slots): present (0/1), name string (11 characters at most; an empty user slot reads "U5 EMPTY") |
| 20 NAM_WRITE | piece (2 bytes: bits 0-6, 7-13), 128 packed bytes | the 2 piece bytes, rc (0 ok, 1 invalid). Piece i holds bytes 112 i .. 112 i + 111 of a model (the last piece fewer), packed 7 bit: groups of a byte of high bits (bit j = bit 7 of byte j) then 7 bytes. Stored in RAM only |
| 21 NAM_COMMIT | slot (0..15) | slot, rc (0 ok, 1 invalid: header, a weight that is not a number, CRC; 2 flash). Checks the pieces received and writes them to the user slot |
| 22 NAM_ERASE | slot (0..15) | slot, rc (0 ok, 1 invalid, 2 flash). Empties the user slot |

Writing the flash mutes the sound for a moment, as saving on the pedal does. A whole import sends `SLOT_PUT` without
### NAM models (protocol 2)

The AMP block's ninth type, `NAM`, plays a neural amp model (NAM A2, its 3-channel "Lite" size, 1871 weights:
`engine/px_nam.h`). Its first parameter, MODEL, picks one of 28 models: 0..11 the factory ones (in the firmware),
12..27 the 16 user slots in the pedal's flash (`firmware/px_models.h`, 0xC0000..0xE0000, kept by firmware updates).
`TEXTS` of AMP type 8, parameter 0 gives each value's model name; the editor asks for it again after a change of
the user slots.

A user model is 7548 bytes, little endian: a 64-byte header, then the 1871 weights as float32 in the `.nam`
file's order.

| Offset | Size | Field |
| --- | --- | --- |
| 0 | 4 | magic `0x4D4E504F` ("OPNM") |
| 4 | 2 | version, 1 |
| 6 | 2 | weights, 1871 |
| 8 | 12 | name, ASCII, 0-ended (11 characters at most) |
| 20 | 2 | level trim, int16, 0.01 dB (added to the model's output) |
| 22 | 2 | CRC16 of the weights (polynomial 0x1021, initial value 0) |
| 24 | 40 | 0 |

The editor (`docs/pxnam.js`) reads a `.nam` file, takes its A2-Lite part (an A2 file is a "SlimmableContainer"
with several sizes; a plain A2-Lite WaveNet also works), measures its loudness on `docs/nam_di.wav` and sets the
level trim so that every model plays at -20 LUFS on that clip, then sends 68 `NAM_WRITE` and one `NAM_COMMIT`.
A1 models (the older "standard" / "lite" / "feather" WaveNets) and other architectures are refused: the pedal's CPU
runs A2-Lite only.

Writing the flash (`SLOT_PUT` with bit 1, `COMMIT`, `SAVE`, `NAM_COMMIT`, `NAM_ERASE`) mutes the sound for a moment, as
saving on the pedal does. A whole import sends `SLOT_PUT` without
bit 1 for every slot, then one `COMMIT`.

## Preset files
Expand Down
Loading
Loading