Seed music knowledge manuals

This commit is contained in:
Meta Vens 2026-06-01 00:22:29 +01:00
commit 16ed4084ff
6 changed files with 337 additions and 1 deletions

View file

@ -0,0 +1,112 @@
# AquaSynth DSP Usage Manual For Music Agents
kind: manual
tier: core-doctrine
topic: AquaSynth DSP usage for composition and production
## Owner
This manual owns the minimum practical DSP and DSL knowledge a musician agent
needs before writing a song candidate, so retrieval starts from usable
AquaSynth technique instead of copying weak prior patches.
## Transfer Rules
- Start with form, not timbre. Declare `meter`, harmonic center or progression,
lane gates, section-level mix motion, and target duration before building
voices.
- Treat every sound as a role owner. Leads, bass, drums, pads, and texture need
separate control surfaces so the next agent can adjust them without surgery.
- Use reference analysis as constraints: tempo/autocorrelation for gates,
register/root/scale for pitch lanes, band stats for filtering, and RMS/motion
coverage for arrangement density.
- Write the simplest patch that makes ownership inspectable. Do not hide a song
in one giant voice or one full-duration noise bed.
## Current AquaSynth Authoring Surface
Composition sugar:
```aqua
meter bpm=128 beats=4
sequence name=kick pattern=x...x...x...x... step=.125 high=.9 low=0
scale name=hook path=/seq/lead/freq root=220 scale=minor degrees=0,2,3,5,3,2 step=.25
chords name=pad root=220 scale=minor progression=0,5,3,4 voicing=0,2,4 paths=/chords/pad/root,/chords/pad/third,/chords/pad/fifth step=bar
mix name=pad points=0:.10,4:.22,8:.15,12:.30,16:.12
```
The sugar lowers into visible `param` and `curve` owners. Bind those paths from
voices with `gain=@/seq/kick`, `freq=@/seq/lead/freq`, or
`gain=@/mix/pad/gain`.
Voice-like leads:
```aqua
source_port name=lead_src kind=syrinx pressure=.75 opening=.42
acoustic_network name=lead_body source=lead_src radiation=beak
acoustic_voice name=lead network=lead_body freq=@/seq/lead/freq gain=@/mix/lead/gain
```
Use syrinx/acoustic ownership when the reference has singing, vocal chops,
creature calls, reed-like lead, or expressive vowel motion. Move pressure,
opening, filter/formant color, and pitch. A static syrinx badge is not a vocal
line.
Subtractive drums:
```aqua
sequence name=kick pattern=x...x...x...x... step=.125 high=1 low=0
voice name=kick_body wave=sine freq=54 gain=@/seq/kick env=ad attack=.002 decay=.14
voice name=kick_click wave=noise gain=@/seq/kick hpf=2500 lpf=7000 env=ad attack=.001 decay=.035
```
Drums need body plus skin. Use sine/triangle bodies for kick/snare weight,
filtered noise only for click, skin, dust, or air, and gates from target tempo.
Noise alone is a placeholder unless it has band limits, a gate, and a musical
job.
Additive/PAD beds:
```aqua
layer name=pad engine=pad freq=@/chords/pad/root gain=@/mix/pad/gain
harmonics name=pad_bank source=pad partials=1:.7,2:.25,3:.18,5:.08
spectrum name=pad_air source=pad_bank centroid=1800 bandwidth=.35
```
Pads own harmonic field and emotional bed. Use harmonic banks and slow
brightness/gain motion. Do not let a pad occupy every band for the full target
unless the reference really does.
Texture and recording color:
```aqua
texture name=dust_hat role=dust pattern=x..x..x. step=.125 gain=.08 sustain=30
texture name=air_wash role=air gain=.035 sustain=30
texture name=codec_bed role=codec gain=.04 sustain=30
```
Texture owns band-limited color, not arrangement. It should support a scene with
motion, gates, or slow modulation. A static broadband noise voice is failure
pressure.
## Production Checklist
- Producer brief: target feel, energy contour, meter, tonal center, section map,
role map, and mix priority.
- First attempt: prove parsing, duration coverage, and audible lane ownership.
- Later attempts: change one hypothesis at a time: timing, register, role
assignment, filter band, envelope, or section/mix motion.
- Listening journal: write what sounded alive, fake, static, missing, or too
generic after every render.
- Gap ledger: name missing AquaSynth primitives or sugar only when a concrete
production problem forced the workaround.
## Failure Modes
- Naming `kick`, `hat`, `pad`, or `syrinx` without audible role behavior.
- Copying one stock drum grid across unrelated targets.
- Letting texture keep the tail non-silent while composition dies.
- Hand-writing isolated frequencies when the reference suggests a tonal center
or progression.
- Treating a metric bump as a lesson without a reusable owner sentence.

View file

@ -0,0 +1,108 @@
# Open Music Theory And Production Textbook Distill
kind: source-distillation
tier: core-doctrine
topic: open music theory and digital production lessons for AquaSynth
## Sources
- Open Music Theory, https://viva.pressbooks.pub/openmusictheory/
- Music Theory for the 21st-Century Classroom, https://musictheory.pugetsound.edu/mt21c/
- Miller Puckette, The Theory and Technique of Electronic Music, https://msp.ucsd.edu/techniques.htm
- Hack Audio, https://www.hackaudio.com/
## Owner
This distillation owns source-grounded general music and production knowledge
for AquaSynth agents, so the music generator can reason from composition and
signal-production fundamentals instead of imitating previous weak candidates.
## Transfer Rules
- Meter is a promise about expectation. Use it to place accents, repetition,
syncopation, fills, and section boundaries, not just to calculate step
seconds.
- Melody needs contour, register, motive, and variation. A lead line should have
a recognizable shape, then repeat, answer, invert, truncate, sequence, or
intensify.
- Harmony is motion plus gravity. Even simple progressions should imply
departure and return. Use roots, chord tones, pedal tones, and bass movement
deliberately.
- Rhythm works through pattern, contrast, and hierarchy. Kick/snare/hat lanes
should form a groove with strong and weak positions, not independent blinking
lights.
- Timbre is spectrum over time. Envelopes, filters, modulation, and saturation
should move the sound from attack to body to tail.
- Mixing is arrangement made audible. Gain lanes, frequency separation, and
automation decide which role owns attention at each section.
## AquaSynth Patterns
Melodic motive:
```aqua
meter bpm=132 beats=4
scale name=lead path=/seq/lead/freq root=220 scale=minor degrees=0,2,3,5,3,2,0,-2 step=.25
sequence name=lead_gate pattern=x.x.xx.. step=.25 high=.75 low=0
mix name=lead points=0:.00,2:.25,6:.18,10:.32,14:.12
```
Harmonic field:
```aqua
chords name=prog root=110 scale=minor progression=0,6,3,5 voicing=0,2,4 paths=/chords/prog/root,/chords/prog/third,/chords/prog/fifth step=bar
mix name=pad points=0:.08,4:.18,8:.11,12:.24,16:.08
```
Groove hierarchy:
```aqua
sequence name=kick pattern=x...x..x....x... step=.125 high=1 low=0
sequence name=snare pattern=....x.......x... step=.125 high=.8 low=0
sequence name=hat pattern=x.x.x.xx.x.x.xxx step=.125 high=.18 low=.03
```
Production automation:
```aqua
mix name=bass points=0:.20,4:.26,8:.14,12:.31,16:.18
mix name=air points=0:.02,4:.05,8:.03,12:.07,16:.02
```
## Composition Moves
- Repeat with change: keep one parameter stable while another evolves. Examples:
same rhythm with different degrees, same degrees with a denser gate, same pad
chord with brighter filter motion.
- Call and response: a lead phrase should leave space for bass, percussion,
chord stab, or texture answer.
- Register contrast: keep bass low, lead in a bounded melodic register, and pads
wide but not louder than the role carrying attention.
- Section contrast: intro, main groove, break, rise, drop, and outro can be
represented by lane gain curves before timbre gets fancy.
- Energy contour: density, brightness, loudness, and rhythmic subdivision are
separate levers. Move one or two deliberately.
## Digital Production Moves
- Attack/body/tail: split percussive sounds into transient click/skin and tonal
body; filter each component differently.
- Subtractive shaping: start rich or noisy, then use filters/envelopes to carve
the useful band. Do not confuse raw oscillator choice with final timbre.
- Additive shaping: build sustained tones from harmonic relationships, then
automate gain/brightness slowly.
- Modulation: use LFO/tremolo/FM/AM for motion, but keep rate and depth tied to
the song grid or expressive gesture.
- Space and air: model ambience as low-gain shaped texture or delayed motion,
not as a full-band noise floor.
## Failure Modes
- A loop with no phrase contour is not melody.
- A progression with no role using its chord tones is metadata, not harmony.
- A drum grid with no body/skin separation becomes weak noisy ticking.
- A pad with no entrance, exit, or brightness motion becomes wallpaper.
- A mix with every lane always on has no foreground.
- A source citation is not a lesson unless it lowers to a current AquaSynth
action.

View file

@ -265,3 +265,4 @@
{"timestamp":"2026-05-31T22:25:00+01:00","topic":"composition-curriculum-redirect","claim":"The song CultCache run learned transferable sound-production role owners, but not composition. Next passes should require meter, progression or tonal center, note-degree sampling, instrument-lane gates, section events, composition-scale automation, and mix movement. AquaSynth now has small Strudel-ish sugar for `meter`, `sequence`, `chords`, and `mix`, all lowering to visible `param`/`curve` owners alongside existing `pattern` and `scale`.","evidence":"Trawl of pass-003 music-production quality standard, distillation report, and abstraction ledgers showed 56 of 75 official candidates had mode-collapse risk while ledgers repeatedly converged on role owners and sugar candidates. Added parser/test coverage for composition-scale sugar and redirected the song swarm prompt toward Composition Map evidence."}
{"timestamp":"2026-05-31T23:15:00+01:00","topic":"producer-apprenticeship-curriculum-gate","claim":"Song curriculum admission must be owned by producer evidence and audible structure, not syntax attendance. `song-score` now records studio document coverage, producer musicianship, composition section score, template-loop risk, noise-percussion risk, and Aqua gap count; verdicts can fail as `weak-producer-missing` or `weak-slop-template`. `music-distill` promotes candidate and role doctrine only from rendered rows that clear the producer gate, while slop/noise/template rows become failure pressure.","evidence":"tools/IpaTrialWorker/Program.cs; tools/run-song-snippet-trial-swarm.ps1; docs/audio-doctrine.md; state/scratch.md"}
{"timestamp":"2026-06-01T00:12:00+01:00","topic":"qdrant-music-knowledge-and-curator-pass","claim":"Music-production knowledge injection is now Qdrant-backed instead of lexical summary matching. `music-index` embeds full knowledge packets in `aquasynth_music_production_knowledge`; `music-search` defaults to Qdrant/Ollama retrieval and emits full owner, transfer rules, patterns, failure modes, and retrieved chunks. The song swarm now runs a dedicated knowledge-curator agent after each musician phase, and `music-distill` ingests `knowledge-curation.md` as curator-distillation doctrine pressure before indexing the next pass store.","evidence":"tools/IpaTrialWorker/Program.cs; tools/run-song-snippet-trial-swarm.ps1; docs/audio-doctrine.md; artifacts/parity/music-qdrant-smoke/20260601T000755/music-search.md"}
{"timestamp":"2026-06-01T00:22:00+01:00","topic":"music-production-manual-ingestion","claim":"Fresh music knowledge stores now include repo-native manuals before agent-derived pressure. `docs/music-production-knowledge/aqua-dsp-usage-manual.md` teaches AquaSynth composition/DSP lowering, and `docs/music-production-knowledge/open-music-theory-production-distill.md` distills open music theory and digital production sources into actionable AquaSynth patterns. `music-distill` ingests these as `manual` documents, and Qdrant search retrieves them as full context packets.","evidence":"docs/music-production-knowledge/aqua-dsp-usage-manual.md; docs/music-production-knowledge/open-music-theory-production-distill.md; tools/IpaTrialWorker/Program.cs; artifacts/parity/manual-knowledge-smoke/20260601T001932/music-search.md"}

View file

@ -1969,3 +1969,17 @@ Next likely slice:
- `music-distill` ingests those curator files as `curator-distillation`
documents, then the pass indexes the resulting `.cc` into Qdrant before the
next phase uses it.
2026-06-01 manual/textbook music curriculum slice:
- Added repo-native manuals under `docs/music-production-knowledge/`:
`aqua-dsp-usage-manual.md` and
`open-music-theory-production-distill.md`.
- `music-distill` now ingests those manuals as `manual` knowledge documents in
every fresh music `.cc`, so musician agents retrieve AquaSynth DSP usage,
music theory, arrangement, groove, harmony, melody, production, and failure
modes before prior-run candidate pressure.
- Smoke proof: `artifacts/parity/manual-knowledge-smoke/20260601T001932`
produced a 16-document knowledge store with 2 manuals, indexed it into
Qdrant, and `music-search` retrieved the AquaSynth DSP manual with
`retrieval: qdrant-ollama`.

View file

@ -1957,6 +1957,11 @@ static IEnumerable<MusicProductionKnowledgeDocument> BuildMusicKnowledgeDocument
{
yield return curatorDocument;
}
foreach (var manualDocument in MusicManualDocuments(created))
{
yield return manualDocument;
}
}
static IEnumerable<MusicProductionKnowledgeDocument> MusicRoleDocuments(IReadOnlyList<SongSummaryRow> rendered, string created)
@ -2204,6 +2209,102 @@ static IEnumerable<MusicProductionKnowledgeDocument> MusicCuratorDocuments(strin
}
}
static IEnumerable<MusicProductionKnowledgeDocument> MusicManualDocuments(string created)
{
var manualRoot = Path.Combine(Directory.GetCurrentDirectory(), "docs", "music-production-knowledge");
if (!Directory.Exists(manualRoot))
{
yield break;
}
foreach (var manual in Directory.EnumerateFiles(manualRoot, "*.md", SearchOption.TopDirectoryOnly).Order(StringComparer.OrdinalIgnoreCase))
{
var text = ReadBoundedText(manual, 12000);
if (string.IsNullOrWhiteSpace(text))
{
continue;
}
var id = $"music-manual-{SafeName(Path.GetFileNameWithoutExtension(manual))}-{StableUuid(manual)[..8]}";
var topic = ManualField(text, "topic") ?? Path.GetFileNameWithoutExtension(manual).Replace('-', ' ');
var tier = ManualField(text, "tier") ?? "manual-doctrine";
yield return new MusicProductionKnowledgeDocument(
id,
"manual",
topic,
tier,
LinesAfterHeading(text, "Owner", 900).DefaultIfEmpty("Manual owns reusable music-production knowledge for AquaSynth agents.").First(),
text,
LinesAfterHeading(text, "Transfer Rules", 16).ToArray(),
LinesContaining(text, "meter ", "sequence ", "scale ", "chords ", "mix ", "voice ", "texture ", "source_port", "layer ", "harmonics ", "spectrum ").Take(24).ToArray(),
LinesAfterHeading(text, "Failure Modes", 16).ToArray(),
[],
[],
[new SpeechScoreMetric("manual_chars", text.Length, 0)],
[manual],
created);
}
}
static string? ManualField(string text, string field)
{
var prefix = $"{field}:";
return text.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.FirstOrDefault(line => line.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))?
.Substring(prefix.Length)
.Trim();
}
static IEnumerable<string> LinesAfterHeading(string text, string heading, int maxItemsOrChars)
{
var lines = text.Split(['\r', '\n']);
var start = Array.FindIndex(lines, line => line.Trim().Equals($"## {heading}", StringComparison.OrdinalIgnoreCase));
if (start < 0)
{
yield break;
}
var collected = new List<string>();
for (var index = start + 1; index < lines.Length; index++)
{
var line = lines[index].Trim();
if (line.StartsWith("## ", StringComparison.Ordinal))
{
break;
}
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
if (line.StartsWith("- ", StringComparison.Ordinal))
{
collected.Add(line[2..].Trim());
}
else if (!line.StartsWith("```", StringComparison.Ordinal))
{
collected.Add(line);
}
}
if (maxItemsOrChars > 32)
{
var paragraph = TrimForReport(string.Join(' ', collected), maxItemsOrChars);
if (!string.IsNullOrWhiteSpace(paragraph))
{
yield return paragraph;
}
yield break;
}
foreach (var item in collected.Take(maxItemsOrChars))
{
yield return item;
}
}
static IReadOnlyList<MusicKnowledgeHit> RankMusicKnowledge(IReadOnlyList<MusicProductionKnowledgeDocument> documents, string query, int limit, string retrievalMode = "lexical")
{
var terms = ExpandTerms(Tokenize(query)).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();

View file

@ -316,7 +316,7 @@ for ($pass = 1; $pass -le $Passes; $pass++) {
"--store",
$latestMusicKnowledgeStore,
"--query",
"producer brief listening journal actionable composition arrangement groove harmony melody bass drums syrinx subtractive additive pad texture mix automation failure novelty AquaSynth",
"AquaSynth DSP manual music theory production arrangement groove harmony melody bass drums syrinx subtractive additive pad texture mix automation failure novelty",
"--limit",
"40",
"--require-vector",