Clarify graph nasal coupling authority

This commit is contained in:
Meta Vens 2026-05-27 16:11:14 +01:00
commit efa425483f
7 changed files with 15 additions and 11 deletions

View file

@ -224,8 +224,9 @@ terminal-specific admittance in connection pressure instead of collapsing every
co-located terminal into one node area, and branch output uses a floored co-located terminal into one node area, and branch output uses a floored
area-ratio pressure normalization so weak side ports no longer receive full area-ratio pressure normalization so weak side ports no longer receive full
junction pressure. The generated tract graph also stopped treating the first junction pressure. The generated tract graph also stopped treating the first
nasal tube diameter as the velum aperture; velum now owns branch coupling and nasal tube diameter as the velum aperture; velum now owns branch entrance area
aperture. Two tempting compensators were cut: raw per-port outgoing coupling and nasal aperture, while connection coupling remains a structural admittance
limit. Two tempting compensators were cut: raw per-port outgoing coupling
made supposedly oral fixtures nearly silent, and lip/beak radiation gain did made supposedly oral fixtures nearly silent, and lip/beak radiation gain did
not restore oral vowel RMS. The internal-node scatter fix made unconnected not restore oral vowel RMS. The internal-node scatter fix made unconnected
injection/source terminals transmit pressure between adjacent segments instead injection/source terminals transmit pressure between adjacent segments instead

View file

@ -154,8 +154,10 @@ Trombone anatomy:
controls consumed by tract voices; graph injection maps burst into source controls consumed by tract voices; graph injection maps burst into source
`transient` rather than a PT-specific side path. `transient` rather than a PT-specific side path.
- `nasal_branch` adds a second diameter/area tube and generated oral/nasal - `nasal_branch` adds a second diameter/area tube and generated oral/nasal
connection terminals. Velum owns branch coupling and nasal aperture; the first connection terminals. Velum owns branch entrance area and nasal aperture;
nasal tube sample is not allowed to masquerade as the velum opening. 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 - generated graph records mirror live `tract` parameter bindings into acoustic
source, terminal, connection, radiation, and path-area fields so `/pink/...` source, terminal, connection, radiation, and path-area fields so `/pink/...`
controls exercise the actual graph. controls exercise the actual graph.

View file

@ -849,7 +849,7 @@ public static class FaustEmitter
var detune = port.Kind == AcousticSourceKind.Labial ? $" * (1.0 + ({balance} - 0.5) * 0.018)" : ""; var detune = port.Kind == AcousticSourceKind.Labial ? $" * (1.0 + ({balance} - 0.5) * 0.018)" : "";
var phase = $"os.phasor(1.0, {frequency}{detune})"; var phase = $"os.phasor(1.0, {frequency}{detune})";
var closure = $"clip01((0.12 - ({opening})) / 0.12)"; var closure = $"clip01((0.12 - ({opening})) / 0.12)";
var release = $"(max(0.0, (({closure}) : mem) - ({closure})) : + ~ *(0.90))"; var release = $"(max(0.0, (({closure}) : mem) - ({closure})) : + ~ *(0.995))";
return port.Kind switch return port.Kind switch
{ {
AcousticSourceKind.Glottal => AcousticSourceKind.Glottal =>
@ -859,7 +859,7 @@ public static class FaustEmitter
AcousticSourceKind.Reed => AcousticSourceKind.Reed =>
$"(ma.tanh(sin(2.0 * ma.PI * {phase}) * (1.0 + {pressure} * 8.0)) * {opening} + no.noise * {noise} * 0.2) * {balance}", $"(ma.tanh(sin(2.0 * ma.PI * {phase}) * (1.0 + {pressure} * 8.0)) * {opening} + no.noise * {noise} * 0.2) * {balance}",
AcousticSourceKind.TurbulenceJet => AcousticSourceKind.TurbulenceJet =>
$"((no.noise : fi.highpass(2, 900.0 + 2600.0 * clip01(1.0 - {opening}))) * {noise} * {pressure} * min(clip01((0.8 - {opening}) / 0.8), clip01(8.0 * (0.7 - {opening})) * clip01(30.0 * ({opening} - 0.3))) * 0.62 + (no.noise : fi.highpass(1, 450.0)) * {transient} * {pressure} * {release} * (0.8 + 0.8 * clip01({opening} / 0.8))) * {balance}", $"((no.noise : fi.highpass(2, 900.0 + 2600.0 * clip01(1.0 - {opening}))) * {noise} * {pressure} * min(clip01((0.8 - {opening}) / 0.8), clip01(8.0 * (0.7 - {opening})) * clip01(30.0 * ({opening} - 0.3))) * 0.62 + {transient} * {pressure} * {release} * 0.58 * (0.8 + 0.8 * clip01({opening} / 0.8))) * {balance}",
AcousticSourceKind.Click => AcousticSourceKind.Click =>
$"no.noise * {pressure} * max({opening}, {transient}) * exp(0.0 - age * 120.0) * {balance}", $"no.noise * {pressure} * max({opening}, {transient}) * exp(0.0 - age * 120.0) * {balance}",
AcousticSourceKind.Synthetic => AcousticSourceKind.Synthetic =>

View file

@ -1417,7 +1417,7 @@ public static class PatchScript
0, 0,
AcousticBranchKind.Nasal, AcousticBranchKind.Nasal,
nasal.Velum, nasal.Velum,
1, 0.15f,
true); true);
AddAcousticBranchRecord(branch); AddAcousticBranchRecord(branch);
AddAcousticTerminalRecord(new AcousticTerminal( AddAcousticTerminalRecord(new AcousticTerminal(
@ -1434,13 +1434,11 @@ public static class PatchScript
AcousticTerminalKind.Junction, AcousticTerminalKind.Junction,
branch.Name, branch.Name,
MathF.Pow(Math.Max(0, branch.Opening), 2) / Math.Max(0.000001f, nasalArea.Diameters[0] * nasalArea.Diameters[0]))); MathF.Pow(Math.Max(0, branch.Opening), 2) / Math.Max(0.000001f, nasalArea.Diameters[0] * nasalArea.Diameters[0])));
var branchConnectionIndex = _acousticConnections.Count;
AddAcousticConnectionRecord(new AcousticConnection( AddAcousticConnectionRecord(new AcousticConnection(
BranchConnectionName(branch), BranchConnectionName(branch),
[BranchFromTerminalName(branch), BranchToTerminalName(branch)], [BranchFromTerminalName(branch), BranchToTerminalName(branch)],
AcousticConnectionLaw.AreaScattering, AcousticConnectionLaw.AreaScattering,
branch.Coupling)); branch.Coupling));
MirrorParameterBinding(OwnerField(tractPath, "velum"), $"/acoustic/connections/{branchConnectionIndex}/coupling");
var nasalRadiation = new AcousticRadiationPort( var nasalRadiation = new AcousticRadiationPort(
$"{nasalPathName}_radiation", $"{nasalPathName}_radiation",
nasalPathName, nasalPathName,

View file

@ -177,3 +177,4 @@
{"evidence":"After switching graph radiation from raw pressure to boundary flow, recalibrated the graph radiation gain from 3.0 to 4.0. A 4.5 trial improved utterance RMS but pushed static fixtures closer to soft-clip influence, so 4.0 was kept. Focused utterance parity passed with artifacts/parity/pink-trombone-utterance-logmel/20260527T124230804: mama cosine 0.5712 RMS 0.4431, papa 0.8659 RMS 0.1768, thrombosis 0.4379 RMS 0.3324. Static parity passed with artifacts/parity/pink-trombone-logmel/20260527T124311305: open/front/nasal/ma/sibilant/closure cosine 0.5942/0.6710/0.6369/0.5955/0.4201/0.6143.","claim":"Radiation gain is part of the post-flow normalization contract, not a substitute for articulation. The kept value improves underpowered utterance output while preserving static guardrails; pressure storage/release remains the actual consonant problem.","timestamp":"2026-05-27T12:45:00+01:00","topic":"acoustic-radiation-flow-normalization"} {"evidence":"After switching graph radiation from raw pressure to boundary flow, recalibrated the graph radiation gain from 3.0 to 4.0. A 4.5 trial improved utterance RMS but pushed static fixtures closer to soft-clip influence, so 4.0 was kept. Focused utterance parity passed with artifacts/parity/pink-trombone-utterance-logmel/20260527T124230804: mama cosine 0.5712 RMS 0.4431, papa 0.8659 RMS 0.1768, thrombosis 0.4379 RMS 0.3324. Static parity passed with artifacts/parity/pink-trombone-logmel/20260527T124311305: open/front/nasal/ma/sibilant/closure cosine 0.5942/0.6710/0.6369/0.5955/0.4201/0.6143.","claim":"Radiation gain is part of the post-flow normalization contract, not a substitute for articulation. The kept value improves underpowered utterance output while preserving static guardrails; pressure storage/release remains the actual consonant problem.","timestamp":"2026-05-27T12:45:00+01:00","topic":"acoustic-radiation-flow-normalization"}
{"evidence":"Added `AudioArticulationComparison` to `AudioComparison` and updated Pink Trombone parity reports with envelope cosine, active-frame ratio, silence mismatch, envelope/spectral flux ratios, motor-band ratio, speech-band ratio, articulation score, and utterance verdicts. Focused tests passed. Latest utterance artifact artifacts/parity/pink-trombone-utterance-logmel/20260527T130026316 reports mama/papa/thrombosis as `not-accepted-articulation` with articulation scores 0.1930/0.1829/0.1848 despite log-mel cosine 0.5712/0.8659/0.4379. Static reports also expose weak speech-band ratios instead of hiding behind cosine.","claim":"Log-mel cosine is a spectral witness, not a speech-articulation authority. The parity harness must surface silence-map, envelope, flux, motor-band, and speech-band failures so filtered buzz cannot forge a listening receipt.","timestamp":"2026-05-27T13:05:00+01:00","topic":"voice-articulation-metric-witness"} {"evidence":"Added `AudioArticulationComparison` to `AudioComparison` and updated Pink Trombone parity reports with envelope cosine, active-frame ratio, silence mismatch, envelope/spectral flux ratios, motor-band ratio, speech-band ratio, articulation score, and utterance verdicts. Focused tests passed. Latest utterance artifact artifacts/parity/pink-trombone-utterance-logmel/20260527T130026316 reports mama/papa/thrombosis as `not-accepted-articulation` with articulation scores 0.1930/0.1829/0.1848 despite log-mel cosine 0.5712/0.8659/0.4379. Static reports also expose weak speech-band ratios instead of hiding behind cosine.","claim":"Log-mel cosine is a spectral witness, not a speech-articulation authority. The parity harness must surface silence-map, envelope, flux, motor-band, and speech-band failures so filtered buzz cannot forge a listening receipt.","timestamp":"2026-05-27T13:05:00+01:00","topic":"voice-articulation-metric-witness"}
{"evidence":"Segment delay lowering no longer clamps physical acoustic graph segments to one sample before wave-clock lowering; `WaveClockPolicy` now owns the legal delay floor. Generated `tract propagation=graph` patches use `HalfSampleGrid` instead of first-order Thiran, matching the PT/Kelly-Lochbaum half-sample regime. Focused graph, Faust validation, utterance, and static parity tests passed. Latest utterance artifact artifacts/parity/pink-trombone-utterance-logmel/20260527T133539554: mama cosine/articulation 0.5982/0.1952, papa 0.8615/0.1979, thrombosis 0.5217/0.2640. Latest static artifact artifacts/parity/pink-trombone-logmel/20260527T133424894. Re-testing the literal SndKit reflection sign made thrombosis loud/unstable; adding a broader glottal harmonic tail worsened voiced-band behavior, so both were cut.","claim":"Physical tract length must lower to sub-sample graph delays; forcing each section to one sample made the tract acoustically overlong and hid failures behind a low resonance crutch. Half-sample graph timing is the correct next foundation, but articulation still fails because body/radiation and pressure-release behavior are incomplete.","timestamp":"2026-05-27T13:40:00+01:00","topic":"acoustic-graph-half-sample-clock"} {"evidence":"Segment delay lowering no longer clamps physical acoustic graph segments to one sample before wave-clock lowering; `WaveClockPolicy` now owns the legal delay floor. Generated `tract propagation=graph` patches use `HalfSampleGrid` instead of first-order Thiran, matching the PT/Kelly-Lochbaum half-sample regime. Focused graph, Faust validation, utterance, and static parity tests passed. Latest utterance artifact artifacts/parity/pink-trombone-utterance-logmel/20260527T133539554: mama cosine/articulation 0.5982/0.1952, papa 0.8615/0.1979, thrombosis 0.5217/0.2640. Latest static artifact artifacts/parity/pink-trombone-logmel/20260527T133424894. Re-testing the literal SndKit reflection sign made thrombosis loud/unstable; adding a broader glottal harmonic tail worsened voiced-band behavior, so both were cut.","claim":"Physical tract length must lower to sub-sample graph delays; forcing each section to one sample made the tract acoustically overlong and hid failures behind a low resonance crutch. Half-sample graph timing is the correct next foundation, but articulation still fails because body/radiation and pressure-release behavior are incomplete.","timestamp":"2026-05-27T13:40:00+01:00","topic":"acoustic-graph-half-sample-clock"}
{"evidence":"Focused PT tests passed. Utterance artifact artifacts/parity/pink-trombone-utterance-logmel/20260527T150836912: mama/papa/thrombosis cosine 0.8337/0.8893/0.5317, rmsRatio 1.0768/1.5626/0.4004, articulation 0.2118/0.1890/0.2594. Static artifact artifacts/parity/pink-trombone-logmel/20260527T150749857: open/front/nasal/ma/sibilant/closure cosine 0.6942/0.6732/0.7386/0.7067/0.4548/0.5449. A long noisy release transient was cut because it drove papa motor-band ratio to 47.0313.","claim":"Generated graph nasal branches no longer mirror velum into connection coupling. Velum owns nasal entrance area and nostril aperture; `AcousticConnection.Coupling` is a structural max-admittance limit. A fixed 0.15 generated nasal coupling avoids the previous double gate without flooding the graph. `TurbulenceJet` transient lowering now emits a short pressure pulse rather than filtered noise, but true plosive intelligibility still needs graph pressure storage/release around severe closures.","timestamp":"2026-05-27T15:03:00+01:00","topic":"pink-trombone-nasal-coupling-authority"}

View file

@ -119,8 +119,8 @@ live_invariants:
- The physical voice research packet now includes a practical implementation/researcher map (`research/physical-voice-modeling/PEOPLE.md`) and talk/transcript ledger (`research/physical-voice-modeling/talks/TALKS.md`). Birkholz/VocalTractLab pressures multi-level articulatory control and gestures; Story/TubeTalker pressures continuous parametric area functions and length/coupling; Smith pressures bidirectional delay-line scattering and fractional-delay waveguides; Fels/ArtiSynth pressures separation between biomechanics, acoustics, timeline controls, and diagnostics. These are reusable DSL semantics, not modules to clone. - The physical voice research packet now includes a practical implementation/researcher map (`research/physical-voice-modeling/PEOPLE.md`) and talk/transcript ledger (`research/physical-voice-modeling/talks/TALKS.md`). Birkholz/VocalTractLab pressures multi-level articulatory control and gestures; Story/TubeTalker pressures continuous parametric area functions and length/coupling; Smith pressures bidirectional delay-line scattering and fractional-delay waveguides; Fels/ArtiSynth pressures separation between biomechanics, acoustics, timeline controls, and diagnostics. These are reusable DSL semantics, not modules to clone.
- Physical voice implementation has started moving PT pressure into neutral acoustic owners: `AcousticPath`, `AcousticTerminal`, `AcousticConnection`, `AcousticSourcePort`, `AcousticBranch`, `AcousticRadiationPort`, `WaveClockPolicy`, and `AcousticPortNetwork`. Parser commands `path`, `terminal`, `connect`, `source_port`, `branch`, `radiation_port`, `wave_clock`, and `acoustic_network` now exist. Existing `tract_shape`, `glottis`, `tract_injection`, `nasal_branch`, and `tract` commands populate acoustic records as compatibility aliases while the current `Voice.Tract` Faust renderer still owns audio. - Physical voice implementation has started moving PT pressure into neutral acoustic owners: `AcousticPath`, `AcousticTerminal`, `AcousticConnection`, `AcousticSourcePort`, `AcousticBranch`, `AcousticRadiationPort`, `WaveClockPolicy`, and `AcousticPortNetwork`. Parser commands `path`, `terminal`, `connect`, `source_port`, `branch`, `radiation_port`, `wave_clock`, and `acoustic_network` now exist. Existing `tract_shape`, `glottis`, `tract_injection`, `nasal_branch`, and `tract` commands populate acoustic records as compatibility aliases while the current `Voice.Tract` Faust renderer still owns audio.
- `acoustic` / `acoustic_voice` can now render an `AcousticPortNetwork` through a compact Faust response proxy or, when typed terminals are present, a compiled bidirectional Faust segment graph. Graph lowering splits paths at terminal positions, aggregates co-located terminals into graph nodes, orders connection ports deterministically, scatters area-weighted/pressure/bypass connection groups, injects source terminals even at connected nodes, and sums radiation terminals. Segment delay follows physical segment length and the network `wave_clock` strategy through unit-grid, half-sample, linear fractional, Lagrange, or Thiran/allpass Faust delay primitives. Source, branch, radiation, terminal, and connection controls can bind through ordinary Aqua parameters into emitted Faust. PT-shaped `tract` authoring now routes accepted parity through `propagation=graph`; the old waveguide parity lane is not a comparison baseline or historical pressure lane. - `acoustic` / `acoustic_voice` can now render an `AcousticPortNetwork` through a compact Faust response proxy or, when typed terminals are present, a compiled bidirectional Faust segment graph. Graph lowering splits paths at terminal positions, aggregates co-located terminals into graph nodes, orders connection ports deterministically, scatters area-weighted/pressure/bypass connection groups, injects source terminals even at connected nodes, and sums radiation terminals. Segment delay follows physical segment length and the network `wave_clock` strategy through unit-grid, half-sample, linear fractional, Lagrange, or Thiran/allpass Faust delay primitives. Source, branch, radiation, terminal, and connection controls can bind through ordinary Aqua parameters into emitted Faust. PT-shaped `tract` authoring now routes accepted parity through `propagation=graph`; the old waveguide parity lane is not a comparison baseline or historical pressure lane.
- Pink Trombone log-mel parity now writes graph candidates only. Generated tract graphs mirror live `/pink/...` tract bindings into acoustic source, terminal, connection, radiation, and path-area fields. Graph generation stopped baking first-frame tongue/constriction/lip morphology into the path; `AcousticPath.AreaControl` now turns tongue/constriction/lip controls into live area expressions at graph sample points. Velum owns nasal branch coupling/aperture, and the first nasal tube sample is no longer allowed to decide the velum opening. Graph radiation now uses aperture as a boundary impedance owner: lip/beak opening blends boundary reflection from near-closed termination to declared open-end reflection, and radiation reads boundary flow (`incoming - outgoing`) through a stronger radiation slope instead of raw incoming pressure. Latest static graph evidence: open/front/nasal/ma/sibilant/closure cosine 0.6088/0.6826/0.6468/0.6153/0.4158/0.6198. - Pink Trombone log-mel parity now writes graph candidates only. Generated tract graphs mirror live `/pink/...` tract bindings into acoustic source, terminal, radiation, and path-area fields. Graph generation stopped baking first-frame tongue/constriction/lip morphology into the path; `AcousticPath.AreaControl` now turns tongue/constriction/lip controls into live area expressions at graph sample points. Velum owns nasal branch entrance area/aperture, while connection coupling is a structural admittance limit and no longer mirrors velum as a second gate. The first nasal tube sample is no longer allowed to decide the velum opening. Graph radiation now uses aperture as a boundary impedance owner: lip/beak opening blends boundary reflection from near-closed termination to declared open-end reflection, and radiation reads boundary flow (`incoming - outgoing`) through a stronger radiation slope instead of raw incoming pressure. Latest static graph evidence after structural nasal coupling is under `artifacts/parity/pink-trombone-logmel/20260527T150749857`: open/front/nasal/ma/sibilant/closure cosine 0.6942/0.6732/0.7386/0.7067/0.4548/0.5449.
- PT expressive parity should decompose into reusable Aqua primitives before audio golf: `tract_shape` owns continuous diameter/area geometry over normalized position, physical length (`length_cm`), interpolation/resampling, derived reflection coefficients, and per-cell acoustic delay; `AcousticAreaControl` owns live sampled morphology controls on a path; `WaveClockPolicy` owns the legal delay floor instead of forcing every segment to one sample; generated graph tracts now use `HalfSampleGrid` to match the PT/Kelly-Lochbaum half-sample regime; ordinary same-path graph interiors now own signed two-port area-discontinuity scattering; `glottis` owns excitation controls with mild harmonic waveshaping and a small higher-harmonic brightness term for graph sources; `tract_injection` owns positioned frication/burst controls; `AcousticSourcePort.Transient` owns graph-native release/click energy; sustained `TurbulenceJet` lowering owns a narrow-open aperture gate so closed constrictions no longer hiss; `AcousticSourcePositionControl` owns differentiable runtime weights over fixed source terminals so moving articulators can move source energy without recompiling the graph; `AcousticRadiationPort` owns aperture-dependent boundary reflection, flow radiation, and current post-flow normalization; `nasal_branch` owns a second diameter/area tube and branch aperture; `tract_motion` owns control slew and obstruction threshold; `AcousticPortNetwork` owns graph lowering. `PinkTromboneReferenceRenderer` ports the pinned MIT `chdh/pink-trombone-mod` DSP source (`external/pink-trombone-mod` at 359c2d3b42b10280404c1650dc601902112b4c90), and reference WAVs before `artifacts/parity/pink-trombone-utterances/20260526T211902375` are invalid. The accepted PT utterance curriculum is mama, papa, and thrombosis; lulek was cut because its control sketch taught a bad artifact. Latest graph-only utterance smoke under `artifacts/parity/pink-trombone-utterance-logmel/20260527T133539554`: mama/papa/thrombosis remain `not-accepted-articulation` with articulation scores 0.1952/0.1979/0.2640, but the half-sample clock improves `thrombosis` motor-band behavior and removes an overlong-tract crutch. `AudioComparison.Articulation` now reports envelope cosine, active-frame ratio, silence mismatch, envelope/spectral flux ratios, motor-band ratio, speech-band ratio, and an articulation score so log-mel cannot forge a listening receipt. A direct LF coefficient source was tested and cut because it overdrove the graph and broke static open vowel; a broader harmonic-tail source was tested and cut because it worsened voiced-band behavior. A naive midpoint admittance scatter was tested and cut because it collapsed `mama`; the kept area-discontinuity scatter needed the opposite reflection sign for this graph state convention, and re-testing the literal SndKit sign after the clock fix made `thrombosis` loud/unstable. Next pressure is graph-native storage/release around severe constrictions plus nasal/oral branch coupling; output coloring alone is not allowed to impersonate articulation. - PT expressive parity should decompose into reusable Aqua primitives before audio golf: `tract_shape` owns continuous diameter/area geometry over normalized position, physical length (`length_cm`), interpolation/resampling, derived reflection coefficients, and per-cell acoustic delay; `AcousticAreaControl` owns live sampled morphology controls on a path; `WaveClockPolicy` owns the legal delay floor instead of forcing every segment to one sample; generated graph tracts now use `HalfSampleGrid` to match the PT/Kelly-Lochbaum half-sample regime; ordinary same-path graph interiors now own signed two-port area-discontinuity scattering; `glottis` owns excitation controls with mild harmonic waveshaping and a small higher-harmonic brightness term for graph sources; `tract_injection` owns positioned frication/burst controls; `AcousticSourcePort.Transient` owns graph-native release/click energy as a pressure pulse rather than filtered noise; sustained `TurbulenceJet` lowering owns a narrow-open aperture gate so closed constrictions no longer hiss; `AcousticSourcePositionControl` owns differentiable runtime weights over fixed source terminals so moving articulators can move source energy without recompiling the graph; `AcousticRadiationPort` owns aperture-dependent boundary reflection, flow radiation, and current post-flow normalization; `nasal_branch` owns a second diameter/area tube and branch aperture while `AcousticConnection.Coupling` owns structural max admittance; `tract_motion` owns control slew and obstruction threshold; `AcousticPortNetwork` owns graph lowering. `PinkTromboneReferenceRenderer` ports the pinned MIT `chdh/pink-trombone-mod` DSP source (`external/pink-trombone-mod` at 359c2d3b42b10280404c1650dc601902112b4c90), and reference WAVs before `artifacts/parity/pink-trombone-utterances/20260526T211902375` are invalid. The accepted PT utterance curriculum is mama, papa, and thrombosis; lulek was cut because its control sketch taught a bad artifact. Latest graph-only utterance smoke under `artifacts/parity/pink-trombone-utterance-logmel/20260527T150836912`: mama/papa/thrombosis remain `not-accepted-articulation` with cosine 0.8337/0.8893/0.5317 and articulation scores 0.2118/0.1890/0.2594. `AudioComparison.Articulation` reports envelope cosine, active-frame ratio, silence mismatch, envelope/spectral flux ratios, motor-band ratio, speech-band ratio, and an articulation score so log-mel cannot forge a listening receipt. A direct LF coefficient source was tested and cut because it overdrove the graph and broke static open vowel; a broader harmonic-tail source was tested and cut because it worsened voiced-band behavior. A naive midpoint admittance scatter was tested and cut because it collapsed `mama`; the kept area-discontinuity scatter needed the opposite reflection sign for this graph state convention, and re-testing the literal SndKit sign after the clock fix made `thrombosis` loud/unstable. A long noisy release transient was tested and cut because it turned papa into motor-band energy; deterministic pressure release with PT-scale decay is structurally kept but still not sufficient. Next pressure is true graph pressure storage/release at severe closures; output coloring alone is not allowed to impersonate articulation.
- If dotnet builds hang in this workspace, stop orphan dotnet workers and retry with `--disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false`; plain parallel/shared builds can stall without useful diagnostics. - If dotnet builds hang in this workspace, stop orphan dotnet workers and retry with `--disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false`; plain parallel/shared builds can stall without useful diagnostics.
- eSpeak NG is an early parity reference for timing, IPA coverage, and log-mel pressure, not an anatomy oracle or final target. - eSpeak NG is an early parity reference for timing, IPA coverage, and log-mel pressure, not an anatomy oracle or final target.
- Do not expand into prosody, emotional context, personality, or broad Weksa expressivity until the tiny IPA utterance harness can show useful loss movement. - Do not expand into prosody, emotional context, personality, or broad Weksa expressivity until the tiny IPA utterance harness can show useful loss movement.

View file

@ -638,6 +638,8 @@ public sealed class PatchScriptTests
Assert.Contains(patch.AcousticPaths, path => path.Name == "voices_0_oral" && path.AreaControl is not null); Assert.Contains(patch.AcousticPaths, path => path.Name == "voices_0_oral" && path.AreaControl is not null);
Assert.Contains(patch.AcousticSourcePorts, port => port.Name.StartsWith("voices_0_inj_", StringComparison.Ordinal) && port.Transient > 0 && port.PositionControl is not null); Assert.Contains(patch.AcousticSourcePorts, port => port.Name.StartsWith("voices_0_inj_", StringComparison.Ordinal) && port.Transient > 0 && port.PositionControl is not null);
Assert.Contains(patch.AcousticTerminals, terminal => terminal.Name.StartsWith("voices_0_area_", StringComparison.Ordinal)); Assert.Contains(patch.AcousticTerminals, terminal => terminal.Name.StartsWith("voices_0_area_", StringComparison.Ordinal));
Assert.Contains(patch.AcousticConnections, connection => connection.Name.Contains("_nose_connection", StringComparison.Ordinal) && MathF.Abs(connection.Coupling - 0.15f) < 0.0001f);
Assert.DoesNotContain(patch.ParameterBindings, binding => binding.FieldPath.StartsWith("/acoustic/connections/", StringComparison.OrdinalIgnoreCase) && binding.FieldPath.EndsWith("/coupling", StringComparison.OrdinalIgnoreCase));
Assert.Contains("acoustic_graph_radiated", export.Source); Assert.Contains("acoustic_graph_radiated", export.Source);
Assert.Contains("graph_terminal_area_voices_0_area_", export.Source); Assert.Contains("graph_terminal_area_voices_0_area_", export.Source);
Assert.DoesNotContain("wg_diameter_target_", export.Source); Assert.DoesNotContain("wg_diameter_target_", export.Source);