9.1 KiB
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, https://github.com/chdh/pink-trombone-mod- Pinned local source:
external/pink-trombone-modat359c2d3b42b10280404c1650dc601902112b4c90 - Source files inspected:
src/Synthesizer.tssrc/Glottis.tssrc/Tract.tssrc/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:
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_shapedeclarations 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
glottisdeclarations for tract excitation quality; - reusable
tract_injectiondeclarations for positioned frication/burst pressure; - reusable
nasal_branchdeclarations with velum-controlled junctions; - reusable
tract_motiondeclarations for slew and obstruction thresholds; - a
tractvoice command owned byVoice.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_shapesection field whenpropagation=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.PinkTromboneRebuildscontains the current AquaSynth tract-voice proxy as a deliberately non-passing rebuild.- The
tractDSL command parses into an ordinaryVoicewithVoice.Tract, so this remains a voice with a very expressive tract treatment. tract_shapeowns 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.glottisandtract_injectionown excitation and positioned noise/burst controls consumed by tract voices.propagation=waveguideemits an oral right/left tube from the derived reflection field. It is the first low-level propagation path, not full PT.nasal_branchadds a second diameter/area tube and generated three-way oral/nasal scattering junction when used by a waveguide tract.tract_injectionpressure is distributed into waveguide section updates by position and width when waveguide propagation is active.tract_motionsmooths 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.
substepsis 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.PinkTromboneParityFixturesdefines fixed Aqua DSL workouts for open, front, nasal, sibilant, and closure cases using the reusable low-level primitives.PinkTromboneReferenceRendererrenders deterministic test-only traveling-wave references for those fixture controls.PinkTromboneLogMelParityTestsrenders Aqua waveguide candidates, writes listening WAV/report artifacts underartifacts/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-playgroundexposes the same control surface for fast knob-twiddling through a small WebAudio witness.PinkTromboneReferenceDeclaresMissingWaveguideAuthorityprevents 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:
- Promote
Voice.Tractfrom 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. - Replace
substepsas 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. - 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:
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.