Skip to content

Tiempos 0.1.0-experimental: time left on all eight tracks (USB only) - #1096

Merged
repeat98 merged 16 commits into
repeat98:mainfrom
imdantelo:tiempos
Nov 7, 2026
Merged

repeat98 merged 16 commits into
repeat98:mainfrom
imdantelo:tiempos

Conversation

@imdantelo

Copy link
Copy Markdown

Tiempos 0.1.0-experimental (new module, Octatrack, USB only)

A screen with the time left on all eight audio tracks, opened with CUE + MIDI from any page. It works out each voice's real playback speed from how fast its play position moves, so timestretch, repitch and tempo changes are included without knowing the sample's BPM. It only reads OS memory: it writes no stock code or data, patches no sites, and has no DSP code. Follows #953, where the owner closed the card question: since #993 a C runtime module with sources in its package row has no card form.

Author: @imdantelo (Diego Antelo Barba). Code written with Claude Code.

What is in this PR

  • sdk/octabam/modules/tiempos/, moved from sdk/drafts/tiempos/ and declared like Beat Slicer: manifest.py, a verify.py gate (host test plus a byte-for-byte package rebuild), README, TESTING, evidence/performance.json, and two LCD photos in media/.
  • runtime.json and unit.s removed. build.py tiempos.c binds the core's four hooks by symbol name (module_tick, module_draw, module_key, module_enc), and the package comes out byte-identical without them.
  • New since the draft: pressing the same track key twice within 0.4 s closes the screen. Both presses still reach the unit, so stock QUICK ASSIGN opens as it does on stock. I chose to keep that behaviour, so no stock gesture changes. One press still selects the track and leaves the screen open.
  • Row in src/engine/assets/octatrack-module-packages.json, a sdk/catalog.json entry, src/community/module-changelogs/tiempos.json, and the regenerated module-documents.json and compatibility-pairs.json.

Owner decisions needed

  1. ABI 4 publication. The package is ABI 4: only the core's four hooks, with no event words and no sites. module_packages.capabilities accepts only ABI 6–9, so npm run octatrack:module-packages stops with "Not a supported published runtime ABI". As a result the package row has no sha256 or public file yet, verify.py reports [FAIL] the package row is not completed yet, and test_published_module_packages_rebuild_byte_for_byte fails. usb-only.ts, module:doctor ("USB package … a C runtime module, no card form") and modules:compat all accept the module. Should ABI 4 be added to the published set, or should Tiempos declare an event or table it does not need to reach ABI 6+? Changing the shared check would be its own Fix: PR; nothing in this PR touches a check.

  2. Performance waivers. perf:audit fails three rows that only an owner approval can waive, as with Beat Slicer:

    • There is no static cycle bound.
    • There is no cfmeter or frame-guard figure: my unit runs the released base, which has no modwerk_cost and answers no development requests.
    • There is no MIDI flood: Tiempos has no MIDI path.

    Here is what we have instead.

    • Emulator, development base 6a44c813. The draw costs 314.6 µs a UI tick with the screen open and empty rows. Scaled by pixel count, eight playing rows would cost at most about 4.3 ms, against a 16.4 ms budget.
    • MKI. No change on LOAD or in the base's five-minute records, with the screen open or closed.

Test evidence (details in TESTING.md)

  • Host tests: 16/16 pass with -Werror.
  • Hardware: my Octatrack MKI, OS 1.40C, on the released Modwerk base 24a0ed57 (built from a local checkout as the owner asked in Proposal: Tiempos, time left on all eight tracks (Octatrack, USB only) #953), driven over USB.
    • Package 0506a245…, which is this PR's exact package:
      • Timed trial: single and double presses on track keys.
      • Install with Keep → power cycle: the base restored the set (set a=1 [31282ae5]) and CUE + MIDI opened Tiempos → Undo back to the empty set.
      • A seven-minute trial with three tracks playing: CPU 62 % just after a minute with the screen open, against a 64 % peak without Tiempos. DSP load and space were unchanged, and there was no stall.
    • Package 225a0170…, the previous package with the same drawing and timing code, checked against a stopwatch:
      • Totals 2:08 at 120 BPM and 1:49 at 140 BPM on 64-bar tones at 100, 120 and 140 BPM.
      • Trimmed Static and Flex tracks.
      • 1:25 left and 0:24 elapsed at stopwatch 0:24.28.
      • The last-30-seconds flash and a hand retrigger.
  • Not tested: an MKII, Part changes and project reloads with the screen open, timestretch modes other than NORMAL, and other modules beside Tiempos.
  • Screenshots: phone photos of the MKI's LCD, cropped and converted to greyscale. They were taken with 225a0170; the drawing code is identical in 0506a245.
  • npm run module:doctor -- tiempos: green except the three performance rows (decision 2); the board claim is the author's until 2026-11-13. npm run pr:ready: not Ready only because of decision 1.

What the guides lacked or got wrong

These are not fixed in this module PR, which ships alone. They can be a separate Docs: / Fix: PR if you want them:

  • docs/ADD_A_MODULE.md and module:doctor treat a C runtime module with only the core hooks as publishable, but the publication pipeline refuses its ABI (decision 1). Nothing warns about this before octatrack:module-packages runs.
  • The performance section assumes modwerk_cost or cfmeter. It doesn't say what to do when your unit runs a released base. Here the emulator with a development base was the only way to measure the hook cost.
  • pr:ready runs modules:pairs with the system python3. On macOS that is 3.9, which crashes on int | None in dsp_dynload/package.py. It needs Python ≥ 3.10 on PATH, and the error doesn't say so.
  • LCD photos have to be greyscale PNG. modules:check catches that, but docs/MODULE_UI_CAPTURES.md doesn't mention it for photographs.

🤖 Generated with Claude Code

Diego and others added 5 commits October 26, 2026 12:10
Draft of a ColdFire runtime module: hold CUE and press MIDI for one screen
with every audio track's time left, measured from each voice's play speed.

- Read the trim start and end at voice +0x28/+0x2c (+0x30 is 0 on a playing
  Static voice, read in the emulator) and count from the trim start.
- English column notices (ELAPSED, TOTAL); one UI claim, key:CUE+MIDI.
- README lists the stock-flow change (CUE + MIDI no longer switches to MIDI
  tracks while installed).
- TESTING.md: pinned-toolchain build, 13 host checks, and emulator evidence
  (MKI panel, development base): the gesture and keys, removal, and three
  64-bar tracks at 100/120/140 BPM shown within a second of the expected
  times at project tempos 120 and 140. No hardware results yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README: USB-only limit, the CUE + MIDI line kept, and a track that has
not played yet shows empty. TESTING: the base the MKI ran (24a0ed57,
built from the local site at 976c6ca), two trials of 225a0170 (totals
of a whole, trimmed and Flex track, tempo change, keys, as reported),
and the DSP stall after USB DISK MODE that the unit's log recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…loses, MKI evidence

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

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

Copy link
Copy Markdown
Owner

Thanks Diego, this is a really complete first PR: the MKI lifecycle with a kept power cycle, the stopwatch checks and the photos are what I asked for in #953.

On your two questions:

  1. ABI 4. A C package with no event subscriptions comes out of build.py as ABI 4, without a name, and the site only publishes ABI 6 and later. Rather than teach the site ABI 4, I'll change the builder so such a package is ABI 8 and carries its title, as a subscribing one already does, so the unit's inventory names Tiempos too. It changes the base, so it comes in its own Fix: PR after the two base PRs ahead of it; I'll tag you. Once it's on main: merge main into tiempos, run npm run octatrack:module-packages to rebuild the package and fill its row, do one short install, Keep and Undo on your MKI with the new package (its SHA-256 changes), and run npm run pr:ready until it says Ready.
  2. Performance. I accept the three waivers for this experimental release.

Two text fixes, since they show on the module page:

  • octamod.module.json → compatibility.limitations still says "Not yet tested on a unit…" and that the key codes are "to be confirmed on an MKI". Replace those with what is still open.
  • README: "Tests and measurements" still says "Host tests only; no hardware…", and the stock-flow entry ends "Not checked on a unit". Bring both in line with TESTING.md, then run npm run modules:generate. Neither file counts toward the qualification hash.

Generated by Claude Code

…view)

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

Copy link
Copy Markdown
Author

Thanks! Both text fixes are pushed (21f6b7d): the limitations and the README now match TESTING.md. I'll merge main once your builder fix lands, rebuild the package with npm run octatrack:module-packages, and run install, Keep and Undo on my MKI with the new package.

repeat98 commented Nov 1, 2026

Copy link
Copy Markdown
Owner

Thanks, Diego, the text now matches TESTING.md. One thing to fold into your push after the builder fix: a track with a negative RATE plays backwards, and as I read tiempos.c (around line 132), a falling play position counts as a jump on every tick, so the row keeps the last forward speed and counts toward the sample's end. Could you check one reversed track on your MKI and either handle it or add a limitations line? The builder fix isn't up yet; I'll tag you when it's on main.


Generated by Claude Code

Diego and others added 3 commits November 2, 2026 14:59
…and MKI results

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

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

@imdantelo the builder fix is on main (#1231). It didn't need a base change after all. The base's loader already reads the ABI 8 form, and the change sits in scripts/octatrack-module-packages.py, not in the pinned build.py. So npm run octatrack:module-packages now publishes a C package with no event subscriptions as ABI 8, named after its id ("tiempos" in the unit's inventory). Every other package rebuilds byte for byte.

Next steps on tiempos:

  1. Merge main.
  2. Reversed playback (my 1 Nov comment) is still open. Check one track with a negative RATE on your MKI, then either handle it in tiempos.c or add a limitations line.
  3. Run npm run octatrack:module-packages. It writes public/octatrack-modules/tiempos/0.1.0-experimental.mwrm and fills the row's abi, features, name, module, bytes and sha256. Then run npm run octatrack:module-packages -- --check until every package says identical.
  4. verify.py calls build.py directly, which still makes ABI 4, so repack the same way before you compare. Add import importlib.util and replace data = out.read_bytes() with:
    spec = importlib.util.spec_from_file_location('packages', ROOT / 'scripts/octatrack-module-packages.py')
    packages = importlib.util.module_from_spec(spec); spec.loader.exec_module(packages)
    data = packages.titled(out.read_bytes(), 'tiempos')
  5. Do one short install, Keep and Undo on your MKI with that file, and add it to TESTING.md under its SHA-256. From the PR's current tiempos.c it is 8163c42c… (2,488 bytes). If you change tiempos.c in step 2, use the sha256 the command writes into the row.
  6. Run npm run pr:ready until it says Ready, then push.

Generated by Claude Code

Diego and others added 4 commits November 7, 2026 13:04
# Conflicts:
#	sdk/catalog.json
#	src/catalog/compatibility-pairs.json
#	src/catalog/module-documents.json
#	src/engine/assets/octatrack-module-packages.json
…a417

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

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

Copy link
Copy Markdown
Author

Updated after #1231:

  • main merged (246c3b4). npm run octatrack:module-packages publishes Tiempos as ABI 8, named "tiempos": public/octatrack-modules/tiempos/0.1.0-experimental.mwrm, 2,852 bytes, SHA-256 0b54a734258945acbf74551b8920ee4bfa760d390964bd04d2877e4382e990b9. --check says identical for every package, and verify.py now checks that its build matches the published file.
  • MKI, base 9b3ba417, that exact file: install and Keep, the inventory names it "tiempos", CUE + MIDI opens TIEMPOS, it is still there after a power cycle, and Undo returns to the empty set, after which CUE + MIDI switches to the MIDI tracks again, as on stock. Recorded in TESTING.md; the qualification points at this package.
  • Reverse playback is solved. Speed is signed. Going backwards, time left counts down to the trim start and time played counts from the end. A jump against the playback direction counts as a retrigger. RATE 0 shows --:--. Tested on the MKI, and the host tests pass (24/24).

One thing for you: module-set.test.ts treats any hook words as site events (> 0, linked to features 128). titled() keeps the four UI handler words for a C package with no events, so Tiempos has 4 hook words and features 0, which is what the builder computes. The one-line fix to the test (> 4) is #1301; pr:ready on this branch is waiting on it.

@repeat98

repeat98 commented Nov 7, 2026

Copy link
Copy Markdown
Owner

Thanks Diego, signed speed is a nice way to handle reverse playback, and thanks for finding the test.

#1301 is on main now. Bar LED went in beside Tiempos since your last merge, so please merge main once more. octatrack-module-packages.json, module-set.test.ts, sdk/catalog.json and module-documents.json will conflict: keep both Bar LED's and Tiempos' rows, regenerate with npm run modules:generate and npm run octatrack:module-packages -- --check, then run npm run pr:ready until it says Ready and ping me.

# Conflicts:
#	sdk/catalog.json
#	src/catalog/module-documents.json
#	src/engine/assets/octatrack-module-packages.json
#	src/engine/elekloader/module-set.test.ts
@imdantelo

Copy link
Copy Markdown
Author

main merged again (dd3ae53, with Bar LED and Stem Rec). The conflicts in octatrack-module-packages.json, module-set.test.ts and sdk/catalog.json are resolved by keeping both rows. module-documents.json and compatibility-pairs.json are regenerated. npm run octatrack:module-packages -- --check: every package is identical, Tiempos still 0b54a734… (only playmodes is held at 0.1.1, as on main). verify.py passes.

pr:ready is not Ready yet, for one reason I can't fix from the branch: module:doctor marks Tiempos's three performance rows (cycles, stock benchmark, stress), the ones you waived on 31 October. As far as I can see, the doctor accepts a waiver only through sdk/tiempos-build-approval.json, which only you write. Here is the record for this version, in the same shape as Beat Slicer's:

{
  "kind": "owner-approved-update",
  "id": "tiempos",
  "version": "0.1.0-experimental",
  "approvedBy": "repeat98",
  "approvedOn": "<date>",
  "ownerStatement": "<your words>",
  "reason": "Tiempos runs only on the UI task (tick, draw, key, encoder hooks) and has no MIDI path or frame-interrupt work. Its draw cost is an emulator estimate scaled by pixel count, and the MKI LOAD readings are in TESTING.md. No static bound, no cfmeter capture and no MIDI flood.",
  "waived": ["chip-worst-case-cycles", "current-build-hardware"],
  "sourceSha256": "45e53efc39e6aba499d312e8e0b26995d2110a6657cbff8f06dc3aaaa9c1f035"
}

The other failures pr:ready reports locally also fail on main and aren't Tiempos's: PageTraffic.test.ts and community-activity.test.ts (date-dependent), and in module-doctor.test.mjs other developers' board claims (beat-slicer, poly8, vector, …), which only show while I'm signed in to the board. Once the approval file is in, I'll rerun pr:ready, push, and let you know.

@repeat98
repeat98 merged commit 9d77bf2 into repeat98:main Nov 7, 2026
8 checks passed
@repeat98

repeat98 commented Nov 7, 2026

Copy link
Copy Markdown
Owner

Thanks Diego, Tiempos is merged and live: https://modwerk.app/module/tiempos/

I added sdk/tiempos-build-approval.json for my 31 October waiver and merged main once more on your branch, so there's nothing left for you to push. Thanks for sticking with it through the builder change and the reverse-playback fix.

@imdantelo

Copy link
Copy Markdown
Author

Thanks a lot for the reviews and for adding the approval record. Happy to see it live.

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.

3 participants