From d8a33f7e6bf0dbe5d3e012b136372ade456caacd Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 29 May 2026 01:57:38 +0100 Subject: [PATCH] Bound PT utterance render diagnostics --- src/AquaSynth.Faust/FaustCompiler.cs | 16 ++++++++-- state/evidence.jsonl | 1 + state/scratch.md | 24 +++++++++++++++ .../PinkTromboneLogMelParityTests.cs | 30 ++++++++++++++----- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/AquaSynth.Faust/FaustCompiler.cs b/src/AquaSynth.Faust/FaustCompiler.cs index 8ec7f4a..5efaf92 100644 --- a/src/AquaSynth.Faust/FaustCompiler.cs +++ b/src/AquaSynth.Faust/FaustCompiler.cs @@ -284,9 +284,19 @@ public static class FaustCompiler foreach (var argument in arguments) start.ArgumentList.Add(argument); using var process = Process.Start(start) ?? throw new InvalidOperationException($"failed to start `{fileName}`"); - var stdout = process.StandardOutput.ReadToEndAsync(cancellationToken); - var stderr = process.StandardError.ReadToEndAsync(cancellationToken); - await process.WaitForExitAsync(cancellationToken); + var stdout = process.StandardOutput.ReadToEndAsync(); + var stderr = process.StandardError.ReadToEndAsync(); + try + { + await process.WaitForExitAsync(cancellationToken); + } + catch (OperationCanceledException) when (!process.HasExited) + { + process.Kill(entireProcessTree: true); + await process.WaitForExitAsync(CancellationToken.None); + throw; + } + return (process.ExitCode, await stdout, await stderr); } } diff --git a/state/evidence.jsonl b/state/evidence.jsonl index 3eea345..1cdd3d0 100644 --- a/state/evidence.jsonl +++ b/state/evidence.jsonl @@ -215,3 +215,4 @@ {"evidence":"A visual review of the Warbling White-eye comparison showed the previous best candidate still failed the reference: its contours were piecewise straight and its harmonic ladder was too strong. Added `interp=smooth` control curves lowered to Faust `seg_smooth` smoothstep segments, then rerendered the Warbling White-eye audition with smooth pressure/opening/tension/stiffness gestures and a low-drive single-labium candidate. `artifacts/listening/warbling-white-eye-20260528T220500961/06-smooth-low-drive.compare.png` now shows curved motif contours and much weaker harmonics, though it is still only a rough birdlike gesture, not a species-quality match.","claim":"Smooth realtime gesture semantics are required for vocal modeling. Straight spectral contours are often authored linear control curves leaking through the physical model, so future bird/human fitting should use smooth motor gestures before adding morphology changes or spectral compensators.","timestamp":"2026-05-28T22:50:00+01:00","topic":"smooth-vocal-gestures"} {"evidence":"Created `research/vocal-source-grounding` with downloaded/captured references on MEAD source physics, syrinx modeling, two-mass vocal fold modeling, self-oscillating vocal fold experiments, Birkholz 2024 pressure losses, and Faust physical modeling primitives. The grounding pass found `drive` is currently split-brained: it scales reservoir pressure, phonation gate, and modal/displacement brightness. Literature points instead to pressure as energy input, tissue mass/stiffness/damping/collision as source morphology, aperture/area-dependent flow loss as pressure-flow shaping, and tract/radiation load as spectral/acoustic coupling.","claim":"The next valve-law cut should demote generic `drive` into a calibration/compatibility alias, then make harmonic richness and ease of oscillation emerge from explicit morphology, pressure-flow loss, collision/contact, damping, and graph load rather than a timbre rescue knob.","timestamp":"2026-05-28T23:12:00+01:00","topic":"vocal-source-grounding"} {"evidence":"Demoted graph tissue-valve `drive` from split-brained vocal authority into a parser compatibility alias for `flow_scale`, added explicit `flow_scale`, `tissue_loss`, `aperture_shape`, and `flow_loss` source-port fields, and changed Faust graph lowering so reservoir pressure is pressure-owned while oscillation threshold/Q, velocity decay, aperture law, and pressure-flow resistance come from physical morphology/load controls. Canonical human, bird, and alien graph patches now use the new fields. Focused parser/export/render tests passed, class-sliced non-PT suites passed, and fresh Warbling White-eye audition artifacts were written under `artifacts/listening/warbling-white-eye-20260529T002500-drive-demotion`. The PT accepted-utterance diagnostic renderer is unstable in this run: the mama artifact writes, then the testhost exits with code -1 before reporting a managed assertion.","claim":"Graph vocal source energy, threshold, and harmonic behavior now have separate inspectable owners. Future bird/human tuning should move through pressure, stiffness/tension, damping/tissue loss, aperture/flow resistance, collision, radiation, and graph load instead of reviving a generic vocal drive knob. The next cleanup should inspect the remaining low-frequency flow floor/radiation normalization and the PT diagnostic testhost crash, not use the crash as permission to restore a generic drive knob.","timestamp":"2026-05-29T00:20:00+01:00","topic":"graph-tissue-valve-drive-demotion"} +{"evidence":"Rechecked the PT accepted-utterance diagnostic after clearing stale child `dotnet` processes. The focused test passes with enough wall-clock budget; fresh artifact `artifacts/parity/pink-trombone-utterance-logmel/20260529T005420700` records render timings of about 31s for mama, 45s for papa, and 59s for thrombosis. `PinkTromboneAcceptedUtterancesReportGraphLogMelParityWhenFaustIsInstalled` now writes generated DSP/control artifacts before rendering, applies a three-minute per-utterance cancellation budget, and writes render stdout/stderr/timing. `FaustCompiler.RunAsync` now kills the entire child process tree when cancellation fires. Focused PT utterance plus graph Faust validation/render tests passed: 3 tests in 2m17s.","claim":"The previous PT testhost failure is not currently a reproducible managed graph-source crash; the real process smell was unbounded external Faust/dotnet render work with poor pre-crash artifacts. Current acoustic evidence points to underpowered/weakly articulated radiated flow, not a loud low-frequency floor, so next tuning should use graph probes rather than restore the generic drive authority.","timestamp":"2026-05-29T01:00:00+01:00","topic":"pt-utterance-process-observability"} diff --git a/state/scratch.md b/state/scratch.md index 271a7ec..ec7ed8d 100644 --- a/state/scratch.md +++ b/state/scratch.md @@ -2,6 +2,30 @@ Current slice: +- PT utterance diagnostic crash recheck: the focused test is reproducible as + slow but passing when stale child `dotnet` processes are cleared and the test + is run with enough wall-clock budget. Fresh verified artifact: + `artifacts/parity/pink-trombone-utterance-logmel/20260529T005420700`. + Per-utterance render timing now writes `render.txt` beside each candidate + before/after the Faust render path: `mama` ~31s, `papa` ~45s, `thrombosis` + ~59s. The previous two-minute attached shell timeout was not a valid crash + witness. +- Harness/process fix: `PinkTromboneAcceptedUtterancesReportGraphLogMelParityWhenFaustIsInstalled` + now writes `candidate-graph.dsp` and `controls.csv` before rendering, wraps + each external Faust render in a three-minute per-utterance timeout, and writes + stdout/stderr/timing to `render.txt`. `FaustCompiler.RunAsync` now kills the + whole child process tree when cancellation fires, so timed-out `faust` or + nested `dotnet run` work cannot keep poisoning later runs. +- Current acoustic evidence after the source-law cleanup is weakness, not a + loud low-frequency floor: latest utterance RMS ratios are `mama` 0.0876, + `papa` 0.1509, `thrombosis` 0.0673. `thrombosis` still fails the diagnostic + cosine floor with cosine 0.3318. Next vocal work should inspect source-flow + strength/articulation and radiation transfer with debug probes, not restore a + generic `drive` knob. +- Verification: + `dotnet test tests\AquaSynth.Dsl.Tests\AquaSynth.Dsl.Tests.csproj --no-restore --disable-build-servers -p:UseSharedCompilation=false -p:BuildInParallel=false --filter "PinkTromboneAcceptedUtterancesReportGraphLogMelParityWhenFaustIsInstalled|FaustCompilerRendersTissueValveGraphWhenInstalled|FaustCompilerValidatesAcousticPathGraphWhenInstalled" -v minimal` + passed: 3 tests in 2m17s. + - Research-guided machine cut: graph segment delay no longer clamps physical segment delay to a full sample. `WaveClockPolicy` now owns the minimum legal delay: unit grid stays at 1 sample, half-sample grid and first-order Thiran diff --git a/tests/AquaSynth.Dsl.Tests/PinkTromboneLogMelParityTests.cs b/tests/AquaSynth.Dsl.Tests/PinkTromboneLogMelParityTests.cs index e2618d4..293e8ab 100644 --- a/tests/AquaSynth.Dsl.Tests/PinkTromboneLogMelParityTests.cs +++ b/tests/AquaSynth.Dsl.Tests/PinkTromboneLogMelParityTests.cs @@ -1,4 +1,5 @@ using System.Globalization; +using System.Diagnostics; using System.Text; namespace AquaSynth.Dsl.Tests; @@ -111,9 +112,27 @@ public sealed class PinkTromboneLogMelParityTests { var reference = referenceRenderer.RenderUtterance(fixture.Id, fixture.ControlPoints, fixture.DurationSeconds); var source = AutomatedGraphSource(fixture); - var candidate = await FaustCompiler.RenderAsync( - source, - new FaustRenderOptions(reference.SampleRate, reference.Samples.Length / (float)reference.SampleRate)); + var fixtureDir = Path.Combine(artifactDir, fixture.Id); + Directory.CreateDirectory(fixtureDir); + File.WriteAllText(Path.Combine(fixtureDir, "candidate-graph.dsp"), source); + File.WriteAllText(Path.Combine(fixtureDir, "controls.csv"), UtteranceControlCsv(fixture)); + + var stopwatch = Stopwatch.StartNew(); + using var renderTimeout = new CancellationTokenSource(TimeSpan.FromMinutes(3)); + FaustRender? candidate; + try + { + candidate = await FaustCompiler.RenderAsync( + source, + new FaustRenderOptions(reference.SampleRate, reference.Samples.Length / (float)reference.SampleRate), + cancellationToken: renderTimeout.Token); + } + catch (OperationCanceledException) + { + Assert.Fail($"Faust render timed out for `{fixture.Id}` after {stopwatch.Elapsed.TotalSeconds:0.0}s; artifacts: {fixtureDir}"); + return; + } + stopwatch.Stop(); Assert.NotNull(candidate); Assert.True(candidate.Samples.Length > 0, $"{candidate.Stderr}{Environment.NewLine}artifacts: {artifactDir}"); @@ -124,13 +143,10 @@ public sealed class PinkTromboneLogMelParityTests var report = UtteranceReport(fixture, comparison); reports.Add(report); - var fixtureDir = Path.Combine(artifactDir, fixture.Id); - Directory.CreateDirectory(fixtureDir); WriteWav(Path.Combine(fixtureDir, "reference-pink-trombone.wav"), reference.Samples, reference.SampleRate); WriteWav(Path.Combine(fixtureDir, "candidate-graph.wav"), candidate.Samples, candidate.SampleRate); - File.WriteAllText(Path.Combine(fixtureDir, "candidate-graph.dsp"), source); File.WriteAllText(Path.Combine(fixtureDir, "report.txt"), report); - File.WriteAllText(Path.Combine(fixtureDir, "controls.csv"), UtteranceControlCsv(fixture)); + File.WriteAllText(Path.Combine(fixtureDir, "render.txt"), $"seconds={stopwatch.Elapsed.TotalSeconds:0.000}{Environment.NewLine}stdout:{Environment.NewLine}{candidate.Stdout}{Environment.NewLine}stderr:{Environment.NewLine}{candidate.Stderr}"); if (comparison.LogMelCosineSimilarity < UtteranceGraphSmokeCosineFloors.GetValueOrDefault(fixture.Id, 0.1f)) {