Skip to content

FRACT three-grain track machine (source and native FLEX support) - #926

Merged
repeat98 merged 33 commits into
repeat98:mainfrom
ex1010:fract-submission
Nov 6, 2026
Merged

repeat98 merged 33 commits into
repeat98:mainfrom
ex1010:fract-submission

Conversation

@ex1010

@ex1010 ex1010 commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

FRACT is a three-grain track machine with its own START and render, centered SIZE, wrapping POS and native FLEX pitch. This PR combines the machine source and the native FLEX reader support from #1108. Author: ex1010.

Ready for maintainer review of the source integration. The short hardware check requested for base 9b3ba417 is complete. This remains an unlisted source submission; the listed package/catalogue and its full qualification will be a separate PR. No automatic release is requested.

Source and shared support

  • Active source: sdk/drafts/fract-machine, with owned helpers, guarded private builder, licences and tests.
  • Three grains, one owner on T1–T4. MAIN: POS / SIZE / REVS / SPRD / SHPE / PTCH; SETUP: PAN / SRNG. Native FLEX pitch uses saved 64 as neutral. FX1/FX2 remain available; no active SPACE processor is linked.
  • The native FLEX opt-in requires a same-image START/render pair. Admitted readers retain their voice; refused or unpaid starts and ordinary own-render paths retain stop protection. The descriptor stays ABI 1 / 80 bytes.
  • The branch now preserves FR:1 in known[], with its regression test. compatibility.uiClaims is []: SRC MAIN/SETUP use the shared machine list. The machine guide preserves this native FLEX contract alongside main's new stock-level requirement.
  • UNBOUND8/Variant D is the author's own separate project and layout. Existing third-party licences and notices are retained. Both original PR histories remain ancestors; Fix: keep native FLEX readers alive for opted-in source machines #1108 is superseded by this submission.

Short physical check — 5 November 2026

The owner reports that ordinary machines and FRACT play, and that after saving a Part and powering the unit off/on, the track returns as FRACT and plays. Independent USB readback confirms base 9b3ba417, the exact installed set, one FRACT, a new boot session, and confirmed slot 1 generation 7 with no fallback. The previous confirmed slot 0 is intact. Native integrity SELF TEST passed before the power cycle (1/1 modules, no failures); it was not restarted after boot.

TESTING.md records the full base/module/set hashes and distinguishes owner observations from USB evidence. Main was merged and the guide conflict resolved after testing; all 233 base-proof inputs and 64 module-recipe source inputs still match the tested pair. No firmware rebuild or further device update was needed.

Validation

On commit a0dcb680, npm run pr:ready says Ready, exit 0: 343 app test files, 2,816 passed / 2 skipped; 563 SDK tests / 28 skipped; 39 supporting tests / 1 skipped. Typecheck, lint, bundle, catalogue, licences and compatibility pass (11 existing lint warnings). Both tracked-source-only isolated Docker builds pass; Octatrack development verification validates existing artifacts/source inventory/version pins, and all 37 current elemod release exports reproduce. GitHub CI is checked separately after the push.

The firmware-free gate compiles 10 C units plus one assembler unit, links at two synthetic origins and rejects obsolete FX/SPACE symbols. Normal/profile/detail checks and the draft-doctor temporary location were verified during consolidation. The current short-check preparation reran the normal source gate, 47 FRACT host tests (4 historical skips), 12 machine-event tests and the exact private pair in the full emulator (native FLEX, three advancing grains, retrigger and nonzero PCM; no loader errors). Emulator evidence is not physical timing qualification.

Source review remains partial: the consolidation checkpoint classified 10/499 parsed chunks, with 0 flags and 10 uncertainty records investigated; 489 parsed chunks plus 10 file blockers remain deferred, with 24 static exclusions. Review scope and investigation. This report adds documentation and merges reviewed main; it does not claim complete source review.

Preview

Approved FRACT conceptual artwork

Original conceptual artwork; illustrative values. SVG, PNGs and MIT reuse notice.

Select FRACT in SRC SETUP

Select FRACT in SRC SETUP.

FRACT sample browser

Choose a loaded FLEX sample.

FRACT MAIN with three grains

Play with three grain markers. These are private-prototype emulator captures supplied by ex1010, not exact-public-build hardware evidence. Screenshot and interface rights remain with their respective owners.

Remaining release work

The draft doctor still reports absent listing/package/fingerprint, compatibility pairs and full release qualification. A separate listed-release PR still needs the exact package and catalogue row, install/Keep/Undo/removal/power-cycle evidence, memory/cycle measurements, companion loads and the owner's approval record. Long stress, physical live-trigger deletion and parameter-extreme audio quality remain untested.

Firmware, extracted stock code, samples, audio, memory dumps, card/NVRAM images and private build outputs are excluded. Guide correction: native FLEX opt-in and shared voice-memory regression requirements are documented; this update also preserves main's stock-level requirement. No additional guide gap was found in the short hardware check.

Three-grain Flex granulator and stereo SPACE, with source, media,
resource evidence and the partial exact-build MKII hardware report.
Authorship: ex1010. Attribution-only rebuild retains the installed
runtime package bytes.
@repeat98

Copy link
Copy Markdown
Owner

Hey, thanks for FRACT. The README and the tests are really thorough.

Before the smaller fixes, one bigger thing. Reading sourcehook.s, the grains don't process FX2's input: they replace the Flex track's own source audio on the ColdFire, right after the stock fetch, before FX1 even sees it. Only SPACE lives in the FX2 slot. So FRACT is really a machine that borrows an FX2 slot, and I'd like it registered as one: a track machine in the base's ot_machines table with its own render, the way POLY8 plays the track's Flex sample.

Why:

  • The base's frame guard only bounds renders that go through the machine registry (machine_registry.c). FRACT's grains run in the frame interrupt outside it, at up to about 25 CPU points, so in a busy project they can stop the frames instead of dropping out on that one track.
  • I don't want players to have to set TSTR OFF. As a machine, FRACT renders the track's source itself, so it shouldn't depend on the stock timestretch path any more. If TSTR still needs handling, FRACT should handle it, not the player.
  • Clearing the trig declick and the one-track bookkeeping become the machine's own business instead of edits to stock Flex, and FX1 and FX2 stay free for whatever the player wants there.

One catch on my side: ot_machines has room for 4 today, and Analog BD, POLY8, FM Synth and VECTOR take all of it. I'll raise that in the base in its own pull request, and you can build against it once it's in.

Smaller things you'll hit either way:

  • module-contract is red because the fifth release note is 205 characters (200 max). Test status belongs in the PR description; the notes say what changed for players.
  • octatrack-source fails with "Unsupported reviewed module scope": FRACT isn't in the package builder's list in scripts/build-module-packages.py, and the package side (engine assets, base binding, native comparison, licence files) isn't in the PR yet. LOFI2 (Add LOFI2 0.1.0-experimental: Bryan T's ring modulator / frequency shifter with sample-rate and bit reduction #749) shows the full set. I'd leave that for the machine version, since the list and the assets change with it.
  • It was built against base d6bfff70. Please rebuild against current main and run npm run module:verify and npm run pr:ready before you mark it ready.

Keep it as a draft until then. Happy to answer questions here.

repeat98 added a commit that referenced this pull request Oct 25, 2026
An effect processes its slot's audio on the DSP; a module that makes or
replaces a track's sound is a machine; one that makes notes is a MIDI
generator. The module guides say when to choose each category, the
new-module plan settles it first, the PR review checks it, and
module:doctor refuses an effect whose performance record prices audio
work on the ColdFire (FRACT, #926).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@ex1010 ex1010 changed the title Add FRACT 0.10.0-experimental for Octatrack FRACT track-machine migration (draft; shared SDK support pending) Oct 28, 2026
@ex1010 ex1010 changed the title FRACT track-machine migration (draft; shared SDK support pending) FRACT three-grain track machine (draft; source and native FLEX support) Nov 4, 2026
@ex1010
ex1010 marked this pull request as ready for review November 4, 2026 06:18
@ex1010 ex1010 changed the title FRACT three-grain track machine (draft; source and native FLEX support) FRACT three-grain track machine (source and native FLEX support) Nov 4, 2026
@repeat98

repeat98 commented Nov 4, 2026

Copy link
Copy Markdown
Owner

Thanks for pulling #926 and #1108 into one PR, it's much easier to follow this way. FRACT as a track machine with its own START and render is what I was hoping for. The grains go through the frame guard now, and nobody has to turn TSTR off. The native FLEX opt-in leaves every other machine's path exactly as it was.

On the base: the room I promised has been on main since 29 Oct (71f6c59). ot_machines takes eight machines now, and FRACT needs one row, so there's nothing more to wait for there. The one base piece still missing is FR:1 in known[] in machine_registry.c, so the battery restore at boot keeps a FRACT track's bytes until the set has reinstalled. I'll add that line to this PR myself, with its test, the same way SYNTIZ's WV 1-15 went in (996abd9). The regenerated base then gets a short run on a unit before it merges.

Two small things:

  1. compatibility.uiClaims. FRACT's SRC MAIN and SRC SETUP pages come through the base's machine list, and the guide counts that as shared, not as a claim. With the two screen claims, the configurator would refuse FRACT next to any other machine that declares them. I'd make it [], and I can do that in the same push if you're fine with it.
  2. UNBOUND8. fract_ui.c says it adapts "UNBOUND8's approved Variant D". Is UNBOUND8 yours? If it's someone else's design, their credit and licence belong in THIRD_PARTY_NOTICES.md.

Once this is merged, the listed release comes as its own PR from your side. It needs the package and its row, plus the exact public build on your unit (install, Keep, Undo, removal and a power cycle) recorded in TESTING.md. I'll write the approval record at that point.

@ex1010

ex1010 commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks, that all makes sense. Please go ahead with FR:1 in known[] and its regression test, and change compatibility.uiClaims to [] in the same push as you offered. I agree that SRC MAIN and SRC SETUP are shared through the base machine list and should not be exclusive claims.

UNBOUND8 is my own separate project (ex1010/toli). The "approved Variant D" reference in fract_ui.c is my own layout design from that project, reused for FRACT; it is not a design by another author.

Agreed on the sequence: a short run of the regenerated base on a physical unit before this PR merges, then a separate listed-release PR with the package, catalogue entry and exact-public-build install/Keep/Undo/removal/power-cycle evidence in TESTING.md.

repeat98 and others added 12 commits November 4, 2026 11:15
The boot's battery restore keeps a FRACT track's twelve bytes while the
module is not yet reinstalled (beta finding 24), as SYNTIZ's WV 1-15 did
(996abd9). FRACT's uiClaims become [] (its SRC pages come through the
base's machine list; ex1010 agreed on repeat98#926), and the draft's README,
TESTING, START contract and manifest no longer say main lacks FR:1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
npm run octatrack:base -- --beta --write, then
npm run octatrack:module-packages -- --base-only: only requiredBase moved.

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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…417)

main's repeat98#1007 moved the beta base to 462fbd2b. The generated base assets
were taken from main and rebuilt on the merged source, so FR 1 sits on
main's new base: npm run octatrack:base -- --stock OS.bin --beta --write
(base 9b3ba417...), then npm run octatrack:module-packages -- --base-only
--stock OS.bin: only requiredBase moved.

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>
@repeat98

repeat98 commented Nov 5, 2026

Copy link
Copy Markdown
Owner

Thanks for the quick answers, and good to know UNBOUND8 is yours.

I've pushed what we agreed to your branch: FR:1 in known[] with its regression test, compatibility.uiClaims: [], and current main merged in. The base on the branch is now 9b3ba417 (FR:1 on top of main's latest base, which Mute Modes 0.2.2 moved this morning). README, TESTING.md and the manifest's build reason say the base keeps FR:1 at boot but hasn't run on a unit yet. pr:ready says Ready.

Could you give that base a short run on your unit? It's the last thing before this merges, and I can't get to mine for a few days. A minute or two is plenty:

  1. Update to this branch's base over USB with your usual modules, and check that the unit boots and the other machines still play.
  2. With your private FRACT build on the same base, save a Part with FRACT on a track, power-cycle the unit, and check that the track comes back as FRACT.

Please put what you saw and the base id in TESTING.md, or post it here and I'll add it. If another base change reaches main first, I'll regenerate and send you the new id, and the same two steps cover it.


Generated by Claude Code

ex1010 and others added 3 commits November 5, 2026 22:44
Preserve native FLEX opt-in guidance alongside the new stock-level requirement. Record owner-reported sound and Part restoration, independently verified USB cold-boot identities, and the limits of the short private-pair check. All 233 base proof inputs and 64 module recipe source inputs remain identical to the tested pair.
@repeat98
repeat98 merged commit 9f230b2 into repeat98:main Nov 6, 2026
8 checks passed
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