Sepearate Generation

This commit is contained in:
khodowany
2026-10-04 09:05:25 -05:00
parent e8ac7b5edd
commit 8fdd736e13
56 changed files with 1739 additions and 341 deletions
+8 -34
View File
@@ -93,39 +93,15 @@ Artifacts are published to the khodo generic package registry's required `latest
Uncompressed MusicXML 3.1/4.0 scores exported from Soundslice or MuseScore live in `data/`. Generated score JSON is not committed.
`data/songs` supplies the authored music. `data/rhythms/<meter>/<series>/` supplies the accompaniment rhythm library for 2/4, 3/4, 4/4, and 5/4. All three series are active: the original quarter/eighth patterns plus series `3` with half, dotted-half, and whole notes/rests. Rhythm snippets are build inputs, not separate catalog entries or runtime files. Generation loads the library once and shares it across parts.
`data/songs` supplies the original melody and harmony. The 21 scale patterns, 2,954 relative interval paths, meter-specific rhythm catalogs, and versioned rules in `data/composition` supply production vocabulary. Audition references are outside that path and never participate in construction, scoring, caching or selection.
`data/scales` supplies the 21 C-centered modes of major, melodic minor, and harmonic minor. Build-time Python uses each song's actual melody, its mapped harmony, `data/sequences`, and `data/rhythms` to compose recognizable acoustic and electric variations. The standalone `data/lead_phrases` material is an audition control, not a production seed. No solo assignments are stored in song XML, and the runtime format is unchanged.
Six roles generate independently from immutable source analysis: acoustic accompaniment/solo; electric accompaniment/melody/solo; vocal melody. A bounded process pool composes roles in parallel, with fully keyed per-role caches for incremental builds. `--composition-jobs 1` provides the serial equivalent; the default is two. There is no joint acoustic/electric selection, generated-solo-aware backing, or reuse of generated melody grips. Assembly respects source-defined role windows and the returning vocal pickup.
The arrangement reuses six musical parts: acoustic accompaniment and solo; electric accompaniment, melody and solo; and vocal melody. Each guitar learns one accompaniment over the full form. Corresponding bars reuse identical rhythms, durations, pitches and TAB fingerings, including behind solos. Only authored harmony changes and protected pickup/ending boundaries create local exceptions.
Each solo develops one realized theme from selected features across the actual head. Complete phrases coordinate chord-tone destinations, scale routes, mixed rhythms, space and binding sustained arrivals. Both solos can use all six strings at frets 1–12 without open strings, with different soft register and thematic preferences. Ordinary movement remains strictly mapped. Target-driven approaches, colors, anticipations and conservative blues treatments require explicit validated timing, harmonic and resolution contracts. Direct approaches remain available. No dynamics, accents or humanization have been added.
Source analysis retains complete sounding notes, rests, pickups and cross-bar holds. Production uses **thematic recomposition**: a short rhythm, contour, opening, or characteristic interval from the head initializes a new solo theme. Later phrases develop that realization through harmonic adaptation, extension, answers, or optional brief callbacks. Each instrument establishes a distinct related theme instead of restarting from the corresponding head phrase at every source boundary. Close paraphrase remains available through `composer.compose(..., mode='paraphrase')` for comparison.
Each accompaniment is a source-derived canonical part, reused unchanged at corresponding form positions. Sparse shells/dyads and compact voicings retain essential chord information, with deliberate releases and varied rhythms. Neither backing changes in response to generated solos. Source vocals and electric melody retain their established behavior.
Treatment-specific contracts preserve the selected features only. Whole-source deviation applies to close paraphrase, including sounding durations; it does not penalize recomposition for changing unrelated notes. Before optional runs, realized pitch/time overlap and interval/rhythm fragments reject substantial near-copies (initial settings: 80% agreement across a two-bar window with at least four source attacks). Octave shifts, reattacks and extra attacks cannot dilute the duration comparison. Additional distance earns no bonus. The original source reference and the solo's realized theme remain separate in state and reports.
Scale permission and chord function remain distinct. Ordinary melody and runs must belong to all mapped collections they overlap; mapped accidentals such as C-sharp in D harmonic minor remain valid. A separate, complete enclosure contract can authorize one brief lower approach outside that map. Generic chromatic substitutions remain disabled. Basic chord members respect suspensions, alterations and omissions; slash-bass requirements do not automatically become melodic targets. Ordinary sounds lasting at least two quarter-note beats must remain chord members across every overlapping chord, unless an explicit valid color or prepared suspension applies. Tied notation is merged before evaluation. Terminal anchors must actually complete, and protected quotations retain their contracts.
Rhythm snippets and complete interval routes realize one- or two-bar edits jointly with chord-tone destinations. Routes retain their entry, complete timing, pitch path and arrival across barlines and collection changes. Later candidates receive the incoming note, position and realized theme before pitch generation. Run entries may extend an existing note without reattack. Intermediate arrivals continue the thought; the final destination has a closed-ending contract. Missing harmony creates explicit silence while preserving thematic memory. Short fragments around missing harmony are explicitly reduced and do not claim full motif fidelity.
Destination retrieval retains representatives of the actual chord degrees before narrowing timing/register choices. Thirds, sevenths, specified sixths, suspensions and altered fifths receive a small harmonic-function preference; roots and fifths remain eligible. The same bounded target cost considers incoming motion, recent destinations, the theme's direction and one following harmony. Terminal roots of the mapped tonic also remain competitive. A Dm triad does not acquire Dm7's seventh, and a non-chord slash bass does not become a melody target.
After selecting the strict acoustic/electric pair and its mapped runs, `solo/enclosures.py` compares sparse local ornaments with direct arrivals. The initial vocabulary is a mapped upper neighbor followed by a lower semitone neighbor, each an eighth note, then the exact preselected chord-tone target. The upper is at most three semitones above the target. The lower can already be mapped; chromatic status earns no extra reward. Each candidate replaces a continuously sounding beat before an existing intermediate stop or terminal hold, optionally revising a complete mapped route up to two beats earlier. Identifying features, protected quotations, rests, target timing and the whole required hold remain intact. No target is reattacked merely to make an ornament possible.
Validation checks the complete sounded gesture, all crossed harmony/scale spans, exact pitch and octave, arrival and release, and actual preparation/resolution timing. Only the contracted lower event can receive an exception. Missing, changed, clipped or unresolved targets invalidate the entire gesture. Tied splits do not change classification. A small chorus frontier retains direct options, with at most one enclosure per phrase and four per 32 bars; sparse use is a soft preference, not a quota. The home theme and development history stay strict. A previously sounding mapped upper neighbor may supply the final eighth-note approach segment without a new attack, but its complete duration still obeys ordinary sustained-note rules. Incidental repeated upper-neighbor attacks carry a local cost; deliberate repeated attacks remain available. Placement is resolved across the final solo; ornamentation never changes accompaniment. Build-time `enclosures_enabled=False` on compose/compose_pair/arrangement skips only this final pass; no runtime fields or performance expression are added.
The plain recomposed theme is exported independently of optional runs. Activity retains a soft 4–6 attacks-per-four-beats preference; occupancy remains diagnostic. No accents, dynamics, swing or other performance-expression changes are applied.
Search retains eight phrase alternatives and an eight-state chorus frontier, with two intermediate continuations per established theme. Up to 64 acoustic/electric pairs compete; equivalent themes after transposition are excluded while individual musical costs and pair similarity remain separate. Concrete caches include incoming state, harmony, timing and vocabulary. One bounded replan broadens eligible start and destination pitches. Exhaustion identifies the failed window without invoking a generic composer. Stable ordering and final tie-breaking preserve determinism.
Electric solos use strings 1–4 and favor roughly the electric melody's sounding register. Acoustic solos use strings 2–6 and favor about one octave below that melody. Both require frets 1–12 with no open notes. The register reference uses the original melody voice, excluding added chord voices, with a four-semitone median deadband and bounded preference; it is not a hard pitch corridor. Instrument profiles constrain pitch/anchor retrieval, complete routes, placement and validation, with cache keys separated by profile. Whole phrases can explore and return without a string-use quota. The four-fret hand-position model retains alternative endpoints and uses available time without claiming a maximum playable speed. Chords retain their existing 1–12 anchor policy, and the returning vocal pickup remains protected.
A clear return refers to the introduced theme's stored opening signature (normally three to five attacks with rhythm/rests), rather than selecting a different later three-note turn. Freer development retains a smaller core. Bounded gesture revisions can reconnect editable isolated notes without changing pitch order, attack count, or required arrivals. Existing anchors distinguish local settling, cadential resolution and handoff; a local settle carries the next harmonic destination into subsequent selection. These distinctions affect the solo, never its accompaniment.
Build reports in `generated_assets/analysis/` include selected source features, recurring solo themes, development lineage, anchors, complete routes, plain-versus-head and elaborated-versus-head comparisons, candidate diagnostics, destination degrees and complete enclosure contracts. Out-of-map approach notes are reported separately. Audition reports additionally show string use weighted by sounding duration and distinguish forced first-string notes from optional placements. These measurements establish technical behavior, not musical quality.
For comparisons, preserve the previous `elaborated/snapshot.json` under `build/solo_melody_auditions/paraphrase_baseline/`, then run `./modulus.py python -m generator.solo.lead_audition --capture` and `--render`. Open `build/solo_melody_auditions/index.html` for the original source, previous close paraphrase, new theme and theme with runs, alone and with fixed backing. Historical mixes retain their original backing; new production uses canonical accompaniment. Source controls preserve the imported melody and may expose original harmonic tensions; production variations must pass strict validation. The temporary reference archive remains ignored at `build/lead_melody_reference.zip`.
The current comparison is under `build/solo_foreground_auditions/index.html`: preserved production, a whole-phrase register/string-only control, the new plain theme, the selected strict theme before rhythmic revision and enclosures, and the final solo. Fixed comparisons use the same canonical backing and neutral playback. Full, opening-eight-bar and closing-four-bar comparisons include notation and passage reports; full solos also have unaccompanied versions. `before_enclosure` retains the exact selected pre-ornament realization, and `before_rhythm` isolates the timing revision. Preserve a previous snapshot as `before/snapshot.json`, then run `./modulus.py python -m generator.solo.audition --output build/solo_foreground_auditions --capture after` and `--render`. `--no-enclosures` provides a strict capture. Artifacts remain ignored by Git. Older enclosure comparisons remain under `build/solo_enclosure_auditions/`.
See [Independent Musical Generation](TECHNICAL_GUIDE.md#independent-musical-generation) for the dependency graph, data inventory/provenance, algorithms, constraints, single-role CLI, cache behavior and optional audition/reference commands. Full comparison artifacts for this update are under `build/independent_generation_comparison/`; the baseline is never a production input.
To inspect generated assets without building the full package, run:
@@ -136,17 +112,15 @@ To inspect generated assets without building the full package, run:
The `--check` path compares generation invariants against `data/expected/performance_summary.json`.
Modulus owns the pinned build-only dependencies in its optional `assets` group, selected by `tooling.python.groups` in `modulus.json`. Configure prepares `build/build_common/python`; `./modulus.py python` and CMake use that environment and the exported Modulus modules. Builds never install Python dependencies. After dependency pins change, run configure again. C++-only libraries do not opt in, and Python is not packaged for the Pi.
CMake builds engrave with two Python workers and share a disposable page cache under `build/build_common/engraving_cache`. Native and ARM packaging reuse unchanged pages; CI also retains this cache between runs. Music, playback, and catalog validation still run for every generation. Set `VAMP_ENGRAVING_JOBS` (1-16) to adjust concurrency, or set `VAMP_ENGRAVING_CACHE_DIR` to an empty CMake value to disable caching. Direct generator runs can opt in with `--jobs 2 --engraving-cache build/build_common/engraving_cache --progress`.
CMake builds engrave with two Python workers and share a disposable page cache under `build/build_common/engraving_cache`. Native and ARM packaging reuse unchanged pages; CI also retains this cache between runs. Cached musical roles are reused independently; music, playback, and catalog validation still run for every generation. Set `VAMP_ENGRAVING_JOBS` (1-16) to adjust concurrency, or set `VAMP_ENGRAVING_CACHE_DIR` to an empty CMake value to disable caching. Direct generator runs can opt in with `--jobs 2 --engraving-cache build/build_common/engraving_cache --progress`.
Identical notation bodies share layout and body rasterization even when titles or score identities differ; each score retains its own header, pages, music, and catalog identity. A `cold namespace` means no cache directory exists for the current renderer fingerprint. It does not mean that every score must be rendered independently: repeated bodies can still be reused within that build, including with persistent caching disabled. Progress separates full-score hits, body hits, newly rasterized bodies, and composed pages.
The build-time pipeline is Soundslice/MuseScore -> `.xml` -> musical model and rhythm plans -> part generation -> JSON, engraved PNG pages, generated_tone audio, Pico title artwork, and a read-only catalog database. Sources in `data/songs/` retain the seven-section performance form. Songs generate Acoustic, Electric, and Vocal parts in their authored key, without key variants or a key-selection menu. Measure numbers run continuously across the complete arrangement, starting at 1 in the lead-in; they do not restart with a new section or chorus. Pickups occupy the preceding measure, and exported excerpts retain their arrangement measure labels.
Accompaniment uses deterministic four-bar phrase cycles: a two-bar motif repeats with a one-beat variation in the fourth bar when a suitable candidate exists. Acoustic has separately planned bass and upper-chord rhythms, including simultaneous attacks, sharing one fixed playable voicing until the harmony changes in the canonical form. That complete part repeats unchanged across arrangement iterations. Bass, upper voices, and TAB positions stay constant across rests, barlines, and repeated chord symbols. Any defined chord tone can serve as the bass; explicit slash basses and inversions remain authoritative. The rhythms combine into one notated voice with no ties: each attack releases by the next attack or barline, simultaneous tones share a stem and duration, and rests appear only when the entire part is silent. Held notes are not reattacked. Electric accompaniment targets about two attacks per 4/4 bar, scaled for other meters. The original song informs its one-time rhythm choice; generated solos do not alter it. Its notes retain the selected rhythm's duration without a one-beat cap, stopping at chord changes or barlines and reusing the corresponding melody passage's chord shape when available and scale-compatible. Both parts remain tie-free; clipped binary durations that need ties shorten to one conventional note followed by silence. Rhythm snippets supply attacks and rests; tied continuations do not create accompaniment attacks. Structured harmony supplies chord tones. N.C. and absent harmony remain silent. The seven-section form is unchanged; soloing guitars play single-note phrases without self-accompaniment. Unsupported accompaniment meters and mid-measure meter changes fail explicitly.
All generated monophonic guitar material uses frets 1–12 without open strings. Accompaniment uses all legal compact positions; a chord can extend to fret 20 while retaining at least one sounding anchor at fret 12 or below and the existing three-fret span restriction. Electric source-melody harmonization retains its existing placement policy. Exact source pitches and ties are preserved; unplayable or unsupported input fails explicitly rather than being silently octave-folded.
There are no musical genre presets, genre defaults, or genre metadata. Obsolete `vamp:style` hints are rejected; visual styles, fonts, colors, and barline notation remain supported. Phrase cycles are written into the generated score and played once in reading order.
Guitar parts share standard tuning and chord-tone helpers but use separate acoustic and electric placement systems. Single notes in every guitar part, including solos, melodies, bass notes, and harmonization fallbacks, must use frets 1-12. Chords may extend above fret 12, exclude open strings, and fit within three consecutive fret positions. Frets 7-9 qualify; frets 7-10 do not. Each played acoustic or electric chord requires at least one occupied string at fret 12 or below; this anchor is an eligibility check, not a penalty for higher notes within the grip. Acoustic requires a bass on string 5 or 6 plus all three upper strings 4, 3, and 2. Electric uses chords on strings 1-3 or 1-4. Electric melody notes longer than a quarter note, including full tied runs, receive chords when playable; chord changes create fresh attacks even for short remaining fragments. Electric melodies are raised one octave; vocal registers stay unchanged. All parts still sound one octave below their generated notation, and explicit MusicXML transposition is honored once. Unplayable melody harmonizations remain single notes with a diagnostic; unplayable accompaniment or exact melody pitches fail generation. Acoustic bass attacks and upper-chord attacks qualify independently; an unsounded member of the underlying grip cannot supply the anchor. Held chord tones must retain a sounding anchor, including across notation ties. Solo registers, anchors, pitch paths, and placement all respect the single-note limit before selection. Unreachable exact pitches or explicit TAB fail without silent octave fitting.
There are no genre presets or runtime composition. The complete arranged score is played in reading order. The source-defined form and continuous whole-arrangement measure numbering remain unchanged.
All parts use two music systems per page, with a single system only when the score ends on an odd system. Lines break only between measures and share consistent staff/TAB widths. A measure that cannot fit at readable spacing fails with a diagnostic instead of being split. Tall notation is scaled uniformly to fit the two rows; guitar notation and TAB stay together and aligned. TAB displays frets and ties without duplicate rests; standard notation retains the complete rhythm. The generated `.pages/*.png` files are the same page images displayed by the product.