Skip to content

Octatrack beta base: more DSP room (receiver in the shared window), FX2 swaps keep their block, with the fix/base-oct28 bundle and the Python firmware codec - #1017

Merged
repeat98 merged 66 commits into
mainfrom
claude/dsp-window-pool
Oct 28, 2026
Merged

repeat98 merged 66 commits into
mainfrom
claude/dsp-window-pool

Conversation

@repeat98

Copy link
Copy Markdown
Owner

One beta base for testers this round. Four pieces ship together, with the committed beta base regenerated once from the combined source (6541d7e9):

  1. More DSP room: the loader's packet handling runs from the shared window. The DSP receiver's packet operations (WRITE and its read-back, SUM, BIND/UNBIND/BYPASS, BASE, PEEK, the refusal records) now run from the top 512 words of each core's FX2 block 3 (P:0x37e00, P:0x3fe00), copied there from the arena's top at the first frame. The frame path, PROBE, the reply and the engines' ops 10/11 stay in private P. Arena with nothing placed: 4,292 / 4,418 → 4,741 / 4,867 words (+449 per core). Effects still run from private P: code fetched from the window costs twice (measured, below).
  2. FX2 swaps keep their own buffer block, and the refusal box speaks plainly. A track swapping one buffered FX2 effect for another was refused MEMORY FULL … NEEDS A BUFFER, FX2 BUFFERS 4/4 whenever its core's four blocks were in use, because the planner reserved the outgoing effect's block. Stock gives every slot a fixed block, and the old effect finishes its sub-block before the new one's init, so the slot now keeps its block. A remaining refusal reads NO ROOM / the effect / FX2 ON T1-4 FULL / CHANGE ONE FIRST.
  3. The fix/base-oct28 bundle (merged here at 8dd674f7): POLY8 0.3.2 (card chooser scroll, [vector] Vector & Poly8 together, Vector missing from machine selector window #842 [synth] A minor bug #941 [configuration] FM Synth not showing on SRC list #942), module machines own their SRC SETUP page + VECTOR 0.2.5 ([recorder-loop-fix] Vector show just 1 SRC menu #972), SRC SETUP encoder E (SETUP_ALL) and the LIST flag (this contains Fix: Octatrack base, SRC SETUP's encoder E and the double-tap window for module machines (SETUP_ALL, LIST flags) #943's head), FLEX tracks no machine owns render unguarded (Octatrack base: frame guard skips stock FLEX tracks while FM Synth is installed #999).
  4. The Python half of Modwerk's own firmware codec (own-firmware-codec-py @ abc7055b), which the owner chose to ride on today's base: sdk/firmware_codec and use_elekloader() for every Octatrack tool. Its changelog is merged with Improvement: Modwerk's own firmware section codec and ColdFire decoder #1016's.

What players see

  • About 450 more words of effect code per DSP core: finding 53's heavy stock Part (LO-FI, FILTER, DJ EQUALIZER, CHORUS + DARK, SPRING, PLATE REV, FLANGER on T5-T8) now loads whole, and the project's module set on the test unit (BBD, Tape Echo, Mini Verb, E-Verb, Air Chorus) installs where origin/main refused it ("Mini Verb doesn't fit on either DSP core").
  • Owner-accepted limit: Air Chorus and BBD each declare a whole 16K FX2 buffer, so at most two of tracks 1-4 (and two of 5-8) run them on FX2 at once (were three); E-Verb, Mini Verb and every stock effect keep all their blocks.
  • FX2 swaps no longer fail on a full core; the one remaining refusal is in words a player understands.

How I checked it

  • Measured on the owner's MKII (core 0, dev builds, --dsp-burn-window): a 2,000-cycle loop cost 100.4 idle passes from private P and 203.5 from P:0x36000.
  • Host tests: test_recipe.py (39, incl. new test_window_buffers.c: block-3 rule, wide-first planning, own-block swaps) and the resident placement/board suites; the resident base patch was 3-way merged onto the split receiver and its pins re-set (it reproduces the merged sources exactly).
  • Base: npm run octatrack:base -- --beta --write → 6541d7e9, every flash-safety and browser = native check passed; a control run on clean origin/main reproduced the committed base byte for byte first.
  • Packages: npm run octatrack:module-packages -- --check: all 27 published USB packages rebuild byte-identical with the merged tooling (POLY8 stays at 0.3.1 and Play Modes at 0.1.1, both declared lags). VECTOR, FM Synth and Scale Quantizer's machine recipes were recaptured; only their input pins changed (image hashes the same). Isolated card-module build (build-modules-isolated.sh, pinned image) imported at 03006a5b; Tape Echo's and Euclid's recipes pin the new assets. Analog BD's 212 native composition proofs re-exported identical, only moduleSourceTreeSha256 restamped.
  • On the owner's MKII (RAM boots, no flash): every build's boot uploads ran through the window half on both cores (0 rejected, 0 errors, 0 stalls). Base 6541d7e9: self-test passed; Sidechain, Analog BD, E-Verb and BBD synced with a passing self-test. Its development twin played an 80 s session (PLAY, picks of DARK REV, LO-FI, Air Chorus, SPRING and PLATE REV and E-Verb while playing, Part 2 and back, bank B and back) recorded over 20 USB channels, the same as a twin of origin/main: MAIN 0 dropouts and 0 clicks on both, the largest jump around each action within 2 %, 0 rejected packets, 0 rollbacks. A 2.2 ms gap on T4 about 1.3 s after picking DARK REV there appears on both builds (not this change). Earlier twin: finding 53's Part loaded (4,665 of 4,741 words), a third Air Chorus on T1-4 refused with the new box, E-Verb took block 3.
  • npm run pr:ready: Ready.
  • Not tested: a flashed base and power-on restore of a kept set; long churn runs (owner: test like a player instead).

Owner decisions recorded here

What the guides lacked or got wrong, and where I fixed it

  • Nothing said that code fetched from the shared DSP window costs twice private P, or that Modwerk's base keeps stock's boot loops (which zero the whole window): docs/OCTATRACK_HARDWARE_TRAPS.md (the window bullet, rewritten, no growth), with the dated record in a new docs/OCTATRACK_DSP_WINDOW.md (listed in docs/README.md).
  • docs/module-guides/machines.md (from the bundle) linked the renamed EVENTS.md: now HOOKS.md.
  • npm run device -- meter 0|1 asked for a report length current bases refuse, so it never read: fixed in scripts/device.mjs.

Related to #999, #972, #842, #941, #942. Contains #943 (close it after this merges if it stays open).

🤖 Generated with Claude Code

npp1993 and others added 30 commits October 25, 2026 20:57
…for module machines (SETUP_ALL, LIST flags)

The base's SRC SETUP editor hook (machine_registry.s, from POLY8's shared
hooks) left encoder E (slot 10) read-only for every module machine, POLY8's
hidden slot; Analog BD keeps HIGH there, so HIGH never moved over USB. A machine
now sets MODWERK_MACHINE_SETUP_ALL to edit it.

A track whose machine has no pool opened its double-tap window on stock's
(empty) sample list, because Analog BD and FM Synth tracks are FLEX
underneath; the base corrected it afterwards, which flickered. A new owned site
at 0x400788c4 (mw_chooser_column) lets a MODWERK_MACHINE_LIST machine open on
the machine list at once, as PICKUP does.

Both are opt-in: POLY8, VECTOR, FM Synth and Analog BD 0.1.5 are unchanged
(Analog BD 0.1.6 sets both). Beta base regenerated; the base-bound packages
only change requiredBase; the machine recipes re-pin machine_ports.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ist's row

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lamps to the last row)

Stock's five chooser UP/DOWN handlers clamp the machine list's cursor to
row 5. With POLY8 at row 5 and VECTOR, FM Synth or Analog BD after it, the
list scrolled but the cursor stayed on POLY8. The composition's count sites
now set each clamp to the last row (card builds only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds byte-identical and stays at 0.3.1

machine-ports.json pins POLY8's new manifest and shared-machine.s and lets the
base's ot_machines own the chooser-name pointer (0x4007865e). The machine
recipes pin that file, so their sources move; POLY8, VECTOR, FM Synth, Scale
Quantizer and Analog BD rebuild byte-identical. The card-only clamp pokes are
not in the USB form (Elekloader's port runs the manifest as octabam_poly8).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r the cursor clamps

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… of 280 selections)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e pointer with the clamps

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…from main, rebuilt next

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…AGE)

Over USB the base draws and edits SRC SETUP for every module machine row
(mw_setup_draw6, mw_setup_edit6) and shows the track's backing pool's
FLEX/STATIC setup there, so a machine with setup rows of its own (VECTOR's
page 2: SEED, SPAN, OFST, ROT, RPT, DIR) had none (#972).

A machine that sets MODWERK_MACHINE_SETUP_PAGE (64) contributes a
struct modwerk_machine_setup: the 80-byte struct modwerk_machine, ABI 1,
then two words, page(stock) and knob(index, delta). While SRC SETUP's
cursor is on its row and the current track is its own, the drawer shows
the page it returns and encoders A-F go to knob first (nonzero takes the
turn; 0 lets stock edit the backing pool's byte, with encoder E's rule as
before). Records without the flag are read exactly as before, and a base
without it reads the first 80 bytes, so POLY8, VECTOR 0.2.4, FM Synth and
Analog BD 0.1.5 are unchanged. Flags 16 and 32 stay free for #943.

machine_ports.py emits the two words for a port that lists SETUP_PAGE;
the registry's host test covers the row, track, flag and encoder rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…record

VECTOR's port listed st_setup_draw6 and st_setup_edit6 in replaces (the base
owns those sites), so its own page 2 (SEED, SPAN, OFST, ROT, RPT, DIR) was
dropped from the package and SRC SETUP showed the stock FLEX/STATIC setup
on a VECTOR track (#972). The port now sets SETUP_PAGE and names the card
build's own st_setup_page and st_setup_knob, which the base asks on
VECTOR's row. st_setup_page's test that SRC SETUP's cursor is on row 5 (the
card's VECTOR row) is dropped in the package's source variant: over USB the
row is 5-8, and the base asks only on VECTOR's own row. control.s is
unchanged, so the card build is too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…recipe

The USB package changes (SETUP_PAGE record, one test less), so VECTOR's
machine recipe is recaptured from the stock OS (hashes only; the eight
copies move by the 10 dropped bytes) and every machine recipe re-pins
machine_ports.py, machine-ports.json and vector_runtime.py. Card build
unchanged; the README gains a section at its end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#922 made the double-tap TRACK chooser draw its rows from the list's scroll
offset, but stock's five UP/DOWN handlers clamp the cursor with moveq #5
twice each (0x40078c22, 0x40078cb0, 0x40078d2e, 0x40078dee, 0x40078e7c and
6 bytes on). With two or more machines the cursor stopped at row 5. The base
owns the ten bytes as ot_machines count sites and writes the last row, 4+n,
never below stock's 5 (addresses and guards as POLY8 0.3.2's card pokes).
The registry's host test checks the clamps for 0 to 3 machines; the
machines guide's chooser item and the base changelog say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ware report

The owner's unit, 27 October 2026, driven over USB by the coordinating
session on a development twin of the release base (e6e75d75, the b1b2ca58
build plus --dev): SRC SETUP page 2 draws and edits, the stock setup shows
on STATIC rows and tracks, Analog BD's page on its row. Recorded word for
word in TESTING.md and as the 0.2.5 qualification's functional hardware
report, with what was not tested.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
….4's bytes)

The isolated build of 0.2.5 changes only version fields in the card
package assets: VECTOR's card build is byte-identical to 0.2.4's (image
cabcc296...), so its eight captures document 0.2.5 as they stand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vector.test.ts: 0.2.5 publishes a reported functional hardware result; the
9 October owner exception still covers only 0.2.4; the card evidence records
(captures, behaviour, persistence, core tests) stay 0.2.4's, bound to the
unchanged native source. The quick-test guide and the source-scope test pin
0.2.5; Analog BD's composition proofs take the new module source tree hash
(VECTOR's card bytes are unchanged). The changelog's known issue names what
the unit run did not cover.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…0.2.5 source commit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rce tree (212 rows identical; only moduleSourceTreeSha256 moves)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… clamps)

Rebuilt with npm run octatrack:base -- --beta --write on main. Analog BD's
trust row follows its source policy (machine_ports.py, machine-ports.json);
its package bytes are unchanged. The five base-bound packages only change
requiredBase (--base-only). VECTOR's USB package (18,354 bytes, sha256
45c962ca) is rebuilt alone with its strict stock-free scans.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
repeat98 and others added 17 commits October 28, 2026 09:30
…n private P)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…perations in the window; docs and changelog

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and its twin

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sdk/firmware_codec holds the section format of Elektron OS images (aplib.py packs, elz.py depacks), the .syx
transport and ColdFire instruction lengths, for every machine. Every script that runs the pinned Elekloader
checkout now puts it on sys.path through firmware_codec.use_elekloader(), which serves these modules in place
of the checkout's codec/ and isa/ (an import finder first on sys.meta_path; it refuses if the checkout's codec
was imported first). sdk/tests/test_firmware_codec.py checks the codec against vectors of the modules it stands
in for and fails on any script that imports elekloader without use_elekloader() or reaches the checkout another
way.

The recipes that pin a build's inputs record the files actually used (firmware_codec.inputs()): CC Map, Mute
Modes, Tape Echo, Euclid and the five machine packages, refreshed after rebuilding every published USB package
byte-identical with the new tooling (Tape Echo's and Euclid's pins also take the page builder files they had
fallen behind). The beta base built from unchanged sources with this codec equals the committed one byte for
byte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-room box in the player's words

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, FLEX render #999) into the window base: one base for both

The generated base files take fix/base-oct28's side here; the beta base is regenerated from the combined source next.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…track tooling) into the window base

Conflicting recipe pins name the merged files; the package rebuild check proves them next.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the base-bound packages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cale Quantizer): every published package rebuilds byte-identical

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t forms (f1a2500)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… beta plan do not grow

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Euclid's recipes to them

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e proofs identical); the codec rule names elekloader-vendor.ts, which only edits the kit NOTICE (#1016)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@repeat98
repeat98 enabled auto-merge (squash) October 28, 2026 11:07
@repeat98
repeat98 merged commit acdf656 into main Oct 28, 2026
9 checks passed
npp1993 added a commit to npp1993/modwerk that referenced this pull request Oct 28, 2026
…nto claude/analog-bd-0.1.6

Generated files regenerated with their producers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

# Conflicts:
#	docs/module-guides/machines.md
#	public/octatrack-modules/analog-bassdrum/0.1.6-experimental.mwrm
#	scripts/module-source.test.mjs
#	sdk/machines/octatrack/HOOKS.md
#	sdk/machines/octatrack/base-binding.json
#	sdk/machines/octatrack/elekloader/runtime_events.h
#	sdk/machines/octatrack/events.json
#	sdk/machines/octatrack/include/modwerk_events.h
#	sdk/machines/octatrack/module-adapters/analog_bd_native_observations.json
#	sdk/machines/octatrack/module-adapters/controller-policies.json
#	sdk/machines/octatrack/module-adapters/machine-recipes.json
#	sdk/machines/octatrack/module-adapters/machine_ports.py
#	sdk/machines/octatrack/module-adapters/standalone-recipes.json
#	src/engine/assets/analog-bd-composition-proofs.json
#	src/engine/assets/bootstrap-package.json
#	src/engine/assets/coldfire-packages.json
#	src/engine/assets/descriptor-recipes.json
#	src/engine/assets/dsp-packages.json
#	src/engine/assets/menu-recipes.json
#	src/engine/assets/module-build.json
#	src/engine/assets/octatrack-base-fills.json
#	src/engine/assets/octatrack-base-sources.json
#	src/engine/assets/octatrack-base-variants.json
#	src/engine/assets/octatrack-base.elemod
#	src/engine/assets/octatrack-module-packages.json
#	src/engine/assets/platform-writes.json
#	src/engine/assets/requested-packages.json
#	src/engine/assets/resident-dsp.json
#	src/engine/assets/rom-packages.json
#	src/engine/assets/usb-audio-packages.json
#	src/engine/assets/utility-packages.json
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