Skip to content

The garden grows up: wind-chime voice, materials, scatter, and a stereo rack - #31

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

The garden grows up: wind-chime voice, materials, scatter, and a stereo rack#31
tap merged 5 commits into
mainfrom
claude/brian-eno-inspired-f6pqk2

Conversation

@tap

@tap tap commented Aug 14, 2026

Copy link
Copy Markdown
Owner

What this changes

Follow-up wave to #30 (the Eno trilogy), all on the garden and the render tool: garden.h's voice is re-built as a physical wind chime (four bar-mode doublets, hardness coupling, pitch-scaled ring time, a gusting wind gardener), then extended with a material switch (chime tubes vs. tuned bars), fixed per-tube mode scatter, and a stereo rack with per-tube seats. The eno_render airport scenario gains a formant choir, and both READMEs' book link lands here.

Why

Listening. The FM bell read as "synth preset," not instrument — a modal chime with real bar physics (Fletcher & Rossing throughout) makes every strike ring down to its fundamental the way the family's pitch contract already assumed. The follow-ups are all the same move at smaller scales: velocity should dull the strike, small tubes should ring shorter, tails should beat, wind should gust and calm, each tube should be its own slightly-imperfect object hanging in its own place. And airport_two_one without voices missed the point of "2/1" — the loops were sung notes.

Verification

  • ctest green: 17 garden scenarios (nine carried, eight new this wave) including the material re-voicing (2.756f vs 4f by Goertzel), per-tube scatter (probe scan: bounded ±3 cents, repeatable per pitch, differing across pitches), the rack (fixed per-pitch seats; spread 0 makes the busses bitwise identical via the √((1∓p)/2) pan law), tick confinement, tail beats at the computed doublet null, hardness, ring-time scaling, and the wind (clustered at gust 1, never closer than the minimum calm at gust 0, seed 7).
  • garden.ipynb re-executed against the shipping capi: fundamental staircase ratios 0.500 ×4, mode-2/fundamental shrinking by exactly soften 0.6 per pass, measured scatter (+2.75 / −2.25 cents for tubes 69/84) matching the hash computed offline, seat chart per pitch, seed triad true, 30 s stereo listening preview embedded.
  • Seed-triad discipline survives the new randomness-shaped features because there is no new randomness: scatter and seats are a stateless xorshift hash of the pitch (the metal_bank.h per-index idiom); the gardener's rng is consumed idle-only, exactly as before.
  • mdbook build clean; the chapter, machine appendix, block diagram, and measured figures are updated.

Notes for the reviewer

  • Contract change. garden::bed::process is now stereo (out_left, out_right), and taptools_garden_process takes (h, outL, outR, n); set_material / set_spread are new. Nothing had shipped — Add the Eno family: tap.discreet~, tap.airport~, tap.garden~ #30 merged and the only consumer is the open TapTools-Max wrapper PR, which gets the pin bump plus sample_operator<0, 2> and the new attributes after this merges.
  • Notebooks re-executed, because behavior changed. They are committed executed.
  • After this merges by rebase/squash, repoint the TapTools-Max submodules/taptools pin at the identical tree on main.

🤖 Generated with Claude Code

https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR


Generated by Claude Code

claude added 5 commits August 12, 2026 02:56
Tools on Tap is deployed to https://timothy.place/TapTools/ on every
merge; the README now says so where a visitor will look first.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
The "2/1" loops held single sung notes, and the render's three-harmonic
organ tone missed that entirely. The airport scenario now records a
small formant-synthesis choir: each loop holds one sustained "aah" —
an additive 1/k harmonic series shaped by the published five-formant
vowel tables for "a" (tenor and alto rows as tabulated in the Csound
manual's formant appendix, after Klatt), three unison voices detuned a
few cents with independent delayed-onset vibrato, lower pitches tenor
and upper alto. The rendered spectrum carries the vowel profile:
strong F1/F2 body, a distinct presence band near 3 kHz, nothing above
5 kHz. The discreet scenarios keep the plain phrase tone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
The garden's bell was a two-operator FM tone; it is now a small modal
wind chime: three decaying sine modes at the transverse-vibration ratios
of a free-free bar, 1 : 2.756 : 5.404 (Fletcher & Rossing, The Physics
of Musical Instruments — f_n grows as (2n+1)^2), each mode on its own
decay_env, the upper two scaled by per-event brightness and dying
faster, as struck tubes do. Mode levels sum to at most 1 so the pool
bound stays arithmetic; modes above 0.45 sr stay silent rather than
aliasing; the default attack becomes a clapper's strike. The public API
is unchanged (set_bell keeps its attack/decay/brightness triple).

The inharmonicity moves the pitch contract instead of breaking it: the
upper modes clear quickly, so YIN reads each strike in its ring-down —
the scale scenario still lands every off-scale plant on the scale, and
the softening scenario now tracks mode two (2.756f), measured in the
re-executed notebook fading by almost exactly the soften ratio per
return (0.263, 0.158, 0.095, 0.057). Chapters, figure script, block
diagram, ctypes docstring, and the render tool's strike settings updated
to match; full suite green, mdbook builds clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
Five refinements to the garden voice, all from the same published
physics (Fletcher & Rossing), no API growth:
- a 4th bar mode at ratio 8.933 — the tens-of-milliseconds contact tick
  (decay divisors now ~ratio^2: radiation damping grows with frequency);
- every mode is a doublet split a fixed few cents, so tails beat slowly
  instead of decaying like lab sines; a strike on a silent tube starts
  its pairs aligned (fresh initial conditions — and deterministic
  per-return measurements), while audible steals still glide;
- strike hardness couples brightness to velocity: soft strikes are dull;
- upper-mode brightness steepens per mode (b, b^2, b^3), so soften
  strips the tick first;
- ring time scales by sqrt(440/f) per strike: high tubes ring shorter.

And one new parameter, gust (0..1): the gardener is now wind — strikes
arrive on a calm/gust cycle, each gust catching up to five neighboring
tubes within a fraction of a second, calms stretched so the average
stays near one strike per pass. RNG discipline intact (idle-only draws;
the seed-triad's third leg still pinned).

The staircase promise is re-pinned on the fundamental, which tracks
decay exactly (measured 0.500 x4 in the re-executed notebook) — whole-
strike peaks now fade faster because quieter returns are also duller.
Five new scenarios: the confined tick, the beating tail (dips at the
computed null and returns), hard-vs-soft spectral tilt, low-vs-high
ring retention, and gusts-vs-calm strike spacing (with decay 0 so only
the wind is counted). 14 garden scenarios green; full suite green;
chapters, figures, block diagram, capi, ctypes, and the render tool
(gust 0.7 in garden_idle) updated; mdbook clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
The tube is the identity. material (chime | bar) swaps the mode-ratio and
haste tables under every tube — the free-free tube's 1:2.756:5.404:8.933
or the tuned bar's double-octave 1:4:10:20 (Fletcher & Rossing), read at
strike time so live blooms re-voice at their next return. Each pitch's
upper modes sit a fixed few cents off the ideal ratios (±3 cents, the
fundamental stays true) and each tube hangs at a fixed equal-power seat
on a stereo rack (spread, default 0.7; 0 collapses to bitwise-identical
busses via the sqrt pan law). Both draws are a stateless xorshift hash of
the pitch (the metal_bank.h per-index idiom), so the gardener's seeded
rng is never consumed and the seed-triad contract survives. Seats follow
the phase rule: snap on a silent tube, ~10 ms glide through an audible
steal.

bed::process is now stereo (out_left, out_right) — a pre-release API
change carried through capi (taptools_garden_process(h, outL, outR, n),
set_material, set_spread), the ctypes bridge (Garden.process returns
(left, right)), eno_render (stereo garden WAVs), and the book. Three new
pinned scenarios: material re-voicing (2.756f vs 4f), per-tube scatter
(Goertzel probe scan: bounded, repeatable, different per tube), and the
rack (fixed per-pitch seats, spread-0 mono bitwise). garden.ipynb
re-executed with a rack section and a stereo listening preview.

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