Scale Patterns
ci / checks (push) Successful in 48m15s

This commit is contained in:
khodowany
2026-09-30 03:17:06 -05:00
parent 7cad6db980
commit f5f0ab5eec
31 changed files with 626 additions and 32 deletions
+12
View File
@@ -171,6 +171,18 @@ At runtime the shared on-demand score loader serves both display and audio. A ba
`--once` additionally validates referenced audio without opening display/audio hardware. Runtime packages contain WAVs alongside pages and the SQLite catalog; the source XML and Python dependencies remain build-only.
### Solo Scale Maps
`generator/scales/` loads the 21 MusicXML patterns in `data/scales` once per build. Each file spells an ascending C-centered octave; seven distinct degrees define its intervals, including spellings such as B double-flat. The seven files in each family must be rotations of that family's first mode. The library transposes patterns internally, not song notes, and searches the 36 distinct pitch collections formed by the three families in twelve roots. No assignments or overrides are stored in song XML.
The analyzer requires a declared tonic and mode in the song's MusicXML key. A one-flat signature with `<mode>minor</mode>` means D minor, not F major. Exact rational harmony offsets are read after arrangement and pickup overlap handling. Full chord semantics, explicit extensions and alterations, degree omissions, and slash basses constrain compatibility; reduced guitar grips never remove these requirements. Existing chord syntax is unchanged: `7alt` shorthand is still rejected, while explicit alterations are supported.
Selection first preserves every required pitch. Recognized ii-V pairs, resolving dominants, and leading-tone diminished resolutions establish local destinations; the declared key provides the default context elsewhere. Minor cadences prefer harmonic minor and major cadences prefer the destination's major collection when compatible. The arrival chord is evaluated afresh, so a plain D-minor tonic need not retain a preceding cadence's raised seventh. Among equally appropriate choices, a deterministic dynamic program minimizes collection changes, then contextual pitch differences. Equivalent modes share a pitch collection rather than forcing new boundaries. This is a conservative harmonic heuristic, not a claim that ambiguous harmony has only one interpretation.
Only the soloing part receives compact `scale_spans`, with absolute rational start/end offsets, labels, and matched status. `N.C.` and solo boundaries stop annotations. Accompaniment, melody, pitches, TAB, and playback are unchanged; no solo notes are synthesized. Original melody notes are not constraints on these slash-only solo passages. Unmatched chords print `No exact scale match` and emit a source/measure/beat warning without changing the harmony. Invalid scale data or missing tonal metadata instead fail generation before publication.
Scale labels appear above chord symbols at collection changes and system starts. Detailed parent collections, source and arranged positions, chord-root modes, degrees, chord-tone targets, and selection reasons are written to `generated-assets/analysis/<song>.txt`. These reports are published transactionally with the build output but excluded from both installation and Docker runtime assets. The C++ runtime only displays the generated pages; it does not load the scale library or run harmonic analysis.
### Engraving Boundary
`generator/engraving/` is a custom Python engraver, not a wrapper around MuseScore or another notation engine. `generator.engraving.layout.layout_score(document, style, fonts)` produces immutable layout pages with exact source intervals, notation anchors and drawing primitives. `generator.engraving.raster.rasterize_page(page, fonts)` draws one page at four-times resolution and downsamples it. `generator.engraving.pipeline.engrave_tree(root, fonts)` is the asset-pipeline entry point. `fonts.Fonts`, `types.Style`, and `types.EngravingError` live in their respective engraving modules; page constants and `check_page` live in `validation`. Package initializers do not re-export these APIs. `generator/musicxml_writer.py` remains a round-trip/export utility and is not involved in engraving.