The garden grows up: wind-chime voice, materials, scatter, and a stereo rack - #31
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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. Theeno_renderairport 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_onewithout voices missed the point of "2/1" — the loops were sung notes.Verification
ctestgreen: 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.ipynbre-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.metal_bank.hper-index idiom); the gardener's rng is consumed idle-only, exactly as before.mdbook buildclean; the chapter, machine appendix, block diagram, and measured figures are updated.Notes for the reviewer
garden::bed::processis now stereo(out_left, out_right), andtaptools_garden_processtakes(h, outL, outR, n);set_material/set_spreadare 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 plussample_operator<0, 2>and the new attributes after this merges.submodules/taptoolspin at the identical tree onmain.🤖 Generated with Claude Code
https://claude.ai/code/session_016zgrm1MGS1eir4hCfZBJaR
Generated by Claude Code