# Pink Trombone Parity Packet ## Objective Use Pink Trombone as old-school speech parity pressure, not as a vague mascot for "more vocal knobs." The current AquaSynth tract voice is a tract-shaped voice treatment with Pink Trombone-style controls. Pink Trombone itself is still a moving vocal-tract waveguide. Those are related machines, but not the same machine. This packet exists so the mismatch stays inspectable. ## Reference Source Primary source for this packet: - `chdh/pink-trombone-mod`: MIT TypeScript modularization of Neil Thapen's Pink Trombone, - Pinned local source: `external/pink-trombone-mod` at `359c2d3b42b10280404c1650dc601902112b4c90` - Source files inspected: - `src/Synthesizer.ts` - `src/Glottis.ts` - `src/Tract.ts` - `src/TractShaper.ts` The original interactive/programmatic Pink Trombone lineage is also visible in `zakaton/Pink-Trombone`, but that package is GPL-3.0. Treat it as reference pressure only unless a later license review says otherwise. ## Current Mechanism Pink Trombone's source-readable graph: ```text frequency/tenseness/intensity -> LF-style glottal source plus aspiration noise -> 44-section main tract diameter array -> squared diameters become section areas -> adjacent section areas become reflection coefficients -> right/left traveling-wave delay-line state -> 28-section nasal branch through a velum junction -> lip output + nose output ``` The synthesizer steps the tract twice per output sample. Tract shape changes are not static formants: the shaper slews section diameters toward target diameters, updates reflections at block boundaries, injects turbulence at constrictions, and emits a transient when a closure opens. The 44 oral and 28 nasal counts are Pink Trombone's implementation grid, not the AquaSynth abstraction. At 44.1 kHz, a 17 cm tract split into 44 cells has an acoustic travel time of roughly 0.5 samples per cell, so the twice-per-sample update is better understood as a discretization/wave-clock choice. AquaSynth's live target is continuous morphology plus fractional-delay waveguide lowering, with the grid chosen by the backend. ## AquaSynth Capability Map Current AquaSynth can express: - runtime parameters with stable paths; - reusable `tract_shape` declarations with authored diameter or area samples, physical length, normalized interpolation, resampling, and per-cell acoustic delay derivation; - derived tract areas and adjacent-section reflection coefficients; - reusable `glottis` declarations for tract excitation quality; - reusable `tract_injection` declarations for positioned frication/burst pressure; - reusable `nasal_branch` declarations with velum-controlled junctions; - reusable `tract_motion` declarations for slew and obstruction thresholds; - a `tract` voice command owned by `Voice.Tract`; - Pink Trombone-shaped controls for intensity, tenseness, tongue body, constriction, velum/nasal opening, turbulence, lip opening, and end reflections; - a Faust-lowered tract voice proxy with LF-style excitation, aspiration, frication, oral resonators, and a velum-controlled nasal lane; - generated oral bidirectional waveguide equations over a `tract_shape` section field when `propagation=waveguide`; - oscillator/noise sources; - ADSR and staged rate/level envelopes; - low/high/band/notch filters; - static and frame-scanned formant banks; - patch-level and voice-local modulation; - compiled Faust control sweeps through `/speech/output/N`. Current AquaSynth cannot exactly express: - fractional-delay tract propagation whose clock derives from physical length, propagation speed, and sample rate; - exact Pink Trombone block timing and source/noise/transient behavior inside the Faust-lowered Aqua graph. ## Reference Renderer Authority `PinkTromboneReferenceRenderer` is a source-port of the pinned MIT TypeScript implementation, not a Pink-Trombone-flavored proxy. Its inner graph mirrors the upstream DSP authorities: - `Synthesizer`: 512-sample blocks, tract stepping twice per output sample; - `Glottis`: LF waveform coefficient solve, aspiration noise, vibrato/wobble, and intensity/tenseness/frequency smoothing; - `Tract`: 44 oral cells, 28 nasal cells, area-derived reflections, three-way nasal junction, lip/nose radiation sum, filtered frication, and closure transients; - `TractShaper`: tongue/rest diameter targets, touch-style constriction reduction, wall slew, velum slew, and obstruction release detection. The renderer keeps AquaSynth's fixture control record as the authoring surface, but those controls are now translated into the source graph rather than into a hand-rolled approximation. Reference WAVs written before `20260526T211902375` were produced by the old approximation and are invalid for parity golf. ## Current Parity Rung The current committed rung is an expressive tract voice, not exact Pink Trombone anatomy: - `PinkTromboneReference.ToReferencePatch()` records the source, tract features, and relevant controls. - `ReferenceRebuildCatalog.PinkTromboneRebuilds` contains the current AquaSynth tract-voice proxy as a deliberately non-passing rebuild. - The `tract` DSL command parses into an ordinary `Voice` with `Voice.Tract`, so this remains a voice with a very expressive tract treatment. - `tract_shape` owns reusable continuous diameter/area functions. The current proxy consumes its shape summaries and derived reflection energy; waveguide lowering consumes a compiled grid sampled from that continuous owner, so authoring sample count and backend section count can differ. - `glottis` and `tract_injection` own excitation and positioned noise/burst controls consumed by tract voices. - `propagation=waveguide` emits an oral right/left tube from the derived reflection field. It is the first low-level propagation path, not full PT. - `nasal_branch` adds a second diameter/area tube and generated three-way oral/nasal scattering junction when used by a waveguide tract. - `tract_injection` pressure is distributed into waveguide section updates by position and width when waveguide propagation is active. - `tract_motion` smooths tract controls and lets the waveguide derive burst pressure from obstruction history. - waveguide lowering derives live per-section diameter targets, areas, and reflection coefficients from shape and gesture controls. - waveguide lowering now defaults to an acoustic unit-delay compiled grid from physical tract length, currently turning a 17 cm oral tract into 22 compiled sections at the 44.1 kHz target instead of treating PT's 44 cells as anatomy. - `substeps` is now legacy waveguide clock pressure. Current Faust lowering consumes it through drive/loss scaling, but the coherent target is fractional-delay propagation from physical tract length and wave speed. - `PinkTromboneParityFixtures` defines fixed Aqua DSL workouts for open, front, nasal, sibilant, and closure cases using the reusable low-level primitives. - `PinkTromboneReferenceRenderer` renders deterministic test-only traveling-wave references for those fixture controls. - `PinkTromboneLogMelParityTests` renders Aqua waveguide candidates, writes listening WAV/report artifacts under `artifacts/parity/pink-trombone-logmel/`, and reports the current waveguide baseline: open vowel cosine 0.6143, front vowel 0.6349, nasal 0.5425, sibilant 0.3744, closure-release -0.0820. - Waveguide lowering now uses one Faust feedback component `wg_loop ~ si.bus(...)` for the compiled oral tract and nasal branch. The previous scalar named-recursion form was cut because it was the wrong Faust shape, and the PT 44/28 grid is now reference pressure rather than the default emitted topology. - The proxy script parses and emits Faust with live controls, but its missing features explicitly name the waveguide authorities AquaSynth does not own. - `tools/vocal-tract-playground` exposes the same control surface for fast knob-twiddling through a small WebAudio witness. - `PinkTromboneReferenceDeclaresMissingWaveguideAuthority` prevents the proxy from being mistaken for real tract parity. That is the correct shape for now. It should be fun to touch, but still honest about the parts of Pink Trombone it cannot claim. ## Next Cut Do not add another formant workaround. The next coherent implementation is one of these: 1. Promote `Voice.Tract` from tract-shaped proxy lowering to a dedicated tract DSP model in AquaSynth.Faust/Core: typed tract sections, diameter curves, reflection calculation, glottal source, nasal branch, and a Faust emitter for that structure. 2. Replace `substeps` as a musical surface with fractional-delay waveguide lowering. Physical length, propagation speed, and sample rate decide delay; runtime morphology controls move diameters and junction openings without recompiling unless topology changes. 3. Use the log-mel artifact loop to golf fixture-by-fixture now that the real tract path renders. The new owner should be explainable as: ```text TractPlan owns section diameters and source/injection events so tract acoustics remain true during rendering. ``` If that sentence becomes awkward, the design is probably drifting back into proxy mud.