Recipes (book Part IX) + the tap.harmony~ kernel - #27
Merged
Conversation
A third kind of chapter for Tools on Tap: Parts I–VII say what each object is for, Part VIII says why to trust it, and a recipe puts several objects on one patch cord and chases a specific sound. The part opener states the rules (every knob spelled as the attribute is spelled; settings are starting points while measurements stay citations; provenance honest; ingredients ranked). Two recipes ship with the part: - "One machine, four decades" — four TR-808 kits off one phasor~/tap.808.seq~ scaffold: Planet Rock electro, Sexual Healing slow soul, Miami bass (the tuned long-decay kick as bassline), and trap with polymeter hat-roll rows. - "Three oscillators into a ladder" — the oscillator chapter's Moog recipe completed into a playable voice: stack, ladder, two tap.adsr~ contours, gate/pitch plumbing, and bass + lead settings tables. Every attribute and message was drafted against the TapTools-Max wrapper sources rather than from memory — which is what caught the snare's absent decay knob, the clap's tail spelling, the sequencer's hits/accents/velocities/step surface, the ladder's numeric mode index, and tap.adsr~'s level-gate contract. PLAN-recipes.md is the drafting record and carries the backlog (acid line, robot voice, shimmer, envelope filter, IR field guide, comb tunings). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
"The patches with names on them" drives the previous recipe's three-oscillator voice at four records, each as a settings delta from its bass/lead tables: Steve Winwood's "While You See a Chance" hook, Bernie Worrell's stacked-Minimoog "Flash Light" bass, Rick Wright's "Shine On You Crazy Diamond" lead, and Keith Emerson's one-take "Lucky Man" modular solo. Gear provenance is stated per patch — documented history versus reconstruction — per the part opener's rules. The Lucky Man section carries the answer to whether the kit needs a Moog modular object: no, because a modular is routing freedom and Max is the patch panel — the modules already ship, and the wiring the solo needs is the previous chapter's diagram. The genuinely modular idiom (the sequenced line: tap.303.seq~ -> mtof~ -> the stack) is sketched once and added to the plan-file backlog as its own future recipe. Shared performance plumbing is stated once: constant-cents vibrato via the Hz-calibrated FM inlet (depth ~ 0.006 x f for +/-10 cents), and the sequencer pair driving the voice through mtof~ with adsr's level-gate contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
The second wave, each drafted against a fresh wrapper-source sweep: the acid line (the Phuture knob-riding method, lane messages, the measured accent-run bloom), the sequenced modular (Berlin school and "I Feel Love" off tap.303.seq~ through mtof~ into the Moog voice), the robot voice (carrier casting with the noise layer as sibilance budget), shimmer (the full spiral-into-wash chain with variants), the funk envelope filter (clav chop, bass quack, cocked wah, and the sidechain/ envelope-outlet patch points), a field guide to rooms (IR curation and placement for tap.convolve~), and comb drones (five keepable tunings and the morph gesture). The drafting audit also caught and fixed a shipped-chapter drift: the pitchaccum chapter documented pitch1/feedback1 with 0..1 feedback values, but the wrapper spells them trans1/fb1 on a 0-99 scale; the rooms recipe documents the buffer~-plus-set loading contract explicitly. New findings (uninterpolated tap.delay~/tap.multitap~, tap.verb~'s std::rand() nondeterminism, the vco signal-inlet glide gap, the missing vocoder sibilance path) are recorded in TapTools-Max's plans/recipes-improvements.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
Four studies in casting, with provenance labeled per the part's rule: "In the Air Tonight" as the anti-robot patch (the VP-330 ghost choir — wide bands, slow mouth, no noise layer, mixed under the dry whisper), the front-and-center robots (ELO, Styx, the Beastie Boys, Kraftwerk's monophony) with the talkbox distinction kept straight, "Hide and Seek" honestly labeled a harmonizer rather than a vocoder — with the closer route built from parallel tap.shift~ voices fed by tap.semitone2ratio, capped at close voicings because granular shifting moves formants — and a plugin-era "Orange-school" carrier voiced from the package's own oscillators, with the house rule against reverse-engineering shipping products stated in print. Plan record updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
…d dry taptools/harmonizer.h (tap::tools::harmony::harmonizer) is the keyboard-harmonizer effect — up to four pitch-shifted copies of a monophonic source holding musical intervals, summed with a dry path the kernel delays to the voices' emission time so chords land as chords rather than slapback. Each voice is a tap::dsp::pvoc (Laroche-Dolson peak-locked shifting) with LPC formant preservation on by default; both algorithms live in DspTap and come from published literature, so this kernel is composition and control. Intervals are fractional semitones clamped to +/-24 (exactly the pvoc ratio contract) gliding through a semitone-domain one-pole; gains ride their own slews; silent voices are skipped for CPU and re-enter cold by design, stated in the header with the other honest limits (one-frame latency, pvoc transient smearing, voice-oriented formant model). Seven Catch2 scenarios pin the contract, house-style: solo voices land their intervals under the DspTap yin oracle (both directions), the dry path is sample-aligned with a unity voice to 1e-6, chords stay bounded with both intervals present, a synthetic formant bump stays home only with the flag on, glide walks the pitch through the middle, and a re-enabled voice returns finite and audible. The C ABI and ctypes bridge gain the kernel (taptools_harmonizer_*, Harmonizer with a chord() helper) per the verification-layer rule; README's pitch table gains the row. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
The chapter the audit demanded: tap.harmony~ documented as an instrument (corrector into harmonizer, formant as the point, chord as the performance surface, glide as the inhuman slide), with the honest latency number and the kernel test battery cited for every claim. Two worked examples carry it: "Woods" as the stacked chapel — with the overdub-honesty note that one harmonizer pass is one performance, and takes are the faithful version — and "715 - CRZZKS" as the Messina-school live stack (dry voice equal citizen inside the chord, the octave-down under falsetto, no reverb this once). The vocoder songbook's Hide and Seek section now ranks tap.harmony~ as the right tool, keeping the shifter stack as the manual fallback; SUMMARY and the plan record grow to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
Formatting only — the style job caught the harmonizer header, test, and capi include block; no behavior change, suite still green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
notebooks/harmonizer.ipynb drives the shipping kernel through the capi bridge, house-style: solo voices across two octaves of voicings land within 0.04 cents of their equal-tempered targets under the DspTap yin oracle; the dry path aligns with a unity voice to a 3.7e-8 residual (why chords land as chords, not flams); the formant section shifts a synthetic 960 Hz-bump voice up a fifth and quantifies the preservation honestly with a band centroid (1058 -> 1154 Hz with the flag on, 1439 riding the full ratio with it off); and the last section plots the "715"-school chord spectrum and the 300 ms glide walking unison to octave. The book's choir-of-one recipe now cites the notebook's numbers instead of leaning on the tests alone, and the plan record marks the notebook shipped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
build, Tap House Style, and Docs workflow badges under the title, each linking to its workflow's run history. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
The pitchaccum, vocoder, and tune chapters' wrong-tool lists predate the harmonizer and recommended workarounds for exactly what it now does; each names the object. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
taptools/adsr.h (tap::tools::adsr::generator) rebuilds the envelope as a circuit model, per the recipes-improvements plan: the default analog mode charges its attack toward a 1.4x overshoot target and truncates at full scale (the CEM 3310 architecture from the datasheet; standard Electronotes ADSR practice), and its decay/release are true RC discharges that taper into their targets. Contract numbers documented and pinned: attack reaches full scale at the knob time with the truncated-charge midpoint at 0.652; decay/release close 95 percent of their gap at the knob time (tau = t/3); release ends at exact zero below 1e-6. Retrigger always rises from the current level. The 2003 Jamoma TTAdsr curves are ported verbatim as hybrid/linear/exponential compatibility modes, magic constants and all. The family trigger contract lands at last: the gate opens above a threshold (default 0.005 - above the trigger bus's 1e-3 floor, below the sequencer's 0.01 plain level, retiring the old hard-coded 0.5 that a default accented row could never open), and gate amplitude is velocity under a sensitivity control (1 + s*(amp - 1), so 303-style 2.0 accents hit twice as hard at full sensitivity; s = 0 is the legacy amplitude-blind behavior). Eight Catch2 scenarios pin all of the above, including the legacy hybrid curve's linear attack and dB-linear decay. The C ABI, ctypes bridge (Adsr class), and the executed notebooks/adsr.ipynb ship alongside per the verification-layer rule - the notebook measures 99.8 ms to full scale on the 100 ms knob, midpoint 0.652 on the law's 0.652, 95.0 percent decay closure, and the plain-hit threshold test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
The gate contract sentence now speaks threshold rather than the retired 0.5 level, the Moog voice notes the analog default gives its contours real RC curves, and the sequenced-modular chapter's accent caveat becomes an accent feature via the new velocity sensitivity. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
tap
pushed a commit
to tap/TapTools-Max
that referenced
this pull request
Aug 5, 2026
tap/TapTools#27 landed on main by rebase; main's head d878622 carries the identical tree to the branch commit this pin referenced, so the pin moves there per the release flow and stays reachable after branch cleanup. No content change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
tap
pushed a commit
to tap/TapTools-Max
that referenced
this pull request
Aug 5, 2026
tap/TapTools#27 landed on main by rebase; main's head d878622 carries the identical tree to the branch commit this pin referenced, so the pin moves there per the release flow and stays reachable after branch cleanup. No content change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
tap
pushed a commit
to tap/TapTools-Max
that referenced
this pull request
Aug 5, 2026
tap/TapTools#27 landed on main by rebase; main's head d878622 carries the identical tree to the branch commit this pin referenced, so the pin moves there per the release flow and stays reachable after branch cleanup. No content change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
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
Adds Part IX — Recipes — to Tools on Tap (a part opener plus eleven recipe chapters, from the TR-808-through-four-decades kits to the Bon Iver harmonizer patches), and ships the harmonizer kernel the drafting audit demanded:
taptools/harmonizer.h(tap::tools::harmony), its Catch2 battery, capi + ctypes-bridge exposure, and the executednotebooks/harmonizer.ipynb. Also: CI badges on the README, and small shipped-chapter corrections the audit caught.Why
The book needed a third kind of chapter — whole patches chasing named sounds — and drafting them against the wrapper sources doubled as an audit of the object offerings. That audit's findings live in TapTools-Max's
plans/recipes-improvements.md; its first shipped consequence is here: the "Hide and Seek" mechanism (a formant-corrected multi-voice harmonizer) had no object, and the DspTap pvoc substrate already carried everything needed. The audit also caught real drift in shipped chapters (the pitchaccum chapter documentedpitch1/feedback1; the wrapper spells themtrans1/fb1on a 0–99 scale), fixed here.Verification
tests/harmonizer_test.cpp, oracle-based (DspTap yin) — full suite green locally and in CI, clang-format/clang-tidy clean.notebooks/harmonizer.ipynbis committed executed — max interval error 0.04 cents across two octaves of voicings; dry-path alignment residual 3.7×10⁻⁸; formant band-centroid 1058 → 1154 Hz on a +7 shift with the flag on versus 1439 Hz riding the full ratio with it off. The choir-of-one chapter cites these cells.create-missing = false, so every SUMMARY entry exists).Notes for the reviewer
harmonizer.ipynbis new and committed executed.tap.harmony~wrapper (pin pointed at this branch), the recipes-improvements plan, and the package README. After this merges by rebase/squash, repoint that pin at the identical tree onmain.🤖 Generated with Claude Code
https://claude.ai/code/session_01V6CC6kpK5Lx2YkJWuNNQpw
Generated by Claude Code