Keep song scoring alive on invalid candidates
This commit is contained in:
parent
e78771872b
commit
e1a3ca5bbf
2 changed files with 45 additions and 31 deletions
|
|
@ -213,16 +213,8 @@ static async Task SongScoreAsync(Dictionary<string, string> options)
|
|||
var scriptCopy = Path.Combine(candidateDir, "candidate.aqua");
|
||||
File.Copy(candidate.ScriptPath, scriptCopy, overwrite: true);
|
||||
var script = await File.ReadAllTextAsync(scriptCopy, Encoding.UTF8);
|
||||
var patch = PatchScript.Parse(script);
|
||||
var timelineNetwork = patch.VocalNetworks.FirstOrDefault();
|
||||
var timeline = timelineNetwork is null
|
||||
? Array.Empty<ProbeTimelineSample>()
|
||||
: ProbeTimelineReport.Build(patch, timelineNetwork.Name, 12);
|
||||
var timelinePath = Path.Combine(timelineRoot, $"{safeCandidateId}.csv");
|
||||
await File.WriteAllTextAsync(timelinePath, ProbeTimelineReport.ToCsv(timeline), Encoding.UTF8);
|
||||
var source = FaustEmitter.EmitScript(script, new FaustExportOptions(safeCandidateId)).Source;
|
||||
var dspPath = Path.Combine(candidateDir, "candidate.dsp");
|
||||
await File.WriteAllTextAsync(dspPath, source, Encoding.UTF8);
|
||||
|
||||
var candidateWav = Path.Combine(audioDir, "candidate.wav");
|
||||
var metrics = new List<SpeechScoreMetric>();
|
||||
|
|
@ -231,39 +223,60 @@ static async Task SongScoreAsync(Dictionary<string, string> options)
|
|||
Artifact("song-challenge", challengePath),
|
||||
Artifact("reference-wav", challenge.ReferenceWavPath),
|
||||
Artifact("candidate-script", scriptCopy),
|
||||
Artifact("candidate-dsp", dspPath),
|
||||
Artifact("primitive-timeline", timelinePath)
|
||||
};
|
||||
metrics.AddRange(SongTargetMetrics(challenge, challengeEvidence));
|
||||
artifacts.AddRange(SongChallengeArtifacts(challenge));
|
||||
artifacts.AddRange(challengeEvidence.Select(SongChallengeEvidenceArtifact));
|
||||
var timelineFacts = PrimitiveTimelineFactExtractor.Extract(timeline).ToArray();
|
||||
var timelineFacts = Array.Empty<PrimitiveTimelineFact>();
|
||||
string verdict;
|
||||
string evaluation;
|
||||
var render = await FaustCompiler.RenderAsync(
|
||||
source,
|
||||
new FaustRenderOptions(challenge.SampleRate, challenge.DurationSeconds));
|
||||
if (render is null || render.Samples.Length == 0)
|
||||
try
|
||||
{
|
||||
verdict = "render-failed";
|
||||
evaluation = render is null
|
||||
? "Faust was not available to render this song candidate."
|
||||
: $"Faust render produced no samples. stderr: {render.Stderr}";
|
||||
metrics.Add(new SpeechScoreMetric("render_failed", 1, 1));
|
||||
var patch = PatchScript.Parse(script);
|
||||
var timelineNetwork = patch.VocalNetworks.FirstOrDefault();
|
||||
var timeline = timelineNetwork is null
|
||||
? Array.Empty<ProbeTimelineSample>()
|
||||
: ProbeTimelineReport.Build(patch, timelineNetwork.Name, 12);
|
||||
await File.WriteAllTextAsync(timelinePath, ProbeTimelineReport.ToCsv(timeline), Encoding.UTF8);
|
||||
timelineFacts = PrimitiveTimelineFactExtractor.Extract(timeline).ToArray();
|
||||
var source = FaustEmitter.EmitScript(script, new FaustExportOptions(safeCandidateId)).Source;
|
||||
await File.WriteAllTextAsync(dspPath, source, Encoding.UTF8);
|
||||
artifacts.Add(Artifact("candidate-dsp", dspPath));
|
||||
|
||||
var render = await FaustCompiler.RenderAsync(
|
||||
source,
|
||||
new FaustRenderOptions(challenge.SampleRate, challenge.DurationSeconds));
|
||||
if (render is null || render.Samples.Length == 0)
|
||||
{
|
||||
verdict = "render-failed";
|
||||
evaluation = render is null
|
||||
? "Faust was not available to render this song candidate."
|
||||
: $"Faust render produced no samples. stderr: {render.Stderr}";
|
||||
metrics.Add(new SpeechScoreMetric("render_failed", 1, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
var matched = MatchLength(render.Samples, referenceSamples.Length);
|
||||
NormalizePeak(matched, .9f);
|
||||
WriteWav(candidateWav, matched, challenge.SampleRate);
|
||||
artifacts.Add(Artifact("candidate-wav", candidateWav));
|
||||
var comparison = analyzer.Compare(referenceSamples, matched);
|
||||
metrics.AddRange(SongComparisonMetrics(comparison));
|
||||
verdict = SongVerdict(comparison);
|
||||
evaluation = SongEvaluationSentence(challenge, comparison, verdict);
|
||||
var comparisonPath = Path.Combine(audioDir, "comparison.txt");
|
||||
await File.WriteAllTextAsync(comparisonPath, SongComparisonReport(challenge, candidate, comparison, verdict), Encoding.UTF8);
|
||||
artifacts.Add(Artifact("comparison-report", comparisonPath));
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception ex) when (ex is PatchScriptException or InvalidOperationException or InvalidDataException)
|
||||
{
|
||||
var matched = MatchLength(render.Samples, referenceSamples.Length);
|
||||
NormalizePeak(matched, .9f);
|
||||
WriteWav(candidateWav, matched, challenge.SampleRate);
|
||||
artifacts.Add(Artifact("candidate-wav", candidateWav));
|
||||
var comparison = analyzer.Compare(referenceSamples, matched);
|
||||
metrics.AddRange(SongComparisonMetrics(comparison));
|
||||
verdict = SongVerdict(comparison);
|
||||
evaluation = SongEvaluationSentence(challenge, comparison, verdict);
|
||||
var comparisonPath = Path.Combine(audioDir, "comparison.txt");
|
||||
await File.WriteAllTextAsync(comparisonPath, SongComparisonReport(challenge, candidate, comparison, verdict), Encoding.UTF8);
|
||||
artifacts.Add(Artifact("comparison-report", comparisonPath));
|
||||
await File.WriteAllTextAsync(timelinePath, ProbeTimelineReport.ToCsv([]), Encoding.UTF8);
|
||||
verdict = "render-failed";
|
||||
evaluation = $"Candidate could not be parsed, lowered, or prepared for render: {ex.GetType().Name}: {ex.Message}";
|
||||
metrics.Add(new SpeechScoreMetric("render_failed", 1, 1));
|
||||
metrics.Add(new SpeechScoreMetric("candidate_invalid", 1, 1));
|
||||
}
|
||||
|
||||
var latency = Stopwatch.GetElapsedTime(startedStamp).TotalMilliseconds;
|
||||
|
|
|
|||
|
|
@ -407,6 +407,7 @@ Instrument and DSL convention invention:
|
|||
- any Strudel-like sugar that would make the patch shorter;
|
||||
- the exact lowering into today's AquaSynth syntax using explicit `voice`, `param`, and `curve` lines.
|
||||
- The `.aqua` candidate must use today's implemented syntax only: `pattern`, `scale`, `param`, `curve`, and ordinary patch/voice syntax are legal. Proposed future sugar is evidence for the next DSL cut, not magic accepted by the parser.
|
||||
- Legal oscillator `wave=` values are `sine`, `square`, `saw`, `triangle`, and `noise` only. Use `square` plus filters/envelopes for pulse-like tone; `pulse` is not accepted syntax.
|
||||
|
||||
Evidence contract:
|
||||
- Read every assigned challenge report and $preEvidence.
|
||||
|
|
|
|||
Loading…
Reference in a new issue