Limit generated tract contact owners
This commit is contained in:
parent
25e8850f27
commit
04f08e1fe7
5 changed files with 82 additions and 6 deletions
|
|
@ -72,9 +72,10 @@ Outputs: load-aware source flow terms, named `_load_pressure` locals for
|
|||
non-turbulence sources, and named `graph_contact_*` closure/reservoir/release
|
||||
signals for contact terminals.
|
||||
|
||||
Derived state: generated tract area terminals are contact-capable graph
|
||||
terminals. They still derive area from the live tract path geometry; they do
|
||||
not become a separate morphology owner.
|
||||
Derived state: generated tract area terminals are topology junctions that
|
||||
derive area from the live tract path geometry; generated contact terminals are
|
||||
a sparse overlay that owns closure pressure storage and release. Area samples
|
||||
are no longer contact owners just because they define tube geometry.
|
||||
|
||||
Forbidden writers: plosive release is not allowed to live only inside a
|
||||
TurbulenceJet source expression. A source-local burst can remain as excitation,
|
||||
|
|
@ -87,6 +88,38 @@ kind, now load-aware through the same source impedance path. The checked-in
|
|||
bronchial paths, one tracheal path, a three-terminal area-scattering merge,
|
||||
and a beak radiation port. No species module was added.
|
||||
|
||||
## 2026-05-29 Sparse Contact Owner
|
||||
|
||||
Owner: generated `tract` authoring owns a sparse contact overlay; graph path
|
||||
lowering owns contact release injection through ordinary two-port scattering.
|
||||
|
||||
Inputs: full area-junction grid for tube geometry, up to four generated contact
|
||||
terminals spread across the tract interior, local terminal area, node incident
|
||||
pressure, and upstream/downstream traveling waves.
|
||||
|
||||
Outputs: named `graph_contact_*` closure/reservoir/release signals only at the
|
||||
sparse contact owners, while every generated `voices_0_area_*` terminal remains
|
||||
a `Junction` for geometry/scattering.
|
||||
|
||||
Derived state: `voices_0_contact_*` is no longer a second morphology grid. It is
|
||||
a small collision/pressure-storage overlay derived from tract section count.
|
||||
|
||||
Forbidden writers: ordinary area terminals must not decide plosive contact
|
||||
state. Inline contact occlusion in the scattering equation is not shipped; the
|
||||
first attempt still overflowed the native Faust debug compiler at eight contact
|
||||
owners, so contact count is capped at four until occlusion can be expressed as a
|
||||
smaller compiled primitive or a lower-pressure diagnostic path.
|
||||
|
||||
Evidence: opt-in thrombosis probe
|
||||
`artifacts/parity/pink-trombone-graph-thrombosis-probes/20260529T122217729`
|
||||
passes with lip-end contact closure peak `0.936876`, contact output peak
|
||||
`0.547741`, lip boundary load `0.516196`, lip flow `0.585704`, and modal source
|
||||
out `1.235997`. Accepted utterance diagnostic
|
||||
`artifacts/parity/pink-trombone-utterance-logmel/20260529T122409541` still fails
|
||||
articulation: `mama/papa/thrombosis` cosine `0.8302/0.7865/0.3218`, with
|
||||
thrombosis RMS ratio `0.0770`, active ratio `0.3151`, and silence mismatch
|
||||
`0.7205`.
|
||||
|
||||
## Component Audit
|
||||
|
||||
### Topology Construction
|
||||
|
|
|
|||
|
|
@ -1432,6 +1432,22 @@ public static class PatchScript
|
|||
$"{prefix}_area_{section}",
|
||||
primaryPathName,
|
||||
position,
|
||||
AcousticTerminalKind.Junction,
|
||||
"",
|
||||
1,
|
||||
0);
|
||||
AddAcousticTerminalRecord(terminal);
|
||||
terminalNames.Add(terminal.Name);
|
||||
}
|
||||
|
||||
var contactSections = SparseContactSections(tract.Sections);
|
||||
foreach (var section in contactSections)
|
||||
{
|
||||
var position = section / (float)Math.Max(1, tract.Sections - 1);
|
||||
var terminal = new AcousticTerminal(
|
||||
$"{prefix}_contact_{section}",
|
||||
primaryPathName,
|
||||
position,
|
||||
AcousticTerminalKind.Contact,
|
||||
"",
|
||||
1,
|
||||
|
|
@ -1590,6 +1606,30 @@ public static class PatchScript
|
|||
private static float NormalizeTractIndex(float index, int sections) =>
|
||||
sections <= 0 ? 0 : Math.Clamp(index / Math.Max(1, sections - 1), 0, 1);
|
||||
|
||||
private static IReadOnlyList<int> SparseContactSections(int sections)
|
||||
{
|
||||
var interior = Math.Max(0, sections - 2);
|
||||
if (interior == 0)
|
||||
{
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
|
||||
var contactCount = Math.Min(4, interior);
|
||||
if (contactCount == 1)
|
||||
{
|
||||
return [1];
|
||||
}
|
||||
|
||||
var result = new SortedSet<int>();
|
||||
for (var i = 0; i < contactCount; i++)
|
||||
{
|
||||
var section = 1 + (int)MathF.Round(i * (interior - 1) / (float)(contactCount - 1));
|
||||
result.Add(Math.Clamp(section, 1, sections - 2));
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
private void AddModBus(IReadOnlyDictionary<string, string> fields, int line)
|
||||
{
|
||||
var name = GetAny(fields, ["name", "n"], "mod");
|
||||
|
|
|
|||
|
|
@ -220,3 +220,4 @@
|
|||
{"evidence":"Moved contact release out of the generic node source sum and into ordinary two-port path scattering. The new graph-owned closure primitive emits closure/reservoir/release/out probes and injects release directionally into downstream/upstream traveling waves. Latest opt-in thrombosis probe `artifacts/parity/pink-trombone-graph-thrombosis-probes/20260529T021934812`: lip contact out rose from prior 0.032413 to 0.548231, reservoir drive 0.519667, reservoir 6.024680, release 0.485894, lip radiation flow 0.581880, modal source out 1.233802, sibilant area-34 source out 0.099287. Latest accepted-utterance diagnostic `artifacts/parity/pink-trombone-utterance-logmel/20260529T022214016` still fails articulation: thrombosis RMS improves to 0.0761 but cosine stays about 0.331 and silence mismatch worsens to 0.7306. Focused structural graph tests, opt-in thrombosis probe, and accepted-utterance diagnostic passed under normal verbosity.","claim":"Closure pressure now participates in the graph path instead of acting as a decorative source pulse. This is the research-backed ownership cut, but it is not speech parity: contact release reaches radiation, while active-frame duration, output balance, and articulation shape remain weak. Next work should inspect contact filtering/duration or explicit utterance/radiation balance, not restore generic drive or global gain.","timestamp":"2026-05-29T02:30:00+01:00","topic":"graph-owned-closure-reservoir"}
|
||||
{"date":"2026-05-29","area":"acoustic-graph","summary":"After graph-owned closure release moved into two-port scattering, thrombosis probe energy reaches lip radiation but accepted utterance parity still fails. The missing contracts are not more release gain: boundary/source impedance remain heuristic rather than port laws, contact is still a scalar pulse instead of constrained-flow history, a node pressure fallback survives for unconnected multi-port nodes, and loss/gesture motion are not yet graph-owned enough.","evidence":"docs/acoustic-graph-missing-pieces-audit.md; artifacts/parity/pink-trombone-graph-thrombosis-probes/20260529T021934812; artifacts/parity/pink-trombone-utterance-logmel/20260529T022214016"}
|
||||
{"date":"2026-05-29","area":"acoustic-graph","summary":"Radiation boundaries now feed load back into the graph by filtering reflected boundary waves through a named boundary-load term before the outgoing wave returns to the delay line. The remaining unconnected multi-port node pressure fallback was cut and replaced with area-scattering plus node area-energy probes. Native PT probes still fail accepted utterance articulation, so this is a coherence repair: contact constrained-flow history and source impedance port laws remain the next missing owners.","evidence":"docs/acoustic-graph-dsp-audit.md; artifacts/parity/pink-trombone-graph-thrombosis-probes/20260529T112805836; artifacts/parity/pink-trombone-utterance-logmel/20260529T112806745"}
|
||||
{"date":"2026-05-29","area":"acoustic-graph","summary":"Generated tract area terminals are geometry Junctions again, while generated contact terminals are a sparse four-section overlay that owns closure pressure storage/release. The eight-contact plus inline-occlusion trial overflowed native Faust debug compile; the four-contact release-only owner passes structural graph tests, the opt-in thrombosis graph probe, and accepted-utterance diagnostics. This exposes rather than fixes the remaining gap: only the lip-end contact closes in thrombosis, and accepted utterances still fail articulation/silence metrics.","evidence":"docs/acoustic-graph-dsp-audit.md; artifacts/parity/pink-trombone-graph-thrombosis-probes/20260529T122217729; artifacts/parity/pink-trombone-utterance-logmel/20260529T122409541"}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ live_invariants:
|
|||
- Graph voice repair pass on 2026-05-28 fixed four model-level ownership leaks: glottal excitation is source-normalized with local `tanh`; segment propagation loss is area-dependent so closures absorb instead of ringing forever; generated nasal side-port area maps velum diameter squared directly instead of through the old hidden 0.15 damper; generated tract lips use live path-end geometry as the aperture owner and no longer double-gate radiation opening/boundary flow. Utterance artifact `artifacts/parity/pink-trombone-utterance-logmel/20260528T070759312` passes smoke and no longer collapses `mama/papa` (`referenceLogMel=0.3791`, `candidateLogMel=0.3651`); `thrombosis` improves to cosine 0.4366 but remains weak/quiet. Static artifact `artifacts/parity/pink-trombone-logmel/20260528T071240442` passes with `closure-release` demoted to sealed-static evidence (`peak=0.000005`). Next pressure is true graph-native closure reservoir/release through the scattering path.
|
||||
- `docs/acoustic-graph-dsp-audit.md` is the current Jenga audit for graph voice DSP. It says the path graph, typed terminals, KL/PT two-port scatter, source/topology separation, velum side-port area, generated lip geometry ownership, area-dependent segment loss, and utterance separability should stay. The first audit cut replaced the generic connection fallback pressure/admittance blend and PT-shaped three-port branch recognizer with one passive N-port area-scattering law for all non-bypass connection groups; emitted Faust no longer contains `graph_connection_pressure_*` for graph connections. The second audit cut moved graph radiation color/admittance into one named local primitive with emitted `graph_radiation_reference_area_*`, `graph_radiation_differentiation_*`, `graph_radiation_highpass_*`, `graph_radiation_admittance_*`, and `graph_radiation_flow_*` signals instead of inline `30/70` and `area + 1.0` expressions. The third audit cut hoisted graph turbulence/release into named per-source `_closure`, `_release`, `_reservoir`, `_reservoir_drive`, `_pressure_drive`, `_release_pressure`, `_noise_gate`, `_release_gate`, `_sustained`, `_burst_noise`, and `_release_pulse` locals. Reservoir charging now uses directed upstream-minus-downstream pressure for ordinary two-port path nodes and positive local incident pressure as fallback; latest artifacts `artifacts/parity/pink-trombone-utterance-logmel/20260528T115452268` and `artifacts/parity/pink-trombone-logmel/20260528T115719882` still show no metric movement. This points away from source-local reservoir charging and toward missing contact-aware closure state that participates in scattering/flow. Remaining suspect owners are unowned segment loss constant, still-empirical radiation/source constants, nearest-node source attachment, and missing contact-aware closure state.
|
||||
- Graph source lowering now names per-node incident pressure and node-local source sums inside the recursive graph loop. Generated tract injection source banks now use cell-centered positions and `1 / sections` index scaling, so turbulence/release energy is born inside tube cells rather than directly on graph/radiation nodes. Latest source-position artifact under `artifacts/parity/pink-trombone-utterance-logmel/20260527T172949293`: mama/papa/thrombosis cosine 0.6654/0.7746/0.5522, rmsRatio 3.0010/2.5712/2.4943, articulation 0.1444/0.1177/0.1193. Static closure-release RMS improved to 1.0078 under `artifacts/parity/pink-trombone-logmel/20260527T172843945`, but papa articulation worsened; keep the cell-centered source placement because it is the correct graph-level source geometry, not because metrics liked it.
|
||||
- Source ports now have an explicit `impedance`/`load` control and graph lowering uses node incident pressure to make glottal, labial/syrinx, reed, click, synthetic, and turbulence sources load-aware. Generated tract area terminals are now `Contact` terminals, with named graph-owned `graph_contact_*_closure`, `_reservoir`, and `_release` signals so closure pressure storage is no longer only a turbulence-source trick. `patches/advanced/bird-syrinx.aqua` is the first checked-in differentiable syrinx patch: paired labial source ports, bronchial paths, a tracheal path, an area-scattering merge, and beak radiation, all through `AcousticPortNetwork`.
|
||||
- Source ports now have an explicit `impedance`/`load` control and graph lowering uses node incident pressure to make glottal, labial/syrinx, reed, click, synthetic, and turbulence sources load-aware. Generated tract area terminals are `Junction` geometry owners again; generated `voices_0_contact_*` terminals are a sparse contact overlay capped at four interior sections, with named graph-owned `graph_contact_*_closure`, `_reservoir`, and `_release` signals so closure pressure storage is no longer either every area sample or only a turbulence-source trick. Eight generated contacts plus inline occlusion overflowed the native debug Faust compile; four sparse contacts pass the opt-in thrombosis graph probe. `patches/advanced/bird-syrinx.aqua` is the first checked-in differentiable syrinx patch: paired labial source ports, bronchial paths, a tracheal path, an area-scattering merge, and beak radiation, all through `AcousticPortNetwork`.
|
||||
- TurbulenceJet now includes a release-timed burst-noise component in addition to the deterministic pressure pulse, but a stronger trial barely moved papa; the source is not the main remaining articulation bottleneck. Graph radiation now mixes 30% raw boundary flow with 70% high-passed flow after local admittance weighting, down from the over-bright 15/85 blend. Latest radiation/source artifact under `artifacts/parity/pink-trombone-utterance-logmel/20260527T174236049`: mama/papa/thrombosis cosine 0.6578/0.7692/0.5585, rmsRatio 3.0006/2.6153/2.3488, articulation 0.1437/0.1173/0.1191. Static `closure-release` under `artifacts/parity/pink-trombone-logmel/20260527T174139661` has rmsRatio 0.9900 and speechBandRatio 0.0842. This is still not speaking; next pressure is true tract resonance/passive scattering and pressure storage, not more burst gain.
|
||||
- Same-path two-port area discontinuities now emit `graph_area_energy_in_*` and `graph_area_energy_out_*` probes alongside the three-port branch `graph_connection_energy_*` probes. Use these to inspect passivity and formant-body failures at the scatter sites rather than judging only final output loudness.
|
||||
- `FaustExportOptions.DebugProbeUi` wraps graph probe signals in Faust `vbargraph` UI controls under `/debug/...` without changing audio output arity. Native streaming Faust patches now separate writable controls from read-only probe zones and can read/snapshot probe values after `ProcessBlock`; use this for acoustic graph passivity/radiation inspection, leave it off for normal parity renders.
|
||||
|
|
|
|||
|
|
@ -133,7 +133,9 @@ public sealed class PatchScriptTests
|
|||
Assert.Contains(patch.AcousticSourcePorts, port => port.Name.StartsWith("voices_0_sibilant_", StringComparison.Ordinal) && port.Kind == AcousticSourceKind.TurbulenceJet);
|
||||
Assert.Contains(patch.AcousticBranches, branch => branch.Name == "voices_0_nose" && branch.Kind == AcousticBranchKind.Nasal);
|
||||
Assert.Contains(patch.AcousticRadiationPorts, port => port.Name == "voices_0_lip" && port.Kind == AcousticRadiationKind.Lip);
|
||||
Assert.Contains(patch.AcousticTerminals, terminal => terminal.Name.StartsWith("voices_0_area_", StringComparison.Ordinal) && terminal.Kind == AcousticTerminalKind.Contact);
|
||||
Assert.Contains(patch.AcousticTerminals, terminal => terminal.Name.StartsWith("voices_0_area_", StringComparison.Ordinal) && terminal.Kind == AcousticTerminalKind.Junction);
|
||||
Assert.Contains(patch.AcousticTerminals, terminal => terminal.Name.StartsWith("voices_0_contact_", StringComparison.Ordinal) && terminal.Kind == AcousticTerminalKind.Contact);
|
||||
Assert.True(patch.AcousticTerminals.Count(terminal => terminal.Name.StartsWith("voices_0_contact_", StringComparison.Ordinal)) <= 4);
|
||||
Assert.Contains(patch.WaveClocks, clock => clock.Name == "voices_0_clock" && clock.Strategy == WaveClockDelayStrategy.FractionalLinear);
|
||||
Assert.Contains(patch.ParameterBindings, binding => binding.FieldPath == "/glottis/0/tenseness");
|
||||
|
||||
|
|
@ -144,7 +146,7 @@ public sealed class PatchScriptTests
|
|||
Assert.Contains("graph_source_voices_0_sibilant_", faust);
|
||||
Assert.Contains("graph_terminal_area_voices_0_area_", faust);
|
||||
Assert.Contains("graph_connection_reflection_voices_0_nose_connection", faust);
|
||||
Assert.Contains("graph_contact_voices_0_area_", faust);
|
||||
Assert.Contains("graph_contact_voices_0_contact_", faust);
|
||||
Assert.Contains("* 0.80", faust);
|
||||
Assert.Contains("* 0.20", faust);
|
||||
Assert.Contains("de.fdelay", faust);
|
||||
|
|
|
|||
Loading…
Reference in a new issue