Skip to content

Add the Eno family: tap.discreet~, tap.airport~, tap.garden~ - #30

Merged
tap merged 9 commits into
mainfrom
claude/brian-eno-inspired-f6pqk2
Aug 12, 2026
Merged

Add the Eno family: tap.discreet~, tap.airport~, tap.garden~#30
tap merged 9 commits into
mainfrom
claude/brian-eno-inspired-f6pqk2

Conversation

@tap

@tap tap commented Aug 12, 2026

Copy link
Copy Markdown
Owner

What this changes

Adds a new kernel family recreating three Brian Eno systems — the Discreet Music two-machine tape loop (discreet.h / tap.discreet~), the Music for Airports incommensurate loop bank (airport.h / tap.airport~), and a generative event loop on the Bloom principle (garden.h / tap.garden~) — plus shared tape machinery (tape_loop.h), the full verification stack for each (Catch2 scenarios, C ABI, ctypes bridge, executed notebooks), an eno_render listening tool, and a new Tools on Tap part ("Tape and time": three user chapters, three machine appendices, block diagrams, measured figures).

Why

The library's families so far recreate instruments and effects; this one recreates systems, and it exists to state a design inversion the house has not had before: every prior regenerating loop is stabilized by a feedback cap (delay.h's k_fb_max = 0.99), while these kernels let regeneration reach exactly 1.0 and stay bounded because each pass is degraded — darkened and saturated on the tape, decayed and softened in the garden. Wear is the stabilizer. The three works are the same idea at three abstraction levels (audio → loops → events), which the book part uses as its through-line.

Provenance per house IP policy: the Discreet Music back-cover schematic + the AES tape-echo literature (Arnardóttir/Abel/Smith 2008, Välimäki et al.); Eno's published accounts of "2/1"; the Bloom principle from published interviews and Eno's 1996 generative-music talk (no app tables, timings, or sounds — "Bloom" is a live Opal Ltd trademark, hence the neutral object name; bell synthesis cites Chowning 1973).

Verification

  • 24 promise-named scenarios across discreet_test.cpp, airport_test.cpp, garden_test.cpp; full suite green locally on Linux/GCC Release. Highlights: regen-1.0 two-window RMS non-growth over 10 s; per-pass generation loss measured against the analytic wear transfer (0.292 at 6 kHz, 0.890 at 300 Hz — both matching prediction to three decimals); wow depth by the YIN oracle at 10.9 cents vs the 10.9-cent closed form; bit-exact loop freeze and lcm realignment (24000/30000 samples → exactly 2.5 s) in airport; the decay-0.5 return staircase (0.795/0.399/0.2/0.1/0.05 → retirement) and the full seeded triad in garden.
  • Executed notebooks discreet.ipynb, airport.ipynb, garden.ipynb drive the shipping C++ through the C ABI; committed executed. Audio previews are embedded decimated (16 kHz) to keep notebook sizes near house norms; full-rate listening copies come from eno_render (all five scenario WAVs verified non-silent and unclipped).
  • mdbook 0.4.40 (the CI pin) builds the book clean with the new part; create-missing = false satisfied.
  • The gap: macOS/Windows legs of the matrix and clang-tidy (which runs in the Max repo) are first exercised by CI on this PR. Windows long width is handled (heads wrap explicitly), but LLP64 is untested locally.

Notes for the reviewer

  • Max/Pd package. The wrappers, reference pages, and help patchers for the three new objects are not in this PR — they land in TapTools-Max as the follow-up, which will also bump its submodules/taptools pin. After this merges by rebase/squash, the consumer pin should point at the identical tree on main.
  • Notebooks re-executedtaptools_py.py gained Discreet, Airport, Garden classes; the three new notebooks are committed executed.
  • New precedent, flagged: garden.h is the library's first randomized event source (seeded tr808::white_noise, the established seed-triad contract); step_seq.h's "no randomness anywhere" promise is untouched, and the contrast is documented in both headers' banners.
  • Memory honesty: airport.h's worst case (8 × 30 s reels ≈ 92 MB double @ 48 kHz) is stated in its banner; prepare(sr, max_loop_seconds) sizes it down freely.

🤖 Generated with Claude Code

https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR


Generated by Claude Code

claude added 9 commits August 12, 2026 01:18
tape_loop.h (tap::tools::tape) factors the pieces both Eno-family tape
kernels compose, the way swing_vca.h holds the drum family's shared
stages: reel (position-addressed circular tape, Hermite reads wrapped at
a settable loop length), wow_flutter (deterministic dual-sine transport
per the AES tape-echo literature), wear (darkening one-pole -> bounded
swing_shape saturation -> normalized DC blocker), and the delay.h ramp.

discreet.h (tap.discreet~) recreates the two-machine long-delay rig from
the Discreet Music back-cover schematic. The design inversion the kernel
exists to state: regeneration legally reaches 1.0, and stability comes
from the wear path, not a feedback cap — with drive engaged the loop is
BIBO-bounded at any regen, and at drive 0 the sub-cutoff band sustains
indefinitely (the Frippertronics contract). Loop-time changes ride the
ramp as honest tape-speed doppler.

Tests pin the promises: echo grid to the sample, regen-1.0 non-growth
over ten seconds, per-pass darkening measured against the analytic wear
transfer, DC non-accumulation, wow depth measured by the YIN oracle
against the closed-form deviation, bitwise mix endpoints, doppler glide
re-lock, and bit-exact reproducibility.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
C ABI section, ctypes bridge class (Discreet), and the executed
discreet.ipynb: the echo grid to the sample, twenty seconds of bounded
regen-1.0 sustain, per-pass generation loss measured against the
analytic wear transfer (0.292 and 0.890 per pass, both matching the
prediction to three decimals), the wow transport pitch-tracked at 10.9
cents peak against the 10.9-cent closed form, and the fade-the-send
performance move rendered end to end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
airport.h (tap.airport~) recreates the "2/1" tape system from Eno's
published accounts: up to eight free-running loops of unequal lengths,
each a tape_loop.h reel with a single head that both plays and records.
The phase is never reset by any setter — the free-run is the piece — and
a length change is an honest splice that re-wraps without rewinding.
Per-loop level, equal-power pan (exact endpoints, the delay.h multitap
law), and a playback darken corner that bypasses to bit-transparency at
the band ceiling; no per-pass generation loss, because a loop replays
the same magnetic imprint. composite_period_seconds() reports the lcm of
the active lengths, +inf on overflow.

Tests pin the structural promises exactly: bit-exact returns on the loop
grid through a mid-run setter storm, bit-exact freeze at record-off, the
lcm realignment of coprime lengths (and non-realignment at half), hard
pans bitwise absent from the far bus, the darken shade measured against
the analytic one-pole transfer, and the splice law.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
C ABI section, ctypes bridge class (Airport, with per-loop sequence
setters on the Multitap template), and the executed airport.ipynb:
bit-exact returns on the loop grid, the 2.5 s lcm of a 24000/30000
sample pair confirmed by composite_period_seconds and by the rendered
coincidence raster, an airport-scale seven-loop bank whose composite
period overflows to infinity, the per-loop shade measured on the
analytic one-pole transfer (0.169 vs 0.169), and two minutes of
"2/1"-like material rendered and embedded.

Notebook audio previews are embedded decimated (16 kHz) to keep the
executed notebooks near house size; discreet.ipynb re-executed the same
way. Full-rate listening copies come from the render tool.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
garden.h (tap.garden~) is the family's third abstraction level: discreet
recirculates audio, airport phases loops, garden recirculates events. A
planted note snaps to the scale at entry, sounds a two-operator FM bell
(Chowning 1973, ratio 3 — harmonic, so YIN reads the fundamental), and
returns at its loop position every pass, velocity times decay and
brightness times soften, until it retires below the floor. The stability
inversion carries up a level: per-pass decay IS the stabilizer, the
population converges by construction, and a fixed sixteen-bell pool
(quietest-stolen, envelopes re-aimed rather than reset) hard-bounds the
audio. Left idle, a seeded gardener (tr808::white_noise, the house
xorshift64* contract) plants about one scale note per pass. Recreates
the published principle only — no app tables, timings, or sounds; named
for Eno's gardener-not-architect metaphor.

Tests pin the return grid to a sixth of a millisecond, the decay ratio
per return, the strictly-purifying FM sideband, scale membership by the
YIN oracle, the full seeded triad (bit-exact per seed, differing across
seeds, seed-irrelevant with idling off), the idle threshold, oldest-drop
at the 64-event ring, and pool/finiteness bounds under heavy stealing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
C ABI section, ctypes bridge class (Garden), and the executed
garden.ipynb: the decay-0.5 return staircase measured at 0.795, 0.399,
0.2, 0.1, 0.05 and then retirement to zero live events; the softening
FM sideband fading per pass while the fundamental holds; a chromatic
sweep of thirteen plants all landing on the pentatonic by the YIN
oracle; the seed triad demonstrated on two gardeners; and two minutes of
self-tending garden with the population breathing around its converged
size (20 events, 16 bells at the end).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
The Eno kernels are long-timescale systems, so offline rendering is the
only practical audition. Five scenarios to WAV: the two-machine loop at
regen 0.95, the regen-1.0 Frippertronics wash with the send faded at the
halfway mark, three stereo minutes of seven incommensurate airport
loops, four planted garden notes recirculating to silence, and two
minutes of the seeded gardener left alone. Verified non-silent and
unclipped end to end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
book/PLAN-eno-chapters.md: the drafting record for three user-facing
chapters and three machine appendices, per the PLAN-pitch-chapters.md
shape — SUMMARY placement diff, per-chapter outlines with every numbered
item carrying its evidence (notebook section or pinned test scenario),
figure list, and drafting notes. Status: planned; flips to drafted when
the chapters land.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
A new Part IV for the Eno family — "The tape that forgets slowly",
"Loops that never line up", "The garden that plays itself" — plus three
machine appendices (tape_loop.h/discreet.h, airport.h, garden.h) closing
Part IX, with later parts renumbered. Hand-authored block diagrams in
the house style for all three objects, measured figures generated by
book/figures/eno.py against the shipping kernels (generation loss on the
analytic wear transfer, the incommensurate-loop raster with its 2.5 s
lcm, the decay staircase), and the PLAN flipped to drafted.

The part's through-line is the family thesis: three works, one idea at
three abstraction levels, and in all three degradation is the stability
mechanism. Every number in the chapters cites its executed notebook cell
or pinned test scenario; mdbook 0.4.40 (the CI pin) builds clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
@tap
tap merged commit 9d63666 into main Aug 12, 2026
12 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