Skip to content

Improvement: a machine engine's DSP price lives in its own package - #1487

Closed
twwwy wants to merge 3 commits into
repeat98:mainfrom
twwwy:fix/engine-price-in-package
Closed

twwwy wants to merge 3 commits into
repeat98:mainfrom
twwwy:fix/engine-price-in-package

Conversation

@twwwy

@twwwy twwwy commented Nov 12, 2026

Copy link
Copy Markdown
Contributor
  • What was wrong or hard: Analog BD's DSP price (411 per voice, 3 per core) sat in its machine record, inside the controller digest that the base trusts by hash. Any price change meant a new trust row and a beta base rebuild, so 0.1.7's cheaper engine (150–162 per voice measured full-chain against 0.1.5's 380–391; see Analog BD 0.1.7: refused on T5-T8 even on an empty chip, and only one voice on T1-T4: the voice price is still 0.1.5's #1480) could not be reflected without one. Per repeat98 on Analog BD 0.1.7: refused on T5-T8 even on an empty chip, and only one voice on T1-T4: the voice price is still 0.1.5's #1480: "No base rebuild in this PR; a module update must never need one … take Analog BD's price from its package instead of a trust row built into the base", then "Reuse cycles and kind on engines … Leave init at 0 … Refuse 0 or a missing kind in the loader and in build.py … Engines get executed or hardware evidence only", and "cycles on an engine is the price per voice … Fold the per-core part into it".
  • What this changes:
    • An ABI 10 engine carries its price per voice in its header's cycles (bytes 44-45) and kind (46), outside the controller digest. Charged once per track that plays it, a fixed per-core cost folded in.
    • loader.c, abi9.engine (the builder) and the site's module-set.ts refuse an engine with cycles 0, a missing or modeled kind, or a nonzero init. Older bases already refuse any price on an engine, so they fail safe.
    • machine_registry.c charges a voice at its module engine's header price. A record still priced beside such an engine, a per-core cost of another kind, or no price at all is refused, never admitted free. Machines without an engine keep their record's price.
    • Analog BD now declares 414 (411 + 3 folded) in its engine header and 0/0 in its record (its source_kind stays, as Improvement: a CPU budget admits Octatrack machines before they play #1482's CPU budget and the voice checks read it). Same DSP room as today: DSP FULL appears where it did. 187 + 4 = 191 follows as a module-only Analog BD update once this merges.
    • Beta base rebuilt (on top of Fix: FM Synth's voices pass the Octatrack base's frame guard and CPU budget #1483). Only Analog BD's trust row and package change; Output Matrix, CC Map and Recorder Loop Fix keep their bytes and name the new base. Machine recipes recaptured: identical images, stock copies and fills; only the hashes of machine-ports.json and machine_ports.py move.
    • Found on the way: my first rebuild moved modwerk_controller_write_begin/end (an extra check in engine_shape grew a function before them), which silently untrusted the held Sidechain 0.2.1 package; the check was redundant with the loader's and is gone. Held entries also keep the old requiredBase (as in d720a028a, fixed by hand in 3cb49bae8). New sdk/tests/test_base_bound_trust.py: every published base-bound package is trusted by, and names, the committed base. It passes on main and caught the requiredBase slip again after merging main here.
  • How I checked it:
    • Host: new loader host-test cases (no price, modeled, no kind, nonzero init refused; 414 then 191 read back; a price-only change keeps the controller digest), abi9 builder tests, board fixtures (unpriced and modeled packages refused), registry test of the header path, site module-set.test.ts cases. Each new rule was mutation-checked: removing it makes its test fail.
    • npm run pr:ready: everything green except two SDK tests that fail identically on untouched main on this Mac (test_dsp_packages_rebuild_from_source, test_real_units_relocate_alike…: local dsp_asm builds, 1004 vs 1009 words); CI's pinned toolchain should differ. Untouched main rebuilds the committed base byte for byte on this Mac.
    • Hardware (twwwy's MKII, 13 November 2026, on the pre-merge commit 2eed068c): a --dev twin of this base (80f62ad6) with its own trust rows, Analog BD trials only (never kept):
      • at 414: second voice on T1-T4 refused "ANALOG BD NEEDS +20%", T5 alone refused "+23%", as on today's base;
      • the 191 package on the same twin, no rebuild, accepted under the same trust row; the base's source_voice table read 335 per voice (191 × 7/4);
      • at 191: two voices on T1-T4 admitted, the third refused "+9%, DSP 60%"; one voice on T5 admitted, a second refused "+11%, DSP 58%" (all as computed);
      • recorded over USB audio: T5 808 and 909 four-on-the-floor, 0.00-0.05 ms timing spread, no clicks or dropouts; 909 with FIXD ON sample-identical hit to hit (-66 to -81 dB); T1 + T3 + T5 together with 4× DARK REV; FX swaps, Analog BD ↔ FLEX, Part and pattern switches while playing stopped and resumed exactly where expected; self-test passed (longest frame 371 µs); crash and stall records unchanged throughout (an older module-pool crash record predates the session).
      • The PR's release base (de01247b, non-dev) RAM-booted and accepted the published Analog BD 0.1.7 and Sidechain 0.2.1 as one trial set. The unit's 16 kept modules were unchanged after every power cycle.
  • For the 191 follow-up (not this PR): Analog BD's ColdFire glue is not in Improvement: a CPU budget admits Octatrack machines before they play #1482's CPU budget (cpu_price is 0 for DSP-voice machines). At 191 each voice added about 4.5 points of CPU; three voices ran at about 67 % with the longest frame at 86 %, and twice a single frame reached 99.9-100.3 % (first PLAY, and during switching), nothing skipped. Worth deciding before three voices ship.
  • Not tested: the merged base (583a189a) on the unit; DSP load at 414; an unpriced or modeled engine on the unit (host only).
  • What the guides lacked or got wrong, and where I fixed it: docs/OCTATRACK_DRIVING.md said base-bound modules cannot be tested on a twin; it now gives the twin-only recipe route, and notes that a RAM boot sent through serve once left the unit off USB while the one-shot boot worked. sdk/runtime/loader/README.md now documents the engine price and that the site mirrors the loader's header checks.

🤖 Generated with Claude Code

twwwy and others added 3 commits November 13, 2026 03:16
An ABI 10 engine package carries its price per voice in its header's cycles
and kind (bytes 44-46), as an effect's per-instance figure: worst case per
sample, charged once per track that plays it. It lies outside the controller
digest, so a new price ships in the package and never changes the base's
trust row (repeat98, repeat98#1480).

- loader.c: an engine needs cycles > 0 and kind executed or hardware; init
  and the other descriptor bytes stay 0. Older bases already refuse any
  price on an engine, so they fail safe.
- abi9.engine (the builder) refuses the same; module-set.ts checks it as
  the loader does.
- machine_registry.c: a voice is charged at its module engine's price; a
  record priced beside it, a per-core cost of another kind or no price at
  all is refused, never admitted free.
- Analog BD: 414 per voice in its engine header (411 + 3 folded, so the
  same DSP room as today); its machine record keeps 0/0 and its kind.
- Beta base rebuilt; only Analog BD's trust row and package change.
  Sidechain 0.2.1 (held) stays trusted and now names the new base.
- Machine recipes recaptured: identical images, copies and fills; only the
  hashes of machine-ports.json and machine_ports.py move.
- New sdk/tests/test_base_bound_trust.py: every published base-bound
  package is trusted by, and names, the committed base.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream's repeat98#1483 rebuilt the base; this regenerates it with the engine price
change on top: Analog BD's recipe recaptured (identical copies and fills),
base and base-bound packages rebuilt, Sidechain 0.2.1's held entry pointed at
the new base (test_base_bound_trust caught it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…der's header checks

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

Copy link
Copy Markdown
Owner

Thanks, this is a clean change. The loader, the builder and the site refuse exactly the same headers, the published package differs from 0.1.7 only in its price bytes and record, and the new trust test is a good catch to keep.

Two things before it goes in:

  1. docs/OCTATRACK_PACKAGE_DSP_HOOKS.md (lines 74-76) still says the price (411 a voice, 3 a core) stays in the machine record and is a controller change until Phase 2. Please say there that the engine header's cycles and kind carry it now.
  2. The base files conflict with main again (Fix: an installed Sidechain keeps its key bus memory free from the start, so picks are not refused NO ROOM after a restart #1492 rebuilt the base this morning). Octatrack base: DSP hook chains, so several packaged DSP machines share a hook site #1418 rebuilds the base too and goes in first, so to spare you two rebuilds: please merge main and rebuild the beta base and the base-bound packages once Octatrack base: DSP hook chains, so several packaged DSP machines share a hook site #1418 has landed. I'll write here when it has.

@repeat98

Copy link
Copy Markdown
Owner

Thank you for this. It is merged into #1502 with your commits and authorship kept: every change that needs a new Octatrack base goes out there as one base update, so yours lands with it instead of waiting for a base of its own. If anything looks off in the combined branch, say so on #1502.

@repeat98 repeat98 closed this Nov 13, 2026
repeat98 added a commit that referenced this pull request Nov 13, 2026
…1520)

* Docs: the DSP hooks guide says the engine header carries the price

repeat98's review of #1487: docs/OCTATRACK_PACKAGE_DSP_HOOKS.md still said
the price (411 a voice, 3 a core) stays in the machine record until Phase 2.

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

* Docs: the price bullet becomes a pointer, so the guide shrinks

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: repeat98 <jannik.assfalg@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants