Repository navigation
Conversation
…13ed8) The engine, page and the author's FM SYNTH chooser are vendored byte for byte from timhastie/octatrick-modules v2.12 (ca13ed8): the 2.10 engine with 6 dB of headroom, the 2.11 machine list (a row table, six row-count detours in place of the 2.10 pokes, five row-clamp detours, the SELECT MACHINE TYPE scroll) and the two 2.12 changes: the metronome click no longer cuts a held note (the engine's hook on the click word is removed), and a machine change to or from FM SYNTH resets the track's machine parameters to init, step and scene locks kept as in stock (one new detour, po_unload). With FM Synth alone the list keeps its six rows. Modwerk's machine.s / registration.s are dropped; the bundled quantizer keeps 0.1.2's drawer fix (repeat98#264). Every stock expectation is a stock_guard (73). The author's native Analog BD conflict is cleared in the wrapper (Modwerk declares it in octamod.module.json). Emulator evidence on the image built from this source (MAIN OS 00fa6caa): cycles (one VOIC 4 track 81,422 of 95,779 cycles/block, the largest of five runs), exact memory (43,812 module-owned bytes), stack bound 352 B, two-instance Part/project save and reload, the metronome case and the machine-change init, captures, Part smoke, odd-address check. Hardware fields are placeholders for the author's report. The native/browser record is not refreshed: POLY8's bridge is bound to 0.1.2's chooser hooks (TESTING.md).
…rt inventory refreshed on main 3151975
…racks) The bundled quantizer moves to timhastie/octatrick-modules 48b89e7 (tag v2.13; its synth/ files are the same bytes as v2.12 ca13ed8, so the engine, chooser and page are 0.1.4's). With a scale on, a MIDI track's NOTE knob and NOTE locks step through the scale from ROOT and its CHROMATIC keys play the scale from ROOT (three new detours: 0x40055382 qz_mknob, 0x40050b98 qz_mplock, 0x400436a8 qz_mkey); NOT2..4, TRAN, the arpeggiator, MIDI IN and SCALE OFF are unchanged. 2.13 takes Modwerk's repeat98#264 form of the CHROMATIC drawer hook (0x400449be), so quantizer.s, core.s, keys.s, scale.s and README.md are the author's files byte for byte; the quantizer manifest is his 2.13 manifest in stock_guard form (23 guards). The module LICENSE carries his 2.13 LICENSE (one sentence crediting Modwerk's form). Inventory sdk/imports/synth-48b89e7.json, following 0.1.4's synth-ca13ed8.json. Emulator evidence on the image built from this source (MAIN OS 37661aee): the FM objects are byte-identical to 0.1.4's at the same addresses; NOTE knob / locks 409 of 409 and CHROMATIC keys 245 of 245 against a model of the rules, SCALE OFF as stock, the sequencer unchanged, the quantizer's added cost per call; Part smoke, two-instance persistence, machine-change init; exact memory (44,404 module-owned bytes), stack bound 352 B; 0.1.4's cycle table with its bounding cards rerun here; seven captures (a MIDI track's CHROMATIC page new; two 0.1.4 captures dropped for the eight-media limit). Hardware fields are placeholders for the author's report.
…nly); Analog BD record re-verified and rebound build-module-packages.py --include-requested on this source, imported with --development: only the Synth objects and the Synth version change against main's 0.1.2 packages (Modwerk's fmregistration object is gone, the author's poly and fmmachine objects come in, the bundled quantizer objects change; 0.1.4 has no package commit of its own on this branch). The Analog BD record's moduleSourceTreeSha256 is rebound after verify-analog-bd-native.mjs passed against the new packages (162 native OS and GNU bootloader comparisons, 50 matching refusals, 6 firmware round trips).
…rt inventory refreshed on main 263aa1b
… scale, and a per-track exemption, are planned; a drum track is programmed with SCALE OFF until then
|
Is this ready to merge? |
|
Hi, From my side, yes. The module, the record and my hardware report on the
exact image (MKI, 13 Oct) are in. Two things to mention on your side:
1. Both failing jobs are modules:check stopping at the Tape Echo
preservation binding. The branch changes generated packages under
src/engine/assets, so it needs your binding (or a Tape Echo
re-qualification). I can’t clear that from here.
2. POLY8 and this FM Synth don’t work together for now: POLY8’s bridge
still points at the 0.1.2 chooser, so a build with both stops at POLY8’s
seam check, and FM Synth alone is unaffected. A later update of POLY8’s
composition file can fix that.
SY DRUM (repeat98/modwerk#558 <#558>)
is stacked on this one and becomes ready once this is merged.
- Tim
…On Tue, Oct 13, 2026 at 10:11 AM Jannik Aßfalg ***@***.***> wrote:
*repeat98* left a comment (repeat98/modwerk#555)
<#555 (comment)>
Is this ready to merge?
—
Reply to this email directly, view it on GitHub
<#555?email_source=notifications&email_token=ANTUMBCHMOBIHDCHGVIJY6D5TZO2TA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTMMJVGA4TSNRZGU3KM4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2KYZTPN52GK4S7MNWGSY3L#issuecomment-6150996956>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ANTUMBH6FQGNJALMUJB4I4T5TZO2TAVCNFSNUABGKJSXA33TNF2G64TZHMYTGOJZGM2DSMZTHA5US43TOVSTWNJYGMZTKMZVHE2TTILWAI>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/ANTUMBADP5RKZC4Z3DGDLRT5TZO2TA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTMMJVGA4TSNRZGU3KM4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2KUZTPN52GK4S7NFXXG>
and Android
<https://github.com/notifications/mobile/android/ANTUMBFGDWXRA42UWQKXDUD5TZO2TA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTMMJVGA4TSNRZGU3KM4TFMFZW63VGMF2XI2DPOKSWK5TFNZ2K4ZTPN52GK4S7MFXGI4TPNFSA>.
Download it today!
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
|
Thanks for 0.1.5. I tried to bring it up to date with main today, and it can't be merged yet. It needs more than a refresh. Main has moved a lot since 13 October: the Octatrack base now owns the machine table and several MIDI, chromatic and project events, and POLY8 compositions are checked against FM Synth. 0.1.5 hasn't been checked against that yet. I merged main into your branch locally, moved your notes to What fails on that merge, all without firmware:
Lint, typecheck, the bundle, the catalogue, licences and the package rebuild pass. How FM Synth 0.1.5 registers on the base has to be settled on our side before there is anything useful for you to change, so please don't spend time on rebasing it for now. I'll write here again when I know what is needed. |
|
Thanks for the base update! Is the FM Synth 0.1.5 registration blocker now resolved, or should I still wait before rebasing? If it’s ready, what changes are needed before I rebuild and rerun verification—and does the same guidance apply to SY DRUM? |
|
Hi Tim, sorry for the wait, and thanks for holding. You can start now. FM Synth 0.1.2 on main shows how a machine registers on the base. Your files stay byte for byte under upstream/, and sdk/machines/octatrack/module-adapters/machine-ports.json maps each of your hooks on a base-owned site to a base event (po_mon to ev_midi_note_on, qz_octkey to ev_octave_key and so on). The rest stay guarded patches. For 2.18: a fresh branch from current main, your files in upstream/, then |
|
Thanks, Jannik! I'm starting now: a fresh branch from main with my current line under upstream/, the machine-ports.json lines that modules:compat asks for, and the USB package from build.py. Understood on SY DRUM: I'll make it build and work without FM Synth. I'll answer on #884 separately. Please close this PR when the new one is up. |
|
Hi Jannik, thanks again for unblocking the re-cuts. Before I build SY DRUM, a quick question about which way you'd like it. I'd like people to be able to use SY DRUM and FM Synth in the same project, and I see two ways:
Both need a fifth slot in ot_machines. Which would you prefer? |
|
A few more things I'd like to check with you before I prepare the PRs:
Thanks! |
|
Hi Tim, thanks for asking first.
|
|
Thanks Jannik, that settles it.
One more: my 2.19 quantizer adds seven MIDI-track sites (the MIDI knob, p-lock, key, note, arp trig, preview and held-trig mark) that FM Synth's bundled copy and the standalone quantizer both patch, so the two would overlap. I'm preparing take events for them like the existing ev_knob_store / ev_plock_store. OK with you, or would you rather I handle that another way? |
|
Hi Jannik, three things from building against your answers:
One more: my ev_engine_job draft sits at index 35, which #912 now holds; I'll renumber at merge. |
|
Hi Tim, thanks, that's a lot of useful detail. In the order you asked: Quantizer, the seven MIDI-track sites. Some may already be covered. #857 added For the rest, I'd rather not add events whose only users are two copies of your own quantizer. FM Synth doesn't need MIDI-track quantizing for its own tracks. So please put that part in Scale Quantizer only, and keep FM's bundled copy to what FM tracks need (the events it already uses). Sites that only Scale Quantizer patches then stay ordinary guarded patches. We add an event when a second module needs one. One thing to watch: #954 (ARP KEY LOCKS) also takes 1. LFO SETUP's PMTR names. You're right. That instruction indexes the table by the track's raw byte, and a machine's track keeps 0 or 1, so the pointer swap gives FLEX's page. Analog BD has the same problem, so it's the base's to fix: On 2. SY DRUM. Thanks for spelling out the one-record limit. I don't want to change the table contract for this. Could SY DRUM be a second engine on FM Synth's own row instead, the way Analog BD opens its engine list (POOL, For the SETUP editor at 0x4003a524: please check first whether USB: thanks for the numbers. The loader won't get multi-MB DRAM regions or a bigger image for now. FM Synth's USB package stays at 0.1.2 with the declared lag, and SY DRUM ships in card builds. One question: a track is one machine at a time, so could FM and SY DRUM share one lock table instead of two 2 MiB ones? 3. Tuner. (b) is good: the Tuner clears its own slot when it closes, and the base's check stays read-only. Please add a line about it to
|
|
Thanks Jannik, that's all clear, and I'll send the quantizer addresses separately. On SY DRUM, I'd like to push back a little before changing course. On 26 Oct you wrote:
I built FM Synth 0.1.5 to exactly that: SY DRUM inside FM Synth, registered as a second machine with its own ot_machines record, waiting only on the extra row. It's built, and the card test image passed every item on my test sheet on my MKI on 26 Oct. Reworking it into an engine on FM Synth's row means redoing the chooser, track_page and render dispatch, plus the setup page and step-lock handling, and then retesting all of it on hardware. That's a lot of rework for something that already works. You asked whether there's a reason it needs its own row. On the unit, SY DRUM behaves as its own machine: it has its own name in the SRC list and the double-tap list, its own SRC and SETUP pages, and its own step locks and scenes. Users pick it the way they pick FLEX or STATIC. Hiding it behind FM Synth's engine list would make it the one machine you can't choose directly. Since FRACT and WAVE (#1028) need rows as well, could the base raise ot_machines' room once, to 8 for example? That covers SY DRUM and the machines waiting, without changing how a row works. If that's a problem for the table contract, tell me what limits it and I'll work within that. On sharing one lock table: I'm open to merging them in a future version. The current build was made and tested before I knew that, with separate tables and their own card files, and card builds have the room, so I'd rather ship it as it is. Since SY DRUM ships in card builds only and FM Synth's USB package stays at 0.1.2, the size doesn't matter for USB yet, so the merge can come in a later update. |
|
You're right, Tim. I said option 1 on 26 Oct and you built to it, so let's keep it: SY DRUM stays inside FM Synth with its own chooser row, and I withdraw the engine-on-FM-Synth's-row suggestion. A machine people pick directly, like FLEX or STATIC, belongs in the list as its own row. That needs two changes in the base, and I'll make both in one base PR and tag you:
Two lock tables are fine for now, since SY DRUM ships in card builds only. Merging them can come in a later update. The SETUP editor question from my last comment still stands: please check whether |
|
Thanks Jannik, that's great, and thanks for the base PR for SY DRUM. Here are the seven quantizer sites, checked against current main (
I'll keep those seven as guarded patches in Scale Quantizer only. FM Synth on its own will keep SCALE, ROOT and GLIDE in PROJECT > CONTROL > SEQUENCER, with one SCALE for all FM tracks and no per-track rows, and Scale Quantizer keeps its full per-track rows. One question before I build that: I'd like FM Synth and Scale Quantizer to install side by side, with one set of scale controls on the page. That needs more SEQUENCER rows than the 8 the base allows today, since Scale Quantizer adds 19, and the two per-track scale masks persisted with the other scale settings. Would you accept a base PR from me that raises the added-row limit to at least 19 and persists those masks? If yes, I'll send it together with both module updates. If not, the two stay declared as conflicting, as they are now. On the SETUP editor at 0x4003a524: I checked, and |
|
Thanks Tim, that's exactly what I needed. Scale rows. Let's keep FM Synth and Scale Quantizer declared as conflicting for now, as they are, so no base PR for the extra SEQUENCER rows. FM Synth with one SCALE for all FM tracks, and Scale Quantizer with its per-track rows and the seven guarded patches, sounds right. SETUP editor. Thanks for checking. I'll add the field to the machine record in the same base PR that lets one module contribute several This PR still sits on 13 October's main. When you build the quantizer split, please start from a fresh branch off current main, as in my 25 October note. Push it here or open a new PR, whichever is easier for you. |
|
@timhastie, the LFO-names base fix is up as #1080: |
|
Thanks Jannik, and thanks for doing the LFO SETUP fix in #1080. I'll list the card build's LFO-names detour under the Agreed on keeping FM Synth and Scale Quantizer declared as conflicting for now. One update on the rows: Scale Quantizer now needs only five SEQUENCER rows instead of 19. They are SCALE, ROOT and GLIDE as before, plus TRACK, which picks a track, and FOLLOW, which sets that track ON or OFF. The per-track settings save through the module's own project lines as before. Five rows fit within the eight contributed rows, so no base change is needed for them. I'm now working on letting FM Synth and Scale Quantizer install together. They would run one shared quantizer with a single set of those five rows, so there would be no duplicate SCALE, ROOT or GLIDE. I'm building it, and the quantizer split, on fresh branches off current main. Once it passes in the emulator and on my unit, I'll share the results and ask whether the conflict can be lifted for the pair. |
|
Hi Tim, thanks for the update. One thing before you build the install-together version, so it doesn't cost you a rebuild: two modules can't share one quantizer. If FM Synth and Scale Quantizer run a single quantizer with one set of rows when both are installed, one hooks into the other's code and rows, and a module may not hook into another module's code, rows, tables or files. Shared code would have to go into the base or the shared SDK first. So let's keep them declared as conflicting, as we agreed on 30 October, and send the FM Synth re-cut and the Scale Quantizer split as their own PRs off current main. I'll close this one when the FM Synth PR is up. Generated by Claude Code |
|
Hi Jannik, understood on 31 October: the shared-quantizer build is withdrawn and the two stay declared as conflicting. I'd still like users to be able to have FM Synth and Scale Quantizer on one unit, so here is the dilemma and the routes I can see. I'd like your view on which to take, and whether there is one I haven't thought of. Why FM Synth keeps a quantizer: its chords are built on scale degrees, its chromatic keys and legato follow the scale, and GLIDE slews between scale notes. Without the scale in FM Synth, mono tracks would still snap through the PTCH word, but chords, legato and GLIDE would lose the scale, and I don't want to take that from people using it. So both modules need the same scale state and key sites. Card builds have no base, so I've marked what each route gives.
Which would you take? Or if you have another idea let me know. Either way the FM Synth re-cut and the Scale Quantizer split come first, off current main. |
|
Hi Tim, thanks for laying the routes out so clearly. Route 4 for now: keep the two declared as conflicting and send the FM Synth re-cut and the Scale Quantizer split as agreed. Route 1 would put MIDI quantizing back into FM Synth, and I'd rather keep that in Scale Quantizer. Route 2 is the right shape once more modules want it: a base-owned scale with one "snap this note for this track" accessor could also serve VECTOR and the MIDI generators. Could you open it as a hook proposal issue, with the routes and the modules you see using it? We'll build it when a third module needs it. Card builds keep the conflict either way. |
|
Thanks Jannik. Route 4 it is: the FM Synth re-cut and the Scale Quantizer split come as two PRs off current main, declared conflicting, with the Tuner as a third. The hook proposal for the base-owned scale is #1145, with the routes and the modules I see using it. |
|
Thanks Tim. Closing this one now that the re-cut is up as #1146, with Scale Quantizer 0.1.4 in #1147 and the Tuner in #1148. The review carries on there. Generated by Claude Code |
…r: a module may not hook into another module's code, rows, tables or files); FM Synth stays a declared conflict in one sentence; on main 00ecaf5 the image rebuilds byte-identical to TEST2, the author's MKI report of 30 October is its record
FM Synth 0.1.5: scale quantizer on MIDI tracks (the author's 2.13 quantizer)
This is an author update of FM Synth (
synth), which I am registered for. It moves the quantizer bundled inside FM Synth to my octatrick 2.13 line,timhastie/octatrick-modulesat48b89e7e5315971bf5c29a3fd86183abe8df48f3(tagv2.13). Version0.1.4-experimental->0.1.5-experimental; the catalog pin, release notes and changelog are updated. The FM engine, the FM SYNTH chooser and the page are unchanged from 0.1.4: at48b89e7mysynth/files are the same bytes as atv2.12.0.1.4 was not submitted on its own, so this PR carries both: 0.1.4's two commits, then 0.1.5's five (source and documents, packages, evidence revision, README wording, and my hardware report). The branch is rebased onto main
c181b76b0155c68db4f0efc558f34cfa3a5c8b58(fetched 13 Oct 2026, 08:50 PDT; the rebase applied without conflicts). At 08:58 PDT main was at23556edd; the commits sincec181b76change only documentation (AGENTS.md,CHANGELOG.md,docs/ADD_A_MODULE.md,docs/APP_DEVELOPMENT.md,docs/module-guides/, the elekloader README), none of them a file this branch touches. Since the commit the packages and evidence were made on (263aa1b), main has changed nothing in this module's folder, insdk/octabam/, insdk/catalog.jsonor in the generated assets this branch rebuilds, and a rebuild from the rebased head gives the same image (below).What changes from 0.1.4
SCALE and ROOT act on MIDI tracks too. With a scale on (PROJECT > CONTROL > SEQUENCER, SCALE and ROOT):
qz_mknob(jsr, 8 B) at0x40055382, the knob handler's MIDI clamp just before its store0x4005538a; the store stays stock.qz_mplock(jsr, 10 B) at0x40050b98.qz_mkey(jmp, 10 B) at0x400436a8.What is not snapped in this version. NOT2–NOT4 stay semitone offsets, TRAN transposes in semitones, the arpeggiator's own notes, MIDI IN, VEL / LEN, CCs, LFOs on NOTE and scene locks are stock. An option for the chords, TRAN and the arpeggiator to follow the scale is planned for a later version, together with a per-track switch that exempts a MIDI track from the scale (a drum machine's note numbers are sounds, not pitches). Until then, with a scale on, every MIDI track's NOTE knob, locks and chromatic keys snap: a drum track is programmed with SCALE OFF, and stored notes are never changed. Stock's own ARP SETUP > KEY still forces everything a track sends into a key, per track. SCALE OFF is stock; nothing new is stored.
The #264 fix is now in my own line. Modwerk's 0.1.2 moved the bundled quantizer's CHROMATIC drawer hook to the common argument push
0x400449be(#264: CHROMATIC on a MIDI track froze the unit). My public line carried the old site from 2.9 to 2.12; 2.13 takes Modwerk's form at the same site, credited to the Modwerk contributors in my quantizer README and LICENSE. So the bundledquantizer.sis my file byte for byte again. FM Synth images were never affected.Files.
upstream/quantizer/quantizer.s,core.s,keys.s,scale.s,README.mdandupstream/LICENSEare my48b89e7files byte for byte.upstream/quantizer/manifest.pyis my 2.13 manifest in Modwerk's stock-guard form: its 23 stock expectations becamestock_guard(address, length, SHA-256), each checked against an original MAIN OS 1.40C (164f3122…) first; nothing else in it changed.stock-guards.json: 76 guards (the quantizer's 23, three of them new). The moduleLICENSEcarries my 2.13 LICENSE in full: one added sentence crediting Modwerk's #264 form. The wrappermanifest.pychanges its docstring and proof note only. New inventorysdk/imports/synth-48b89e7.json(following 0.1.4'ssynth-ca13ed8.json). No stock bytes are committed: mytools/stock_scan.pyfinds no stock run of 16 bytes or more in any data file of the module folder, and the assembled quantizer's hits are the six displaced-instruction replays and assembler idioms of my reviewed 2.13 scan.Compatibility. The public Scale Quantizer and Analog BD stay declared conflicts. Modwerk's MIDI Scenes builds only on its own, so it never shares an image with FM Synth; its writes cover the knob store
0x4005538a, and the new hook ends just before it. No conflict entry is added. The POLY8 item of 0.1.4 is unchanged (below).Evidence (emulator, exact image)
The image is MAIN OS
37661aee03a49f310d47e1447f043489c1bce9430c13824dd49ab93ad835e236, built byscripts/export-composition-proofs.py --vendored-sdk --static-stock --modules synth --select synth:truefrom this branch (rebuilt from the final source commit, and again from the rebased head on mainc181b76: the same bytes both times). The update file isb42048d5…(462,628 B, OCTAMOD79); Modwerk's TS packer decodes it to that MAIN OS and re-encodes the same bytes. Pinnedot_emu9dc31d12…. Details inTESTING.md.00_poly.oand01_fmmachine.oare byte-identical to 0.1.4's, and the platform runtime's first 23,072 bytes (both units) are identical and at the same addresses. Every other image difference is the quantizer's (its DRAM unit, its hook sites and table entries, the appended loader).verify.pyPart smoke passes on this image; two FM tracks pass Part save/reload, project save/reload and a fresh project load; the 2.12 machine-change init gives FM SYNTH's init both times with FX1 kept. Not testable on the emulator: the power cycle with only battery RAM and the card (on my hardware sheet).tools/align_check.py(2.13): 5,843 instruction rows in five linked objects, all even; 78 detour / symbol-ref / poke targets even.media/capture.json): five byte-identical to 0.1.4's, the SEQUENCER window now MINOR / A, and a MIDI track's CHROMATIC page with the "A 3" readout (new). 0.1.4's SELECT MACHINE TYPE and SCALE captures are removed: main's audio preview makes eight media with seven screenshots.Open: FM Synth with POLY8 (unchanged from 0.1.4)
POLY8's chooser bridge (
sdk/octabam/modules/poly8/composition.json, unchanged in main's POLY8 0.2.7) is bound to FM Synth 0.1.2's chooser hooks; my chooser (0.1.4 and this version) makes different claims, so a build with POLY8 and FM Synth stops at POLY8's seam check,npm run module:verify -- synthstops at the first such selection, andsdk/native-comparisons/synth.jsonstays main's 0.1.2 record. Without POLY8 in the pool (a local run on main263aa1b, not committed): 122 selections, 35 builds match native outside the platform writes, 87 refusals match, 0 mismatches; the native side ran the same exporter on the host toolchain because Docker is not available here. The same tests fail as for 0.1.4 (TESTING.md, "Composition parity"). I have not changed POLY8's files; I can prepare the bridge update if you want it.Load, plainly
FM SYNTH and SY DRUM tracks are heavy on processor load, and track freezes with many instances of either are expected. FM Synth runs on the ColdFire inside the audio interrupt. One FM SYNTH track at VOIC 4 takes about 85 % of an audio block on the emulator (81,459 of 95,779 cycles, this record's maxConfiguration), and the record qualifies one instance. More FM SYNTH tracks, or SY DRUM tracks beside them (SY DRUM is submitted separately and shares this engine), overrun the block, and then tracks can stall or the unit can freeze. That is expected with many instances of FM SYNTH or SY DRUM; it is not a defect of a particular project. The figures are emulator cycle counts at the record's calibration, not hardware times; the Processor Load module (submitted separately) shows the headroom on the unit.
Hardware
I tested the exact image above (MAIN OS
37661aee…, FM Synth 0.1.5-experimental, the update fileb42048d5…) on my Octatrack. The same facts are intests.qualification.hardware(hardwareStatusreported, my own report) and inTESTING.md:release-notes.jsonstill says the report is pending: that file is part of the native source fingerprint the measurements are bound to, so I left it as measured; the changelog entry,README.md,TESTING.md,docs/VERIFICATION.mdand the record carry the report. The record'sevidenceRevision/hardware.sourceRevisionpoint tobcf3b7f, the rebased commit of the measured source (the module folder is byte-identical to the measured7a5988a).My Octatrick 2.13 build carries the same quantizer source; a report of that build is of a different image and does not qualify this one.
Tape Echo preservation gate
Main
c181b76carries the Tape Echo browser-infrastructure preservation gate (scripts/browser-infrastructure-preservation.mjs, reached fromscripts/retained-evidence.mjs). This branch changes generated packages undersrc/engine/assets/(the rebuilt FM Synth objects and the re-bound Analog BD record), sonpm run modules:check -- --base origin/mainandnpm run modules:generateboth stop at "Invalid or stale Tape Echo browser preservation binding; full qualification is required". I cannot clear that from my side: it needs your binding (or a Tape Echo re-qualification). Becausemodules:generatecannot run,src/catalog/module-documents.jsonis not regenerated in this PR: it still lists FM Synth 0.1.2, whilesdk/catalog.json, the packages and the changelog are at 0.1.5. Amodules:generateafter the binding produces it; I am glad to push that commit once the gate passes.Checks
All on this branch as pushed, rebased on main
c181b76, Node 24.21.0, 13 Oct 2026, without switching the gate off:licenses:check,machines:check,elekloader:check,sdk:imports:check,typecheck,lint(0 errors; 7 warnings, all in files this branch does not touch).modules:check -- --base origin/mainandmodules:generate(above), and thereforenpm run check -- --base origin/main, which stops atmodules:checkafter the licence and machine checks.build:bundlewas not run to a result: it needspublic/module-media/, which onlymodules:generatewrites.module:doctor -- synth: catalog entry, library, category guide, packages (compiled at 0.1.5), thumbnail and declaration checks pass; "module rules" fails on the gate and "native comparison" on the POLY8 item.python3 -m unittest discover -s sdk/tests, as insdk:check): 227 of 228 pass (7 skipped); the failure istest_measured_release_keeps_hardware_attribution_separate, the native-comparison record (POLY8 item).npm test(vitest): 2,253 of 2,282 pass. Of the 29 failures, 5 also fail on an untouched checkout of mainc181b76in the same environment: the 4scripts/module-pages.test.mjstests (missingpublic/module-media/, written bymodules:generate) andsrc/tooling/elekloader-update.test.ts, which exceeds its 5 s timeout on this machine; 4 are the POLY8 item (src/engine/requested-modules.test.tsx2,src/catalog/native-comparisons.test.ts,src/catalog/synth-release.test.ts"publishes through measured cycles …"); 2 are the gate itself (src/catalog/module-qualification.test.ts"preserves tapeecho qualification …", andscripts/module-doctor.test.mjs, whose doctor run reports the failing module rules); and 18 come from the catalog thatmodules:generatecould not regenerate:Compiled module versions differ from the catalog(src/engine/module-build.test.ts,compose-os.test.ts,core-logger.test.ts,session.test.tsx4,src/catalog/build-support.test.tsx2),Changelog version is newer than the catalog for synth(src/community/module-changelogs.test.ts, andsrc/tooling/check.test.tsx7, whosecheck.mjsruns reach the same changelog check), and the 0.1.5 quick test against a 0.1.2 catalog entry (src/community/downloaded-module-guide.test.ts). On mainc181b76in the same environment: 2,277 of 2,282 (those 5).37661aee…, update fileb42048d5…, the bytes of the image I tested.tools/stock_scan.py(2.13) over the module folder finds no run of 16 or more stock bytes in any file; overupstream/(assembled) it finds the same 49 runs as my reviewed 2.13 scan (displaced-instruction replays and assembler idioms, at most 22 bytes); over every other file this branch changes, the hits differ from main's copies only where FM's package changed, and the runs added there are among those 49.263aa1b, wheremodules:generatewas not stopped (a scratch copy with test values in the hardware fields):modules:generateandmodules:checkpassed, a fresh import of the packages reproduced the committed assets, and the only test failures were the POLY8 item and acheck.test.tstimeout on this machine.Review scope
The scope is wider than this module's folder: the branch also carries 0.1.4, and 0.1.5 changes
sdk/catalog.json,sdk/imports/(the 0.1.5 inventory),docs/VERIFICATION.md, the FM Synth release tests (TS and SDK), one module-source test version, the FM quick-test version insrc/community/downloaded-module-guide.ts, the changelog and the rebuilt packages and records; the moduleLICENSEgains the sentence from my LICENSE. So this needs owner review; I have left the automatic-publication boxes unticked.Checklist
Ticked where the facts above show it for this branch as it stands. The open boxes are the gate (
modules:check,module:doctor), the POLY8 item, and the two that are your decisions.Automatically merge and publish my module update after checks pass.
I verified the source, licences, UI and qualification reports, including instance isolation and Part/project/reboot persistence where applicable; no required acceptance check is failed or untested.
New or changed module: I read the guide for its category in
docs/module-guides/(andsequencing.mdif it acts in time), walked its checklists, and TESTING.md lists what I did not test.npm run module:doctor -- <id>is green.Every code change to a module has a greater semantic version and exact catalog pin (documentation and media edits need none).
Source and media are original or properly licensed; authors and full licence texts are preserved.
No Elektron firmware, extracted routines/tables, upgrade files or other infringing material is included.
Every new/changed module with OT UI has real screenshots of its location and relevant control pages, manifest
accessinstructions, andmedia[].otUiversion/build/setup provenance.I verified the captions, button/menu steps, screenshot authenticity and page coverage against the current module UI.
TESTING.md records commands, results, exact source, conditions and limitations; emulator and hardware evidence are separate.
CPU, DSP core and memory gauges are populated in
resources.impactwith rough load tiers, workload, rationale and source records.Runtime/resource changes and new modules:
tests.qualificationcontains worst-case cycle counts for every processor used, under parameter extremes, simultaneous modulation, mode changes and maximum load, within the declared real-time budget.Runtime/resource changes and new modules: exact memory regions include code, state, tables, buffers, stack/heap, padding and shared allocations; words, word widths, bytes and maximum-instance totals agree with the native allocation/build report.
Runtime/resource changes and new modules: this version/source/build has attributed real-hardware test evidence verified by the reviewer (the owner for first releases; the registered author for scoped updates).
Complete README/TESTING/licence/control/compatibility documentation, at least three practical tutorial steps and real black-and-white PNG screenshots document the current behavior with honest version/build provenance.
I rebased onto current main and ran module/version checks on this revision.
Credits
949f3be.Full MIT terms are in the module's
LICENSE.How to test
npm ci, thennpm run check -- --base origin/mainandnpm run module:doctor -- synth(both stop at the Tape Echo gate until it is bound, see above).