vca.h: shared transistor-VCA kernel (warm + swing), with 808 calibration notebook#17
Merged
Conversation
Lift the TB-303's one-transistor class-A VCA stage out of tb303_voice.h into a standalone taptools::vca kernel so tap.303~ and the new standalone tap.vca~ run one implementation. - vca.h: the two-circuit svf.h idiom applied to a gain stage. clean is the pure linear multiply (bit-identical to *~); warm is the slope-normalized biased saturator S(v) = (tanh(d*v+b) - tanh(b)) / (d*sech^2(b)) applied to the post-gain signal, so the even-harmonic warmth and compression track the control voltage. drive/bias exposed (stock d=2.0, b=0.3); optional output-coupling DC block for the shaper's signal-dependent offset. - tb303_voice.h now composes vca::shape() with the stock constants and keeps its own Open303 output high-pass + gain, so the voice is bit-identical. - tests/vca_test.cpp: pins the two-circuit contract and the bit-identity of shape() against the old inline formula, and re-runs the 303 warm-vs-clean path through the shared stage. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS
…ices The swing-type VCA's "many high harmonics" (Service Notes, RS/CL VCA), which swing_vca() had modeled as a flat x*env. The first and lowest-risk piece of the flagged 808 circuit-sim work. - vca.h gains mode_swing: a symmetric (odd-harmonic) tanh(d*v)/d saturator, unity-slope-at-0 so quiet tails stay clean and hot transients pick up grit and compression, no DC (symmetric needs no coupling block). One implementation: a static vca::swing_shape(v, drive) that both mode_swing and swing_vca(x, env, drive) route through. - drive defaults to 0 -> the exact linear passthru, so every calibrated 808 voice is bit-identical until it opts in. The full tr808_* suite passes unchanged; the snare test adds an explicit off-is-bit-identical / on-saturates-and-compresses scenario. - Wired into the three noise-path voices: snare (snappy), clap (CP + maracas), tom (noise reverberation), each with a set_drive circuit-bend. The heavier WDF @circuit pass (kick bridged-T etc.) stays A/B-gated per the field guide. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS
Adds tr808_swing_vca.ipynb — the calibration check for the 808 swing-VCA drive against Fischer's free Technopolis reference set, alongside tr808_calibration. Finding: the crest-factor (the direct measure of the swing VCA's compression) shows our linear model already sits at or above the real 808's transient sharpness on snare/clap/tom — the hardware isn't compressing these hits more than we already do (consistent with the DAFx-14 "device nonlinearity matters less than folklore" result). Drive only compresses past the reference, so it stays a creative bend, not a fidelity default (the default is 0, so no code change follows). The tonal voices the Service Notes actually cite (rim/claves, cowbell) are where a symmetric shaper would earn its keep — a separate test. Also teaches tr808_render the `drive` knob (--set drive N) on snare/clap/tom so the notebook can render the swing variants. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS
Runs the same real-808 comparison on the voices the Service Notes actually cite for the swing VCA's harmonics, and wires the tonal paths so it can. Finding: - Rimshot: swing is clearly warranted — spectral distance to the real RS falls 1.36 -> 0.47 monotonically with drive. It already shipped saturated (k_rs_drive = 2.2); this validates that constant. - Claves: the real CL is a near-pure ~2.5 kHz tone (HF ratio ~0); a symmetric shaper only adds harmonics it doesn't have -> keep linear. - Cowbell: distance to the real CB is large and flat across drive -> the mismatch is oscillator tuning/mix, not the VCA -> keep linear. So the swing VCA is a fidelity feature only where it was already applied (the rimshot); everywhere else linear stays the default. The durable win is unification: the rimshot's inline tanh(ring*k_rs_drive*env)/k_rs_drive is now swing_vca(ring, env, k_rs_drive) on the shared vca.h shaper (bit-identical — the rim/cowbell kernel tests pass unchanged). - tr808_rim.h: rimshot unified onto swing_vca; claves gains an opt-in drive (sentinel <0 = per-model calibrated: RS 2.2 / CL linear). - tr808_cowbell.h: opt-in drive on the osc pair (0 = linear, default). - tr808_render: `--set drive` on rimshot/claves/cowbell for the sweep. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS
Layout-only: satisfies the CI clang-format-18 check over the files touched by this branch (vca.h, tb303_voice.h, tr808_tom.h, tests, the render tool). No behavior change — the full kernel suite still passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS
tap
pushed a commit
to tap/TapTools-Max
that referenced
this pull request
Jul 19, 2026
tap/TapTools#17 merged (rebase), rewriting the feature commits onto main with new SHAs — so the previous pin (8e02ac5, a feature-branch commit) is no longer on kernel main. Re-point submodules/taptools at the merged main tip, which carries the identical swing-VCA kernel. No change to the built externals. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS
tap
added a commit
to tap/TapTools-Max
that referenced
this pull request
Jul 19, 2026
…e 808 noise voices (#53) * tap.vca~: standalone VCA — clean multiply or 303 warm transistor stage A new MSP external wrapping the extracted taptools::vca kernel (submodule pin bumped to 253d550). The left inlet is audio; the right inlet is the gain / control voltage (signal for per-sample modulation, or a float). - circuit clean (default): pure linear multiply, bit-identical to *~. - circuit warm: the TB-303 one-transistor class-A stage — the same kernel tap.303~ runs — biased-tanh saturation applied after the gain, so the even-harmonic warmth and compression track the control voltage, with an output DC block (dcblock) that sheds the shaper's signal-dependent offset. - drive/bias shape the warm circuit (stock at the 303's 2.0 / 0.3). Full vertical slice: wrapper + CMake + wrapper test (attribute defaults, forwarding, clamping) + maxref + help patcher. REVIVAL.md §7 and the 303/808 plans note the extraction; when the flagged 808 circuit-sim phase models the swing VCA's harmonics, that character lands here as a third circuit mode. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS * 808 swing-VCA harmonics: drive on the noise voices, swing circuit on tap.vca~ Bumps the kernel pin to 1b3c284 (vca.h mode_swing + swing_vca drive). - tap.808.snare~/clap~/tom~ gain a `drive` circuit-bend attribute (0..12, default 0 = the calibrated linear model, bit-identical). Raised, it engages the swing VCA's symmetric harmonic saturation on the noise path — grit and compression that ride the envelope. Wrapper tests + maxrefs updated. - tap.vca~ gains `circuit swing` (the TR-808 swing-type VCA, the same stage), alongside clean/warm; `drive` now documented for both warm and swing. REVIVAL.md §7 and plans/tap.808.md record the swing mode landing; the heavier WDF @circuit pass stays A/B-gated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS * Bump kernel pin to the swing-VCA feature tip (8e02ac5) Pulls in the bit-identical rimshot unification (its inline swing-VCA tanh is now the shared vca.h swing_shape) and the calibration notebook / render-tool drive knobs. No change to the built externals' behavior; keeps the Max package built against the complete feature kernel. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS * style: clang-format + mandatory braces on the swing-VCA wrappers Satisfies the Tap House CI style gate: - clang-format-18 over the touched source/projects/*.cpp (tap.vca~ + the tap.808.{snare,clap,tom}~ drive attributes) — layout only. - braces around the tap.vca~ circuit setter's if/else-if (readability-braces-around-statements). No behavior change; the affected wrapper tests still pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS * Re-point kernel pin to the merged main tip (76dc616) tap/TapTools#17 merged (rebase), rewriting the feature commits onto main with new SHAs — so the previous pin (8e02ac5, a feature-branch commit) is no longer on kernel main. Re-point submodules/taptools at the merged main tip, which carries the identical swing-VCA kernel. No change to the built externals. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS --------- Co-authored-by: Claude <noreply@anthropic.com>
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 is
Extracts the TB-303's transistor VCA into a standalone, shared
vca.hkernel, adds the TR-808 swing-type VCA as a second nonlinear circuit, and lands a calibration notebook that measures both against a real 808 to decide where they're a fidelity win vs. a creative bend. Companion to the Max-side PRtap/TapTools-Max(which pins this kernel and shipstap.vca~).Kernel changes
vca.h(new) —taptools::vca, thesvf.htwo-circuit idiom applied to a gain stage:clean— pure linear multiply, bit-identical to*~.warm— the 303 one-transistor class-A stage:S(v) = (tanh(d·v+b) − tanh(b)) / (d·sech²(b))(stockd=2.0,b=0.3), applied post-gain so the even-harmonic warmth + compression track the control voltage; optional output DC block.swing— the TR-808 swing-type VCA: symmetric (odd-harmonic)tanh(d·v)/d, no DC. A staticswing_shape(v, drive)is the one implementation shared bymode_swingandswing_vca().tb303_voice.h— now composesvca::shape()instead of an inline saturator. The voice keeps its own Open303 output high-pass + gain, so it's bit-identical (pinned bytests/vca_test.cpp, which matchesshape()to the old inline formula and re-runs the warm-vs-clean scenarios).swing_vca.h— the 808 noise-voice VCA gains an opt-indrive(default 0 → exactx·envpassthru), delegating to the sharedswing_shape. Wired intotr808_snare/clap/tom(snappy / CP+maracas / noise-reverb paths).tr808_rim.h— the rimshot's inlinetanh(ring·k_rs_drive·env)/k_rs_driveis unified ontoswing_vca(ring, env, k_rs_drive)(bit-identical); claves gains an opt-in drive.tr808_cowbell.h— opt-in drive on the oscillator pair (default 0).tools/render/tr808_render.cpp—--set driveon snare/clap/tom/rimshot/claves/cowbell for the calibration sweep.Default is 0 / linear everywhere — every calibrated 808 voice stays bit-identical until it opts in. The full
tr808_*+tb303suites pass unchanged;tests/vca_test.cppadds the two-circuit + swing contract and the snare test adds an off-is-bit-identical / on-saturates scenario.The calibration finding (
notebooks/tr808_swing_vca.ipynb)Three-way A/B (real 808 = Fischer's free Technopolis set / our linear / our swing) for the noise and tonal voices:
k_rs_drive = 2.2). Claves is a near-pure tone (adding harmonics moves away); cowbell's mismatch is oscillator tuning/mix, not the VCA.Net: the swing VCA is a fidelity feature only where it was already applied (the rimshot). Elsewhere linear stays the default, with
driveretained as an opt-in creative bend. The durable win is one swing-VCA implementation shared acrosstap.303~,tap.vca~, and every 808 voice.Testing
ctestgreen (kernel suite, including all unchangedtr808_*/tb303tests as the bit-identity gate, plus the newvcascenarios). Render tool builds and thedriveknob is exercised by the notebook.🤖 Generated with Claude Code
https://claude.ai/code/session_01GQDkcxQY5w8AV5cJdiHMHS
Generated by Claude Code