AquaSynth/docs/pink-trombone-parity.md
2026-05-27 16:11:14 +01:00

11 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 active Aqua path is the typed acoustic graph: continuous paths, source ports, branch terminals, radiation ports, connection laws, and wave-clock policy. Pink Trombone's old waveguide discretization is source-reference pressure, not an Aqua implementation lane to preserve.

This packet exists so the machine stays inspectable while the old one turns into commit-history dust.

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-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:

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;
  • typed acoustic paths, terminals, connections, source ports, branch/radiation ports, and wave-clock policies;
  • optional acoustic path AreaControl fields that turn tongue, constriction, and lip gestures into live diameter/area expressions at graph sample points;
  • source-port transient control for graph-native release bursts on turbulent or click-like sources;
  • aperture-normalized turbulent source lowering, where sustained jet noise is allowed only through a narrow-open constriction and closure release remains owned by the transient path;
  • mildly shaped glottal source lowering, which adds harmonic drive to the stable glottal primitive without adopting the unstable direct LF coefficient port as the live graph source;
  • source-port PositionControl, which lets a bank of fixed graph terminals share one moving source gesture through differentiable runtime weights;
  • signed two-port path scattering at ordinary same-path interior nodes, using adjacent segment areas as the local tube discontinuity owner;
  • graph lowering that splits paths at terminals, injects typed sources, scatters connection groups, and radiates from typed terminal ports;
  • 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:

  • exact Pink Trombone obstruction history;
  • fully continuous area modulation inside a delay segment between graph sample points. Generated tract graphs now sample live area along the path, but the delay segment between two sampled nodes remains uniform.
  • exact Pink Trombone block timing and source/noise/transient behavior inside the Faust-lowered Aqua graph.

Graph tract timing is no longer intentionally overlong: physical segment delay can be sub-sample, and generated graph tracts use a half-sample clock rather than clamping every segment to one sample.

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.

The accepted utterance curriculum is intentionally small: mama, papa, and thrombosis. lulek was cut after listening because its control sketch was teaching a bad artifact rather than useful Pink Trombone capability.

Current Parity Rung

The current committed rung is an expressive graph voice, not exact Pink Trombone anatomy:

  • PinkTromboneReference.ToReferencePatch() records the source, tract features, and relevant controls.
  • The tract DSL command parses into an ordinary Voice with Voice.Tract, and generates the same acoustic graph records used by explicit graph authoring.
  • tract_shape owns reusable continuous diameter/area functions. Generated graph paths now attach AcousticAreaControl, so tongue, constriction, and lip gestures alter live node areas and therefore scattering along the oral tract.
  • glottis and tract_injection own excitation and positioned noise/burst controls consumed by tract voices; graph injection maps burst into source transient rather than a PT-specific side path.
  • nasal_branch adds a second diameter/area tube and generated oral/nasal connection terminals. Velum owns branch entrance area and nasal aperture; connection coupling is a structural admittance limit, not a second velum writer. The first nasal tube sample is not allowed to masquerade as the velum opening.
  • generated graph records mirror live tract parameter bindings into acoustic source, terminal, connection, radiation, and path-area fields so /pink/... controls exercise the actual graph.
  • generated graph tract injection now emits a source-port bank along the oral tract; /pink/constriction/index weights those ordinary source ports instead of leaving later bursts stuck at the first-frame constriction location.
  • accepted utterance parity lowers the surviving PT control-point sketches into Faust age curves over ordinary /pink/... parameters and compares the Aqua graph render against the source-ported PT renderer.
  • 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 graph candidates, writes listening WAV/report artifacts under artifacts/parity/pink-trombone-logmel/, and reports only the graph lane.
  • Latest static graph fixture evidence after cutting the old parity lane: open vowel cosine 0.6067, front vowel 0.6573, nasal 0.6871, bilabial-nasal-ma 0.6476, sibilant 0.4502, closure-release 0.6168.
  • Latest graph utterance smoke evidence: mama cosine 0.3262 / RMS 1.0722, papa 0.8567 / 0.1801, thrombosis 0.5762 / 0.8389 under artifacts/parity/pink-trombone-utterance-logmel/20260527T120741887. This is still not final speech parity; it is the first honest graph-only moving-utterance rung.
  • Listening pressure remains active, but the smartphone-vibration failure has a named tract owner now. The signed two-port scatter moved papa into a PT-like 500-1000 Hz body band and pulled thrombosis RMS under reference level. Radiation aperture now also owns boundary reflection, and graph radiation reads boundary flow (incoming - outgoing) through a stronger radiation high-pass slope instead of acting as a raw pressure tap. The log-mel witness still overrated the result, so the parity harness now reports articulation diagnostics: envelope cosine, active-frame ratio, silence mismatch, envelope/spectral flux ratios, motor-band ratio, speech-band ratio, and an articulation verdict. The latest utterances are explicitly not-accepted-articulation; pressure storage/release remains the next live cut.
  • tools/vocal-tract-playground exposes the same control surface for fast knob-twiddling through a small WebAudio witness.
  • PinkTromboneReferenceDeclaresMissingWaveguideAuthority prevents graph coverage from being mistaken for exact PT 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. The next target is not to revive the old waveguide. The next target is making moving graph morphology sound like an actual mouth.

Next Cut

Do not add another formant workaround. The next coherent implementation is one of these:

  1. Add graph-native pressure storage/release around severe constrictions so stops are released by the acoustic graph instead of only by a source burst.
  2. Improve nasal/oral branch and radiation behavior so mama gets vowel body without reverting to low-band motor buzz.
  3. Use the artifact loop to golf mama, papa, and thrombosis against the source-ported PT renderer, but treat log-mel as spectral pressure only. Articulation diagnostics own the "does this behave like speech?" verdict.

The new owner should be explainable as:

AcousticGraph owns paths, terminals, sources, connections, radiation, and live
control bindings so tract acoustics remain true during rendering.

If that sentence becomes awkward, the design is probably drifting back into proxy mud.