Drive closure reservoir from path pressure
This commit is contained in:
parent
5e3d4f2ecc
commit
497bf72bbc
5 changed files with 55 additions and 5 deletions
|
|
@ -444,3 +444,24 @@ metrics did not move:
|
|||
Keep the sign fix. The non-result strengthens the diagnosis: the real missing
|
||||
primitive is still a contact-aware upstream/downstream closure state, not a
|
||||
source-local scalar reservoir.
|
||||
|
||||
## 2026-05-28 Directed Reservoir Drive
|
||||
|
||||
For turbulence/release sources attached to ordinary two-port path nodes, the
|
||||
reservoir now charges from directed upstream-minus-downstream pressure:
|
||||
|
||||
`max(0, upstream_incoming - downstream_incoming)`
|
||||
|
||||
Boundary or non-two-port source nodes fall back to positive local incident
|
||||
pressure. This lets a source-local plosive at least read the graph's traveling
|
||||
wave direction instead of only a node-average pressure.
|
||||
|
||||
Latest utterance artifact:
|
||||
`artifacts/parity/pink-trombone-utterance-logmel/20260528T115452268`.
|
||||
Latest static artifact:
|
||||
`artifacts/parity/pink-trombone-logmel/20260528T115719882`.
|
||||
|
||||
Metrics still do not move. That is useful and damning: the source-local
|
||||
reservoir sign/direction is no longer the main missing piece. The graph needs a
|
||||
contact/closure primitive that participates in scattering and flow, not a
|
||||
separate source pulse hoping the node will turn it into articulation.
|
||||
|
|
|
|||
|
|
@ -721,7 +721,7 @@ public static class FaustEmitter
|
|||
: $"({string.Join(" + ", ports.Select(port => GraphIncoming(name, port)))}) / {F(ports.Count)}";
|
||||
var incidentName = $"{name}_graph_node_incident_pressure_{node.Name}";
|
||||
var nodeSourceName = NodeSourceIdentifier(name, node);
|
||||
var nodeSourceExpression = EmitNodeSourceExpression(source, patch, name, node, sources, frequency, parameters);
|
||||
var nodeSourceExpression = EmitNodeSourceExpression(source, patch, name, node, incident[node.Name], sources, frequency, parameters);
|
||||
source.AppendLine($" {incidentName} = {ProbeSignal(options, $"/debug/{name}/node/{node.Name}/incident_pressure", incidentPressure, -2, 2)};");
|
||||
source.AppendLine($" {nodeSourceName} = {ProbeSignal(options, $"/debug/{name}/node/{node.Name}/source", nodeSourceExpression, -2, 2)};");
|
||||
debugProbeKeepAlive.Add(incidentName);
|
||||
|
|
@ -1800,6 +1800,7 @@ public static class FaustEmitter
|
|||
SynthPatch patch,
|
||||
string voiceName,
|
||||
AcousticGraphNode node,
|
||||
IReadOnlyList<AcousticGraphPort> nodePorts,
|
||||
IReadOnlyDictionary<string, AcousticSourcePort> sources,
|
||||
string frequency,
|
||||
ParameterMap parameters)
|
||||
|
|
@ -1811,7 +1812,7 @@ public static class FaustEmitter
|
|||
var sourceName = terminal.Port.Length == 0 ? terminal.Name : terminal.Port;
|
||||
var port = sources[sourceName];
|
||||
return port.Kind == AcousticSourceKind.TurbulenceJet
|
||||
? EmitGraphTurbulenceSourceExpression(source, patch, voiceName, node, sourceName, port, parameters)
|
||||
? EmitGraphTurbulenceSourceExpression(source, patch, voiceName, node, nodePorts, sourceName, port, parameters)
|
||||
: $"{voiceName}_graph_source_{SafeIdentifier(sourceName)}";
|
||||
})
|
||||
.ToList();
|
||||
|
|
@ -1823,6 +1824,7 @@ public static class FaustEmitter
|
|||
SynthPatch patch,
|
||||
string voiceName,
|
||||
AcousticGraphNode node,
|
||||
IReadOnlyList<AcousticGraphPort> nodePorts,
|
||||
string sourceName,
|
||||
AcousticSourcePort port,
|
||||
ParameterMap parameters)
|
||||
|
|
@ -1838,10 +1840,12 @@ public static class FaustEmitter
|
|||
var noise = $"clip01({parameters.Expression(OwnerField(path, "noise"), port.Noise)})";
|
||||
var transient = $"clip01({parameters.Expression(OwnerField(path, "transient"), port.Transient)})";
|
||||
var balance = $"({parameters.Expression(OwnerField(path, "balance"), port.Balance)}) * ({SourcePositionWeightExpression(port, path, parameters)})";
|
||||
var reservoirDrive = ClosureReservoirDriveExpression(voiceName, node, nodePorts, port, localPressure);
|
||||
|
||||
source.AppendLine($" {prefix}_closure = clip01((0.12 - ({opening})) / 0.12);");
|
||||
source.AppendLine($" {prefix}_release = (max(0.0, ({prefix}_closure : mem) - {prefix}_closure) : + ~ *(0.995));");
|
||||
source.AppendLine($" {prefix}_reservoir = (max(0.0, {localPressure}) * {prefix}_closure) : + ~ *(0.992);");
|
||||
source.AppendLine($" {prefix}_reservoir_drive = {reservoirDrive};");
|
||||
source.AppendLine($" {prefix}_reservoir = {prefix}_reservoir_drive * {prefix}_closure : + ~ *(0.992);");
|
||||
source.AppendLine($" {prefix}_pressure_drive = 0.50 + 1.50 * clip01(abs({localPressure}));");
|
||||
source.AppendLine($" {prefix}_release_pressure = 0.20 + 2.80 * clip01({prefix}_reservoir);");
|
||||
source.AppendLine($" {prefix}_noise_gate = min(clip01((0.85 - ({opening})) / 0.85), clip01(25.0 * (({opening}) - 0.04)));");
|
||||
|
|
@ -1854,6 +1858,29 @@ public static class FaustEmitter
|
|||
return $"{prefix}_out";
|
||||
}
|
||||
|
||||
private static string ClosureReservoirDriveExpression(
|
||||
string voiceName,
|
||||
AcousticGraphNode node,
|
||||
IReadOnlyList<AcousticGraphPort> nodePorts,
|
||||
AcousticSourcePort sourcePort,
|
||||
string fallbackPressure)
|
||||
{
|
||||
var samePathPorts = nodePorts
|
||||
.Where(port => port.Segment.Path.Name.Equals(sourcePort.Path, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
var upstream = samePathPorts
|
||||
.Where(port => !port.AtStart && port.Segment.EndPosition <= node.Position + 0.0001f)
|
||||
.OrderByDescending(port => port.Segment.StartPosition)
|
||||
.FirstOrDefault();
|
||||
var downstream = samePathPorts
|
||||
.Where(port => port.AtStart && port.Segment.StartPosition >= node.Position - 0.0001f)
|
||||
.OrderBy(port => port.Segment.EndPosition)
|
||||
.FirstOrDefault();
|
||||
return upstream is not null && downstream is not null
|
||||
? $"max(0.0, {GraphIncoming(voiceName, upstream)} - {GraphIncoming(voiceName, downstream)})"
|
||||
: $"max(0.0, {fallbackPressure})";
|
||||
}
|
||||
|
||||
private static string GraphIncoming(string voiceName, AcousticGraphPort port) =>
|
||||
port.AtStart
|
||||
? $"{voiceName}_graph_in_{port.Segment.Index}_start"
|
||||
|
|
|
|||
|
|
@ -200,3 +200,4 @@
|
|||
{"evidence":"Moved graph radiation output coloring and admittance constants into a named local radiation primitive in `FaustExport`: emitted graph Faust now names `graph_radiation_reference_area_*`, `graph_radiation_differentiation_*`, `graph_radiation_highpass_*`, `graph_radiation_admittance_*`, and `graph_radiation_flow_*` instead of inlining the old `flow * 0.30 + highpass(flow) * 0.70` and `area + 1.0` expressions. Focused structural/Faust checks, accepted utterance smoke, and static PT graph smoke passed. Latest utterance artifact `artifacts/parity/pink-trombone-utterance-logmel/20260528T113949841`: mama/papa/thrombosis cosine 0.7648/0.8550/0.4556, mama/papa candidate separability 0.2044 versus reference 0.3791. Latest static artifact `artifacts/parity/pink-trombone-logmel/20260528T113949813` passes with sealed-static closure peak 0.000011.","claim":"Radiation color was unowned inline math. It now has a single local primitive, but articulation did not materially improve, so the live audible failure is still closure pressure storage/source impedance rather than boundary coloring alone.","timestamp":"2026-05-28T12:05:00+01:00","topic":"acoustic-graph-radiation-primitive-cut"}
|
||||
{"evidence":"Hoisted graph turbulence/release source lowering into named Faust locals per source/node: `_closure`, `_release`, `_reservoir`, `_pressure_drive`, `_release_pressure`, `_noise_gate`, `_release_gate`, `_sustained`, `_burst_noise`, and `_release_pulse`. Fixed the emission order so helper locals are written before the node-source assignment. Focused structural/Faust checks, accepted utterance smoke, and static PT graph smoke passed. Latest utterance artifact `artifacts/parity/pink-trombone-utterance-logmel/20260528T114618213`; latest static artifact `artifacts/parity/pink-trombone-logmel/20260528T114618202`. Metrics match the prior radiation pass.","claim":"Closure/release pressure is now inspectable at the graph-source layer instead of buried in one expression. This is not yet true contact-aware plosive modeling; the next real change is to replace the source-local reservoir/source-impedance law with a graph/contact-owned upstream-downstream pressure model.","timestamp":"2026-05-28T12:20:00+01:00","topic":"acoustic-graph-source-reservoir-naming"}
|
||||
{"evidence":"Changed graph source-local closure reservoir charging from `abs(incident_pressure) * closure` to `max(0, incident_pressure) * closure`, so alternating negative pressure no longer charges a plosive reservoir. Accepted utterance smoke and static PT graph smoke passed. Latest utterance artifact `artifacts/parity/pink-trombone-utterance-logmel/20260528T114903720`; latest static artifact `artifacts/parity/pink-trombone-logmel/20260528T114953503`. Metrics did not move from the reservoir-naming pass.","claim":"Plosive storage should charge from compression, not rectified vibration. The lack of metric movement says the current audible failure is not the reservoir sign alone; Aqua still needs a contact-aware upstream/downstream closure state and source impedance instead of only a source-local scalar reservoir.","timestamp":"2026-05-28T12:55:00+01:00","topic":"acoustic-graph-positive-pressure-reservoir"}
|
||||
{"evidence":"Changed graph turbulence/release reservoir drive to use directed upstream-minus-downstream pressure at ordinary two-port path nodes (`max(0, upstream_incoming - downstream_incoming)`), with positive local incident pressure as the fallback for boundaries or more complex nodes. Focused structural/Faust checks, accepted utterance smoke, and static PT graph smoke passed. Latest utterance artifact `artifacts/parity/pink-trombone-utterance-logmel/20260528T115452268`; latest static artifact `artifacts/parity/pink-trombone-logmel/20260528T115719882`. Metrics still did not move.","claim":"Source-local reservoir direction is no longer the main explanation for weak plosives. The graph needs a contact/closure primitive that participates in scattering and flow, rather than a separate source pulse injected after the node law.","timestamp":"2026-05-28T13:05:00+01:00","topic":"acoustic-graph-directed-reservoir-drive"}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
project: AquaSynth
|
||||
spine_version: 1
|
||||
updated: 2026-05-28T12:55:00+01:00
|
||||
updated: 2026-05-28T13:05:00+01:00
|
||||
|
||||
prime_directive: >
|
||||
Build coherent synth machinery. References exist to reveal missing structure,
|
||||
|
|
@ -125,7 +125,7 @@ live_invariants:
|
|||
- PT utterance metrics now include cross-utterance separability because log-mel parity alone hid the user's actual listening failure. Artifact `artifacts/parity/pink-trombone-utterance-logmel/20260527T225833392` shows `mama/papa` candidate collapse: reference log-mel similarity 0.3791 versus candidate 0.6069, with candidate envelope similarity 0.8885. Interior source terminals no longer decide topology or node area/reflection; they attach to existing graph nodes and inject energy, while non-source terminals own geometry. Keep this source/topology cut even if other broken layers get louder.
|
||||
- Generated lip radiation terminals no longer bake first-frame lip opening into terminal `area_scale`; lip opening owns live path area plus radiation aperture. This removes a stale initial-state authority where words starting with closed lips kept closed-lip admittance. Static PT graph artifact `artifacts/parity/pink-trombone-logmel/20260527T231611586` passes, while utterance artifact `artifacts/parity/pink-trombone-utterance-logmel/20260527T231056242` still fails `mama/papa` collapse and silent `thrombosis`. Next work remains source/reservoir/radiation coupling, not restoring terminal-scale double gates.
|
||||
- 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`, `_pressure_drive`, `_release_pressure`, `_noise_gate`, `_release_gate`, `_sustained`, `_burst_noise`, and `_release_pulse` locals. Reservoir charging now uses positive local pressure (`max(0, incident_pressure)`) instead of `abs(incident_pressure)`; latest artifacts `artifacts/parity/pink-trombone-utterance-logmel/20260528T114903720` and `artifacts/parity/pink-trombone-logmel/20260528T114953503` show no metric movement, which points away from sign convention and toward the lack of a true upstream/downstream closure-contact reservoir. Remaining suspect owners are unowned segment loss constant, still-empirical radiation/source constants, nearest-node source attachment, and missing contact-aware closure state.
|
||||
- `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.
|
||||
- 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.
|
||||
|
|
|
|||
|
|
@ -727,6 +727,7 @@ public sealed class PatchScriptTests
|
|||
Assert.Contains("acoustic_graph_radiated", export.Source);
|
||||
Assert.Contains("graph_terminal_area_voices_0_area_", export.Source);
|
||||
Assert.Contains("graph_source_", export.Source);
|
||||
Assert.Contains("_reservoir_drive", export.Source);
|
||||
Assert.Contains("_reservoir", export.Source);
|
||||
Assert.Contains("_release_pulse", export.Source);
|
||||
Assert.DoesNotContain("wg_diameter_target_", export.Source);
|
||||
|
|
|
|||
Loading…
Reference in a new issue