Let song agents iterate on rendered features
This commit is contained in:
parent
5d3a81a1f1
commit
4b40d12816
6 changed files with 213 additions and 14 deletions
|
|
@ -109,10 +109,13 @@ static async Task SongPrepareAsync(Dictionary<string, string> options)
|
|||
Directory.CreateDirectory(artifactRoot);
|
||||
var decoded = DecodeMono(source);
|
||||
var resampled = Resample(decoded.Samples, decoded.SampleRate, sampleRate);
|
||||
var clipLength = Math.Min(resampled.Length, Math.Max(1, (int)MathF.Round(durationSeconds * sampleRate)));
|
||||
var fullSong = durationSeconds <= 0;
|
||||
var clipLength = fullSong
|
||||
? resampled.Length
|
||||
: Math.Min(resampled.Length, Math.Max(1, (int)MathF.Round(durationSeconds * sampleRate)));
|
||||
var maxStart = Math.Max(0, resampled.Length - clipLength);
|
||||
var random = new Random(seed);
|
||||
var startSample = maxStart == 0 ? 0 : random.Next(0, maxStart + 1);
|
||||
var startSample = fullSong || maxStart == 0 ? 0 : random.Next(0, maxStart + 1);
|
||||
var clip = new float[clipLength];
|
||||
Array.Copy(resampled, startSample, clip, 0, clipLength);
|
||||
NormalizePeak(clip, .9f);
|
||||
|
|
@ -127,11 +130,13 @@ static async Task SongPrepareAsync(Dictionary<string, string> options)
|
|||
var bandStatsPath = Path.Combine(artifactRoot, "logmel-band-stats.csv");
|
||||
var envelopePath = Path.Combine(artifactRoot, "rms-envelope.csv");
|
||||
var envelopeAutocorrPath = Path.Combine(artifactRoot, "rms-envelope-autocorr.csv");
|
||||
var whitenedSpectralAutocorrPath = Path.Combine(artifactRoot, "whitened-spectral-autocorr.csv");
|
||||
var analysisReportPath = Path.Combine(artifactRoot, "analysis.md");
|
||||
await File.WriteAllTextAsync(spectrogramPath, SpectrogramCsv(analysis.LogMelSpectrogram), Encoding.UTF8);
|
||||
await File.WriteAllTextAsync(bandStatsPath, SpectrogramBandStatsCsv(analysis.LogMelSpectrogram), Encoding.UTF8);
|
||||
await File.WriteAllTextAsync(envelopePath, EnvelopeCsv(analysis.RmsEnvelope, sampleRate, analyzer.Config.HopSize), Encoding.UTF8);
|
||||
await File.WriteAllTextAsync(envelopeAutocorrPath, AutocorrelationCsv(analysis.RmsEnvelope, sampleRate / (float)Math.Max(1, analyzer.Config.HopSize)), Encoding.UTF8);
|
||||
await File.WriteAllTextAsync(whitenedSpectralAutocorrPath, WhitenedSpectralAutocorrelationCsv(analysis.LogMelSpectrogram, sampleRate / (float)Math.Max(1, analyzer.Config.HopSize)), Encoding.UTF8);
|
||||
var features = new SongChallengeFeatures(
|
||||
analysis.Features.DurationSeconds,
|
||||
analysis.Features.Peak,
|
||||
|
|
@ -155,6 +160,7 @@ static async Task SongPrepareAsync(Dictionary<string, string> options)
|
|||
bandStatsPath,
|
||||
envelopePath,
|
||||
envelopeAutocorrPath,
|
||||
whitenedSpectralAutocorrPath,
|
||||
analysisReportPath);
|
||||
var challenge = new SongChallenge(
|
||||
challengeId,
|
||||
|
|
@ -263,6 +269,13 @@ static async Task SongScoreAsync(Dictionary<string, string> options)
|
|||
NormalizePeak(matched, .9f);
|
||||
WriteWav(candidateWav, matched, challenge.SampleRate);
|
||||
artifacts.Add(Artifact("candidate-wav", candidateWav));
|
||||
var candidateAnalysisArtifacts = await WriteSongRenderAnalysisAsync(
|
||||
matched,
|
||||
challenge.SampleRate,
|
||||
audioDir,
|
||||
"candidate",
|
||||
analyzer);
|
||||
artifacts.AddRange(candidateAnalysisArtifacts.Select(ArtifactFromAnalysis));
|
||||
var comparison = analyzer.Compare(referenceSamples, matched);
|
||||
metrics.AddRange(SongComparisonMetrics(comparison));
|
||||
verdict = SongVerdict(comparison, instrumentProfile);
|
||||
|
|
@ -303,7 +316,9 @@ static async Task SongScoreAsync(Dictionary<string, string> options)
|
|||
verdict,
|
||||
[
|
||||
"This is a local-only song clip challenge; reference audio is not redistributed by the repo.",
|
||||
$"The target is a randomly selected {challenge.DurationSeconds:0.###}-second scene-audio snippet, not IPA articulation truth.",
|
||||
challenge.StartSeconds <= 0.001f
|
||||
? $"The target starts at the source file beginning and lasts {challenge.DurationSeconds:0.###} seconds; in full-song runs this is the whole decoded song, not IPA articulation truth."
|
||||
: $"The target is a randomly selected {challenge.DurationSeconds:0.###}-second scene-audio snippet, not IPA articulation truth.",
|
||||
"Challenge spectrogram, derivative, envelope, and autocorrelation artifacts are stored as typed CultMesh/CultCache evidence documents in the .cc database.",
|
||||
"Full-patch FM/AM/noise/scene modeling is allowed; primitive timeline facts remain diagnostic when present.",
|
||||
instrumentProfile.ChipDistressRisk >= .6f
|
||||
|
|
@ -1934,6 +1949,10 @@ static IEnumerable<SpeechRenderArtifact> SongChallengeArtifacts(SongChallenge ch
|
|||
yield return Artifact("target-logmel-band-stats", challenge.Artifacts.LogMelBandStatsCsv);
|
||||
yield return Artifact("target-rms-envelope", challenge.Artifacts.RmsEnvelopeCsv);
|
||||
yield return Artifact("target-rms-envelope-autocorr", challenge.Artifacts.RmsEnvelopeAutocorrCsv);
|
||||
if (!string.IsNullOrWhiteSpace(challenge.Artifacts.WhitenedSpectralAutocorrCsv))
|
||||
{
|
||||
yield return Artifact("target-whitened-spectral-autocorr", challenge.Artifacts.WhitenedSpectralAutocorrCsv);
|
||||
}
|
||||
}
|
||||
|
||||
static SpeechRenderArtifact SongChallengeEvidenceArtifact(SongChallengeEvidenceDocument document) =>
|
||||
|
|
@ -1942,6 +1961,9 @@ static SpeechRenderArtifact SongChallengeEvidenceArtifact(SongChallengeEvidenceD
|
|||
$"cultmesh://aquasynth/song-challenge-evidence/{Uri.EscapeDataString(document.EvidenceId)}",
|
||||
document.ContentHash);
|
||||
|
||||
static SpeechRenderArtifact ArtifactFromAnalysis(SongRenderAnalysisArtifacts artifact) =>
|
||||
Artifact($"candidate-{artifact.Kind}", artifact.Path);
|
||||
|
||||
static IReadOnlyList<SongChallengeEvidenceDocument> SongChallengeEvidenceDocuments(SongChallenge challenge)
|
||||
{
|
||||
var documents = new List<SongChallengeEvidenceDocument>();
|
||||
|
|
@ -1955,6 +1977,7 @@ static IReadOnlyList<SongChallengeEvidenceDocument> SongChallengeEvidenceDocumen
|
|||
AddSongChallengeEvidence(documents, challenge, "logmel-band-stats", "text/csv", challenge.Artifacts.LogMelBandStatsCsv);
|
||||
AddSongChallengeEvidence(documents, challenge, "rms-envelope", "text/csv", challenge.Artifacts.RmsEnvelopeCsv);
|
||||
AddSongChallengeEvidence(documents, challenge, "rms-envelope-autocorr", "text/csv", challenge.Artifacts.RmsEnvelopeAutocorrCsv);
|
||||
AddSongChallengeEvidence(documents, challenge, "whitened-spectral-autocorr", "text/csv", challenge.Artifacts.WhitenedSpectralAutocorrCsv);
|
||||
return documents;
|
||||
}
|
||||
|
||||
|
|
@ -1981,6 +2004,35 @@ static void AddSongChallengeEvidence(
|
|||
DateTimeOffset.UtcNow.ToString("O", CultureInfo.InvariantCulture)));
|
||||
}
|
||||
|
||||
static async Task<IReadOnlyList<SongRenderAnalysisArtifacts>> WriteSongRenderAnalysisAsync(
|
||||
IReadOnlyList<float> samples,
|
||||
int sampleRate,
|
||||
string artifactRoot,
|
||||
string prefix,
|
||||
AudioAnalyzer analyzer)
|
||||
{
|
||||
Directory.CreateDirectory(artifactRoot);
|
||||
var analysis = analyzer.Analyze(samples.ToArray());
|
||||
var frameRate = sampleRate / (float)Math.Max(1, analyzer.Config.HopSize);
|
||||
var artifacts = new[]
|
||||
{
|
||||
new SongRenderAnalysisArtifacts("analysis-report", Path.Combine(artifactRoot, $"{prefix}-analysis.md")),
|
||||
new SongRenderAnalysisArtifacts("logmel-spectrogram", Path.Combine(artifactRoot, $"{prefix}-logmel-spectrogram.csv")),
|
||||
new SongRenderAnalysisArtifacts("logmel-band-stats", Path.Combine(artifactRoot, $"{prefix}-logmel-band-stats.csv")),
|
||||
new SongRenderAnalysisArtifacts("rms-envelope", Path.Combine(artifactRoot, $"{prefix}-rms-envelope.csv")),
|
||||
new SongRenderAnalysisArtifacts("rms-envelope-autocorr", Path.Combine(artifactRoot, $"{prefix}-rms-envelope-autocorr.csv")),
|
||||
new SongRenderAnalysisArtifacts("whitened-spectral-autocorr", Path.Combine(artifactRoot, $"{prefix}-whitened-spectral-autocorr.csv"))
|
||||
};
|
||||
|
||||
await File.WriteAllTextAsync(artifacts[0].Path, SongRenderAnalysisReport(prefix, analysis, frameRate), Encoding.UTF8);
|
||||
await File.WriteAllTextAsync(artifacts[1].Path, SpectrogramCsv(analysis.LogMelSpectrogram), Encoding.UTF8);
|
||||
await File.WriteAllTextAsync(artifacts[2].Path, SpectrogramBandStatsCsv(analysis.LogMelSpectrogram), Encoding.UTF8);
|
||||
await File.WriteAllTextAsync(artifacts[3].Path, EnvelopeCsv(analysis.RmsEnvelope, sampleRate, analyzer.Config.HopSize), Encoding.UTF8);
|
||||
await File.WriteAllTextAsync(artifacts[4].Path, AutocorrelationCsv(analysis.RmsEnvelope, frameRate), Encoding.UTF8);
|
||||
await File.WriteAllTextAsync(artifacts[5].Path, WhitenedSpectralAutocorrelationCsv(analysis.LogMelSpectrogram, frameRate), Encoding.UTF8);
|
||||
return artifacts;
|
||||
}
|
||||
|
||||
static AutocorrelationPoint ReadAutocorrPeak(string? path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
|
||||
|
|
@ -2571,6 +2623,59 @@ static string AutocorrelationCsv(IReadOnlyList<float> values, float frameRate)
|
|||
return builder.ToString();
|
||||
}
|
||||
|
||||
static string WhitenedSpectralAutocorrelationCsv(Spectrogram spectrogram, float frameRate)
|
||||
{
|
||||
var series = WhitenedSpectralFluxSeries(spectrogram);
|
||||
var builder = new StringBuilder();
|
||||
builder.AppendLine("lag_frames,lag_seconds,correlation");
|
||||
foreach (var point in Autocorrelation(series, frameRate, Math.Min(Math.Max(1, series.Length - 1), 512)))
|
||||
{
|
||||
builder.Append(point.LagFrames).Append(',');
|
||||
builder.Append(point.LagSeconds.ToString("0.########", CultureInfo.InvariantCulture)).Append(',');
|
||||
builder.AppendLine(point.Correlation.ToString("0.########", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
static float[] WhitenedSpectralFluxSeries(Spectrogram spectrogram)
|
||||
{
|
||||
if (spectrogram.Frames <= 1 || spectrogram.Bands <= 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var means = new float[spectrogram.Bands];
|
||||
var stddevs = new float[spectrogram.Bands];
|
||||
for (var band = 0; band < spectrogram.Bands; band++)
|
||||
{
|
||||
var values = new float[spectrogram.Frames];
|
||||
for (var frame = 0; frame < spectrogram.Frames; frame++)
|
||||
{
|
||||
values[frame] = spectrogram.At(frame, band);
|
||||
}
|
||||
|
||||
means[band] = Mean(values);
|
||||
stddevs[band] = Math.Max(1e-4f, StdDev(values));
|
||||
}
|
||||
|
||||
var series = new float[spectrogram.Frames - 1];
|
||||
for (var frame = 1; frame < spectrogram.Frames; frame++)
|
||||
{
|
||||
var sum = 0f;
|
||||
for (var band = 0; band < spectrogram.Bands; band++)
|
||||
{
|
||||
var current = (spectrogram.At(frame, band) - means[band]) / stddevs[band];
|
||||
var previous = (spectrogram.At(frame - 1, band) - means[band]) / stddevs[band];
|
||||
sum += MathF.Abs(current - previous);
|
||||
}
|
||||
|
||||
series[frame - 1] = sum / Math.Max(1, spectrogram.Bands);
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
static IReadOnlyList<AutocorrelationPoint> Autocorrelation(IReadOnlyList<float> values, float frameRate, int maxLags)
|
||||
{
|
||||
if (values.Count < 2)
|
||||
|
|
@ -2645,6 +2750,9 @@ static IReadOnlyList<SpeechScoreMetric> SongTargetMetrics(
|
|||
var autocorrPeak = ReadAutocorrPeak(challenge.Artifacts?.RmsEnvelopeAutocorrCsv);
|
||||
metrics.Add(new SpeechScoreMetric("target_envelope_autocorr_peak", autocorrPeak.Correlation, 0));
|
||||
metrics.Add(new SpeechScoreMetric("target_envelope_autocorr_peak_lag_seconds", autocorrPeak.LagSeconds, 0));
|
||||
var whitenedPeak = ReadAutocorrPeak(challenge.Artifacts?.WhitenedSpectralAutocorrCsv);
|
||||
metrics.Add(new SpeechScoreMetric("target_whitened_spectral_autocorr_peak", whitenedPeak.Correlation, 0));
|
||||
metrics.Add(new SpeechScoreMetric("target_whitened_spectral_autocorr_peak_lag_seconds", whitenedPeak.LagSeconds, 0));
|
||||
return metrics;
|
||||
}
|
||||
|
||||
|
|
@ -2798,6 +2906,37 @@ static string SongAnalysisReport(SongChallenge challenge, AudioAnalysis analysis
|
|||
builder.AppendLine($"- log_mel_band_stats_csv: `{challenge.Artifacts?.LogMelBandStatsCsv}`");
|
||||
builder.AppendLine($"- rms_envelope_csv: `{challenge.Artifacts?.RmsEnvelopeCsv}`");
|
||||
builder.AppendLine($"- rms_envelope_autocorr_csv: `{challenge.Artifacts?.RmsEnvelopeAutocorrCsv}`");
|
||||
builder.AppendLine($"- whitened_spectral_autocorr_csv: `{challenge.Artifacts?.WhitenedSpectralAutocorrCsv}`");
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
static string SongRenderAnalysisReport(string label, AudioAnalysis analysis, float frameRate)
|
||||
{
|
||||
var bands = SpectrogramBandStats(analysis.LogMelSpectrogram);
|
||||
var brightest = bands.OrderByDescending(band => band.Mean).Take(5).Select(band => band.Band).ToArray();
|
||||
var mostMoving = bands.OrderByDescending(band => band.AbsDeltaMean).Take(5).Select(band => band.Band).ToArray();
|
||||
var spectralAutocorr = Autocorrelation(WhitenedSpectralFluxSeries(analysis.LogMelSpectrogram), frameRate, maxLags: 64)
|
||||
.OrderByDescending(point => point.Correlation)
|
||||
.Take(5)
|
||||
.ToArray();
|
||||
var builder = new StringBuilder();
|
||||
builder.AppendLine($"# Song Render Analysis: {label}");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($"duration_seconds: `{analysis.Features.DurationSeconds:0.######}`");
|
||||
builder.AppendLine($"peak: `{analysis.Features.Peak:0.######}`");
|
||||
builder.AppendLine($"rms: `{analysis.Features.Rms:0.######}`");
|
||||
builder.AppendLine($"zero_crossing_rate: `{analysis.Features.ZeroCrossingRate:0.######}`");
|
||||
builder.AppendLine($"spectral_centroid_hz: `{analysis.Features.SpectralCentroidHz:0.######}`");
|
||||
builder.AppendLine($"spectral_rolloff_hz: `{analysis.Features.SpectralRolloffHz:0.######}`");
|
||||
builder.AppendLine($"brightest_bands: `{string.Join(",", brightest)}`");
|
||||
builder.AppendLine($"highest_delta_bands: `{string.Join(",", mostMoving)}`");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("## Whitened Spectral Autocorrelation Peaks");
|
||||
foreach (var point in spectralAutocorr)
|
||||
{
|
||||
builder.AppendLine(CultureInfo.InvariantCulture, $"- lag_frames `{point.LagFrames}`, lag_seconds `{point.LagSeconds:0.######}`, correlation `{point.Correlation:0.######}`");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
|
|
@ -2837,6 +2976,7 @@ static string SongChallengeReport(SongChallenge challenge) =>
|
|||
log_mel_band_stats_csv: `{challenge.Artifacts?.LogMelBandStatsCsv ?? ""}`
|
||||
rms_envelope_csv: `{challenge.Artifacts?.RmsEnvelopeCsv ?? ""}`
|
||||
rms_envelope_autocorr_csv: `{challenge.Artifacts?.RmsEnvelopeAutocorrCsv ?? ""}`
|
||||
whitened_spectral_autocorr_csv: `{challenge.Artifacts?.WhitenedSpectralAutocorrCsv ?? ""}`
|
||||
""";
|
||||
|
||||
static string SongComparisonReport(SongChallenge challenge, IpaTrialScriptCandidate candidate, AudioComparison comparison, string verdict, SongInstrumentProfile profile) =>
|
||||
|
|
@ -3023,6 +3163,7 @@ static void PrintHelp()
|
|||
--embed-model qwen3-embedding:0.6b
|
||||
--collection aquasynth_ipa_trial_results
|
||||
|
||||
Use song-prepare --duration-seconds 0 to freeze the full decoded source file from sample zero.
|
||||
Agent-authored patch files must be named <targetId>__candidate-name.aqua.
|
||||
Known seed target ids: a, i, u, e, o, m, n, ng, l, r, s, z, f, v, th, p, b, t, d, k, mix-a, mix-m, mix-s, mix-p, mix-u.
|
||||
""");
|
||||
|
|
@ -3059,8 +3200,11 @@ sealed record SongChallengeAnalysisArtifacts(
|
|||
string LogMelBandStatsCsv,
|
||||
string RmsEnvelopeCsv,
|
||||
string RmsEnvelopeAutocorrCsv,
|
||||
string WhitenedSpectralAutocorrCsv,
|
||||
string AnalysisReportMarkdown);
|
||||
|
||||
sealed record SongRenderAnalysisArtifacts(string Kind, string Path);
|
||||
|
||||
sealed record SongChallengeFeatures(
|
||||
float DurationSeconds,
|
||||
float Peak,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ param(
|
|||
[string]$Source = "D:\Music\Reinier\Heyoka\Gate Code\Heyoka - Alien Gibberish.mp3",
|
||||
[string]$SourceFolder = "D:\Music\Reinier\Heyoka",
|
||||
[float]$DurationSeconds = 30,
|
||||
[switch]$FullSongs,
|
||||
[int]$IterationsPerTarget = 5,
|
||||
[int]$Seed = 0,
|
||||
[switch]$NewSegmentPerPass,
|
||||
[switch]$RandomSourcePerAgent,
|
||||
|
|
@ -144,7 +146,7 @@ function Get-SongSources {
|
|||
|
||||
if ($SourceFolder.Length -gt 0) {
|
||||
$files = @(Get-ChildItem -LiteralPath $SourceFolder -File -Recurse |
|
||||
Where-Object { $_.Extension -in @(".mp3", ".wav", ".flac", ".aiff", ".aif", ".ogg") } |
|
||||
Where-Object { $_.Extension -in @(".mp3", ".wav", ".flac", ".aiff", ".aif", ".ogg", ".m4a", ".mp4") } |
|
||||
Sort-Object FullName)
|
||||
if ($files.Count -eq 0) {
|
||||
throw "No supported song files found in '$SourceFolder'."
|
||||
|
|
@ -246,9 +248,11 @@ Set-Content -LiteralPath (Join-Path $loopRoot "loop-index.md") -Value @"
|
|||
- passes: $Passes
|
||||
- agents_per_pass: $AgentsPerPass
|
||||
- songs_per_agent: $SongsPerAgent
|
||||
- iterations_per_target: $IterationsPerTarget
|
||||
- playlist_top_count: $PlaylistTopCount
|
||||
- seed: $seedValue
|
||||
- duration_seconds: $DurationSeconds
|
||||
- full_songs: $FullSongs
|
||||
- new_segment_per_pass: $NewSegmentPerPass
|
||||
- random_source_per_agent: $RandomSourcePerAgent
|
||||
- store: $storePath
|
||||
|
|
@ -317,6 +321,7 @@ for ($pass = 1; $pass -le $Passes; $pass++) {
|
|||
}
|
||||
$agentSource = $songSources[[int]$sourceIndex]
|
||||
$agentSeed = $phaseSeed + ($agent * 104729) + ($song * 8191)
|
||||
$durationArg = if ($FullSongs) { "0" } else { [string]$DurationSeconds }
|
||||
Invoke-LoggedProcess `
|
||||
-FilePath "dotnet" `
|
||||
-ArgumentList @(
|
||||
|
|
@ -330,7 +335,7 @@ for ($pass = 1; $pass -le $Passes; $pass++) {
|
|||
"--artifact-root",
|
||||
$agentChallengeRoot,
|
||||
"--duration-seconds",
|
||||
([string]$DurationSeconds),
|
||||
$durationArg,
|
||||
"--seed",
|
||||
([string]$agentSeed),
|
||||
"--challenge-id",
|
||||
|
|
@ -350,6 +355,9 @@ for ($pass = 1; $pass -le $Passes; $pass++) {
|
|||
$targetPatchList = ($targetPatchDirs | ForEach-Object { "- target patch output directory: $_" }) -join "`n"
|
||||
$agentSourceList = ($agentSources | ForEach-Object { "- assigned source: $_" }) -join "`n"
|
||||
$agentSeedList = ($agentSeeds | ForEach-Object { "- target seed: $_" }) -join "`n"
|
||||
$durationLabel = if ($FullSongs) { "the full decoded song duration from each challenge report" } else { "$DurationSeconds seconds" }
|
||||
$targetKind = if ($FullSongs) { "full-song" } else { "$DurationSeconds second" }
|
||||
$iterationRoot = Join-Path $agentDir "iterations"
|
||||
$outputPath = Join-Path $agentDir "hypothesis-agent.md"
|
||||
$promptPath = Join-Path $agentDir "hypothesis-agent.prompt.md"
|
||||
$logPath = Join-Path $logRoot "$passId-$agentId-hypothesis-agent.log"
|
||||
|
|
@ -367,21 +375,32 @@ $targetPatchList
|
|||
- candidate filename prefix: $agentId
|
||||
- phase id: $passId
|
||||
- phase seed: $phaseSeed
|
||||
- private iteration root: $iterationRoot
|
||||
- required self-iteration attempts per target: $IterationsPerTarget
|
||||
$agentSourceList
|
||||
$agentSeedList
|
||||
- required duration: $DurationSeconds seconds
|
||||
- required duration: $durationLabel
|
||||
|
||||
Goal:
|
||||
Write exactly one parseable AquaSynth `.aqua` patch for each frozen $DurationSeconds second reference clip assigned to you. This is scene-audio parity, not IPA articulation. You may use ordinary voices, FM, AM/tremolo, filters, formants, noise layers, acoustic vocal/syrinx primitives, additive/PAD layers, curves, and helper voices.
|
||||
Write exactly one parseable AquaSynth `.aqua` patch for each frozen $targetKind reference assigned to you. This is scene-audio parity, not IPA articulation. You may use ordinary voices, FM, AM/tremolo, filters, formants, noise layers, acoustic vocal/syrinx primitives, additive/PAD layers, curves, and helper voices.
|
||||
|
||||
Generalization:
|
||||
- You own two target patches, but your report must compare both targets and state what reusable scene/instrument knowledge transfers between them.
|
||||
- The two patches may share instrument roles, texture roles, control idioms, and DSL conventions, but each patch should fit its own target's tempo/register/spectral evidence.
|
||||
- Future agents will receive distilled evidence from this trial when asked to zero-shot an audio production request. Make your `hypotheses.md` useful retrieval context: name what transferred, what did not, and what evidence would change your next patch.
|
||||
|
||||
Self-iteration loop:
|
||||
- For each target, run exactly $IterationsPerTarget local attempts before publishing the final `.aqua` file.
|
||||
- Each attempt must write a candidate under `$iterationRoot/attempt-NN/<target-id>/patch`, run the scoring worker against that one target, inspect the rendered candidate evidence, and revise the next attempt.
|
||||
- Scoring command pattern:
|
||||
`dotnet run --project "$workerProject" -- song-score --patch-root "<attempt-patch-dir>" --challenge "<challenge-json>" --artifact-root "<attempt-dir>" --batch-id "<agent-id>-<target-id>-attempt-NN" --store "<attempt-dir>/iteration-results.cc" --hypothesizer "$agentId-iteration"`
|
||||
- After each score, read the attempt's `evaluator-report.md`, `summary.csv`, `audio/comparison.txt`, `audio/candidate-analysis.md`, `audio/candidate-logmel-band-stats.csv`, `audio/candidate-rms-envelope-autocorr.csv`, and `audio/candidate-whitened-spectral-autocorr.csv`.
|
||||
- Use those candidate-side facts the same way you use target facts: compare spectral bands, envelope autocorrelation, whitened spectral autocorrelation, centroid/RMS, instrument-role metrics, and chip-distress risk. Move timings, filters, gains, sources, roles, and patterns between attempts.
|
||||
- Keep intermediate candidates inside `$iterationRoot`; publish only one final `.aqua` per target to the official target patch output directory.
|
||||
|
||||
Noise and texture:
|
||||
- Do not model background or recording color as a full-duration raw `voice wave=noise` bed. That produces static white-noise wash and will be treated as broken subtractive synthesis, not scene modeling.
|
||||
- Use the shaped texture owner for noise roles: `texture name=dust_hat role=dust pattern=x..x step=<beat_seconds/4> gain=.08 sustain=$DurationSeconds`, `texture name=air_wash role=air gain=.035 sustain=$DurationSeconds`, `texture name=codec_bed role=codec gain=.04 sustain=$DurationSeconds`.
|
||||
- Use the shaped texture owner for noise roles: `texture name=dust_hat role=dust pattern=x..x step=<beat_seconds/4> gain=.08 sustain=<duration_seconds>`, `texture name=air_wash role=air gain=.035 sustain=<duration_seconds>`, `texture name=codec_bed role=codec gain=.04 sustain=<duration_seconds>`.
|
||||
- `texture` lowers to a gated noise voice with role-specific bandpass/highpass/lowpass/tremolo defaults and a control curve or pattern gate. Raw `voice wave=noise` is only acceptable for short transients with explicit gates and narrow filters.
|
||||
|
||||
Instrument ownership:
|
||||
|
|
@ -430,7 +449,7 @@ Evidence contract:
|
|||
- Write exactly one `.aqua` file under each target patch output directory named `<agent-id>__<family>__<hypothesis>.aqua`.
|
||||
- Include at least three scene voices or layers in the patch: a primary voice/body, a rhythmic drum/transient/noise role, and a pad/bed/recording-color role. Prefer syrinx for the primary voice when it is voice-like, subtractive for the drum/transient, and additive/PAD or shaped texture for the bed.
|
||||
- Background/recording-color layers must use `texture` or an equivalently gated and band-shaped explicit voice; a static full-duration white-noise bed is failed evidence.
|
||||
- Make each patch duration/gates cover its matching $DurationSeconds second target.
|
||||
- Make each patch duration/gates cover its matching target duration from the challenge report.
|
||||
|
||||
Return a short final summary naming the patch and report.
|
||||
"@
|
||||
|
|
|
|||
Loading…
Reference in a new issue