Skip to content

Polish batch (verb~/sustain~/filecontainer/filter~) + max-test runtime harness#31

Merged
tap merged 5 commits into
mainfrom
claude/revival-md-planning-y0vjdj
Jun 19, 2026
Merged

Polish batch (verb~/sustain~/filecontainer/filter~) + max-test runtime harness#31
tap merged 5 commits into
mainfrom
claude/revival-md-planning-y0vjdj

Conversation

@tap

@tap tap commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Summary

Knocks out the remaining REVIVAL.md polish items and stands up a runtime (in-Max) test harness. Every new/changed external compiles and the Catch suite is 24/24 green.

Polish items

  • tap.verb~ — oversampling. New oversampling attribute (factors 1/2/4/8). Default 1 is a true bypass, bit-identical to before. Factor >1 runs the reverb cores at host_sr × factor with an anti-imaging upsample and a 4-stage one-pole anti-aliasing downsample.

    ⚠️ Deviation: the legacy downsample ran the core at a lower rate with no antialiasing; this is inverted to genuine antialiased oversampling (cleaner feedback) per the roadmap. Documented in-file; default sound unchanged.

  • tap.sustain~ — multi-voice + rise. Graduates from EXPERIMENTAL single-voice to a 5-voice round-robin/oldest-first bank (voices attr 1–5), each voice with its own capture buffer/loop/fade and a one-shot equal-power rise fade-in. Reference-page digest corrected (was copy-pasted boilerplate).

    ⚠️ Note: the taptools-min archive turned out not to contain the old sustain source, so the polyphony model is a clean, documented reconstruction.

  • tap.filecontainer — ported (was unported). No SQLite vendoring needed: like the original it drives Max's built-in sqlite object via the C API (object_new_typed(CLASS_NOBOX, "sqlite", …) + execstring). Schemas, BLOB import/export, and all messages reproduced; temp-folder + file-moddate handling reimplemented on std::filesystem (moddate restore is best-effort). Docs/help restored from legacy.
  • tap.filter~ — new unified multimode filter. Transposed-Direct-Form-II biquad on the RBJ Audio EQ Cookbook coefficients (same set as tap.biquadcalc); mode is an attribute<symbol> (GCC-clean, not enum class) selecting lowpass/highpass/bandpass(×2)/notch/allpass/peaking/low-+high-shelf; signal- or float-driven frequency, plus q/gain; per-vector coefficient recompute with per-sample smoothing to avoid zipper noise. New maxref + unit test (16 assertions vs. analytic RBJ references).

Unit tests

Added for tap.verb~ (1× bypass is bit-identical, resampler stays finite), tap.filter~ (coefficients vs. analytic refs, DC/HF response, mode switch), tap.sustain~ (multi-voice engagement + rise). Suite 21 → 24 green. tap.filecontainer is runtime-only (its DB needs a live Max).

Runtime test harness (closes the "validate in Max" gap)

  • Vendored Cycling '74's max-test (MIT) as a submodule under runtime-tests/, plus max-test-config.json, a make_maxtest.py patcher generator, two starter *.maxtest.maxpat examples (tap.prime control-rate, tap.radians~ audio-rate), and a README.md.
  • Unlike the Catch tests (mock kernel), these load the real objects in Max and assert on actual audio behavior via test.assert/test.sample~/test.terminate, automatable over OSC with the bundled Ruby runner.
  • Licensing: a paid Max license is not required to run patchers (the standalone "Max Runtime" was dropped in Max 7; unlicensed Max runs them indefinitely, only saving is disabled). It needs a Max install, so it stays a local on-Mac gate for now; CI is feasible later on a self-hosted macOS runner (gated by Max's GUI/activation, not licensing).

Needs you, on a Mac (not blocking this PR)

  1. Open the two example .maxtest.maxpat patchers in Max once to confirm the assert/terminate wiring (they were generated headless), then use them as the template for the rest.
  2. Audition the new DSP — verb oversampling, sustain feel, filter sweeps, and the tap.filecontainer round-trip (especially the best-effort moddate restore).

Verification

  • All four polish externals compile; full Catch suite 24/24 green.
  • CLAUDE.md / REVIVAL.md updated (polish items done, runtime-test harness, licensing note).

🤖 Generated with Claude Code

https://claude.ai/code/session_012rTpfSz5htDrscQKG9uQib


Generated by Claude Code

claude added 4 commits June 18, 2026 10:14
Completes the REVIVAL.md polish items and stands up a runtime (in-Max)
test harness. Full Catch suite now 24/24 green; all four new/changed
externals compile.

Polish items:
- tap.verb~: added the deferred internal oversampling stage. New
  `oversampling` attribute (1/2/4/8, default 1 = true bypass, bit-identical
  to before). Factor >1 runs the reverb cores at host_sr*factor with an
  anti-imaging upsample and a 4-stage one-pole anti-aliasing downsample.
  Deviation: the legacy `downsample` ran the core at a LOWER rate with no
  antialiasing; inverted here to genuine oversampling per the roadmap
  (documented in-file). Default sound unchanged.
- tap.sustain~: graduated from EXPERIMENTAL single-voice to a 5-voice
  round-robin/oldest-first bank (`voices` attr 1-5) with per-voice
  equal-power `rise` fade-in. Reference page digest corrected (was
  copy-pasted boilerplate). DSP feel still wants a Max audition.
- tap.filecontainer: ported (was unported). No SQLite vendoring needed -
  like the original it drives Max's built-in `sqlite` object via the C API
  (object_new_typed CLASS_NOBOX + execstring). Schemas, BLOB import/export,
  all messages reproduced; temp-folder + moddate on std::filesystem
  (moddate restore best-effort). Docs/help restored from legacy.
- tap.filter~: new unified multimode filter. TDF-II biquad on the RBJ
  cookbook coefficients (same set as tap.biquadcalc); `mode`
  attribute<symbol> (GCC-clean) selecting lowpass/highpass/bandpass(x2)/
  notch/allpass/peaking/low+high-shelf; signal- or float-driven frequency;
  q/gain; per-vector recompute with per-sample smoothing. New maxref + test.

Unit tests: added for verb~ (oversampling bypass bit-identical), filter~
(RBJ coefficients vs analytic refs), sustain~ (multi-voice + rise). Suite
21 -> 24 green.

Runtime test harness (new): Cycling '74 max-test vendored as a submodule
under runtime-tests/, with max-test-config.json, a make_maxtest.py patcher
generator, two starter *.maxtest.maxpat examples (tap.prime control-rate,
tap.radians~ audio-rate), and a README. This is the path to closing the
"runtime validation in Max" gap (the Catch tests use a mock kernel;
max-test loads real objects in Max). Needs a licensed Max install, so it's
a local on-Mac gate, not CI. CLAUDE.md/REVIVAL.md updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rTpfSz5htDrscQKG9uQib
The standalone "Max Runtime" was discontinued in Max 7; since then
unlicensed Max runs (and edits) patchers indefinitely, with only saving
disabled after the 30-day demo. The max-test runner only runs patchers, so
no paid license is needed. Reframe the README + REVIVAL.md CI notes: a Max
*install* is required (unlicensed is fine to run), and CI is feasible on a
self-hosted macOS runner gated by Max's GUI/activation rather than by
licensing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rTpfSz5htDrscQKG9uQib
Audited the roadmap against the actual repo state. Several entries still
read as "to-do" for work that's since shipped — corrected so the doc no
longer undersells progress:
- §3: tap.sustain~/vocoder~/spectra~/nr~ marked done (were "revive? yes").
- §5: tap.filter~ "open thread" resolved (it's built); fourpole~/filter~
  repatriation row updated.
- §7: tap.verb~ "not yet included limiter/oversampling" note reconciled
  (both done); tap.delay maxref-trim note marked done (batch 2).
- §2: added a status banner (all of §2 is ported; filecontainer uses Max's
  native sqlite, not the pruned ttblue); fourpole~ "will re-cut" -> done.
- Header date -> 2026-06-18.

Added §9 "Remaining open items" consolidating everything genuinely still
open: runtime validation in Max (incl. verifying the example max-test
patchers), missing/provisional help patchers (sustain~, filter~, the
spectral trio), the still-open resurrection candidates, tap.colorspace
repatriation, the GCC-clean pass, the buffer.record~ optimization, and
release engineering.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rTpfSz5htDrscQKG9uQib
…ared bpatchers

Two of §9's open items: the help patchers and the GCC-clean pass.

GCC-clean pass (the whole tree now builds under Linux/GCC):
- tap.crossfade~ / tap.pan~ stored shape/mode as attribute<enum class>,
  which GCC rejects (min-api's atom::operator== has no enum overload; clang
  accepts a templated conversion GCC won't). Switched to attribute<int> with
  named index constants — the help-patcher umenu-index path is preserved
  exactly. Also renamed the `number` message member (was shadowing the
  `number` type -> -Wchanges-meaning). Both now compile under GCC.
- Added unit tests for both (testable for the first time): they guard the
  curve selection — equal-power cos/sin, linear, and pan's square-root —
  confirming the int-attribute refactor preserves behavior.

Help patchers:
- New help/tap.filter~.maxhelp and help/tap.sustain~.maxhelp, authored from
  the maxref + existing templates, with controls whose attribute/message
  names match the sources (filter: mode/frequency/q/gain/clear; sustain:
  voices/rise/fade/length/clear + bang capture). Valid JSON, patchline
  integrity checked. Authored headless — want a first open-in-Max check.

Restored shared help assets (pre-existing prune gap): the help patchers
reference shared bpatchers that were dropped when the package was pruned.
Restored from legacy:
- help/tap.badge.maxpat (referenced by 50+ help patchers)
- help/tap.jit.ali.kernel-assist.maxpat
Still missing: tap.help.dac~.maxpat (9 refs, no recoverable source — noted
in REVIVAL.md §9). demosound.maxpat is a stock Max abstraction.

REVIVAL.md §9 updated (help patchers + GCC pass marked done; shared-asset
gap documented).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rTpfSz5htDrscQKG9uQib
@tap tap force-pushed the claude/revival-md-planning-y0vjdj branch from 2f5711c to ece5785 Compare June 18, 2026 11:10
The 9 help patchers that reference tap.help.dac~.maxpat had a broken
bpatcher (the asset was dropped in the prune). The repo history only
preserved an older gain~/meter~ pass-through form — not the live.meter~/
dac~ version, so this is rebuilt to spec on the same 2-in/2-out interface
the host patchers expect:
- 2 signal inlets (L/R) and 2 pass-through outlets
- a horizontal stereo live.meter~ (one per channel)
- a local dac~ with a toggle for per-patcher audio on/off
- text labels

Valid JSON, patchline-integrity checked (0 dangling). All TapTools shared
bpatchers now resolve (demosound.maxpat is a stock Max abstraction). Wants
an open-in-Max verification. REVIVAL.md §9 updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rTpfSz5htDrscQKG9uQib
@tap tap merged commit 1063395 into main Jun 19, 2026
4 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