From 16ed4084ff766cec5a20a5376d182ab865fd0a0c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 1 Jun 2026 00:22:29 +0100 Subject: [PATCH] Seed music knowledge manuals --- .../aqua-dsp-usage-manual.md | 112 ++++++++++++++++++ .../open-music-theory-production-distill.md | 108 +++++++++++++++++ state/evidence.jsonl | 1 + state/scratch.md | 14 +++ tools/IpaTrialWorker/Program.cs | 101 ++++++++++++++++ tools/run-song-snippet-trial-swarm.ps1 | 2 +- 6 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 docs/music-production-knowledge/aqua-dsp-usage-manual.md create mode 100644 docs/music-production-knowledge/open-music-theory-production-distill.md diff --git a/docs/music-production-knowledge/aqua-dsp-usage-manual.md b/docs/music-production-knowledge/aqua-dsp-usage-manual.md new file mode 100644 index 0000000..9f488d6 --- /dev/null +++ b/docs/music-production-knowledge/aqua-dsp-usage-manual.md @@ -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. + diff --git a/docs/music-production-knowledge/open-music-theory-production-distill.md b/docs/music-production-knowledge/open-music-theory-production-distill.md new file mode 100644 index 0000000..b3af6c2 --- /dev/null +++ b/docs/music-production-knowledge/open-music-theory-production-distill.md @@ -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. + diff --git a/state/evidence.jsonl b/state/evidence.jsonl index 85794fd..6a9a0dd 100644 --- a/state/evidence.jsonl +++ b/state/evidence.jsonl @@ -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"} diff --git a/state/scratch.md b/state/scratch.md index 21757ca..ac13a65 100644 --- a/state/scratch.md +++ b/state/scratch.md @@ -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`. diff --git a/tools/IpaTrialWorker/Program.cs b/tools/IpaTrialWorker/Program.cs index 2068f28..2b400a9 100644 --- a/tools/IpaTrialWorker/Program.cs +++ b/tools/IpaTrialWorker/Program.cs @@ -1957,6 +1957,11 @@ static IEnumerable BuildMusicKnowledgeDocument { yield return curatorDocument; } + + foreach (var manualDocument in MusicManualDocuments(created)) + { + yield return manualDocument; + } } static IEnumerable MusicRoleDocuments(IReadOnlyList rendered, string created) @@ -2204,6 +2209,102 @@ static IEnumerable MusicCuratorDocuments(strin } } +static IEnumerable 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 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(); + 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 RankMusicKnowledge(IReadOnlyList documents, string query, int limit, string retrievalMode = "lexical") { var terms = ExpandTerms(Tokenize(query)).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); diff --git a/tools/run-song-snippet-trial-swarm.ps1 b/tools/run-song-snippet-trial-swarm.ps1 index a7baf55..adc176a 100644 --- a/tools/run-song-snippet-trial-swarm.ps1 +++ b/tools/run-song-snippet-trial-swarm.ps1 @@ -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",