+6
-6
@@ -135,25 +135,25 @@ All three parts use octave-transposing notation: written notes sound one octave
|
||||
|
||||
`pitch.py` resolves explicit MusicXML instrument transposition once before part generation. Explicit zero transposition is also authoritative. Octave-clef exports already encode sounding pitch in their note values, so they do not receive another implicit octave subtraction. Generated parts carry an explicit `transpose.octave_change: -1`; guitar placement and audio read that shared state. Internal concert-pitch normalization and written-pitch conversion cancel for ordinary source notation except for the intentional song electric melody octave increase. There is no automatic octave fitting, vocal-specific range shift, or key transposition.
|
||||
|
||||
`guitar.py` searches standard tuning E2 A2 D3 G3 B3 E4, frets 1-20 inclusive, with at most four frets between the lowest and highest positions. Open strings are excluded from chords and single-note melodies alike. A pitch that only an open string could produce fails generation rather than being octave-shifted or omitted. Exact melody tones are never dropped or replaced. Simultaneous tones occupy distinct strings, and sustained/tied tones retain their assignments. Acoustic grips use one bass on string 5 or 6 and two or three consecutive strings within 2-4, with zero or one unused string between bass and upper voices. Both rhythmic voices must fit one complete grip, even when only one attacks. Each continuous acoustic harmony span keeps the same bass pitch, upper voicing, and string/fret positions. Any defined chord tone can serve as the acoustic bass, including thirds, sevenths, and extensions. Explicit acoustic slash basses and inversions override these choices, and the bass remains the lowest sounding pitch. There is no alternating-bass substitution.
|
||||
`fretboard.py` owns standard tuning E2 A2 D3 G3 B3 E4, fret positions, chord coverage, and pitch spelling. Both placement systems use frets 1-20 inclusive, exclude open strings, and share a maximum fret difference of three. `guitar.py` handles electric voicing and exact/held melody placement. Exact melody tones are never dropped or replaced, and sustained/tied tones retain their assignments. `acoustic_voicing.py` instead searches four named voices: a bass on string 5 or 6, and one voice on each of strings 4, 3, and 2. Acoustic assignments also require at least one occupied string at fret 12 or below. These are hard constraints: a failed voicing is not widened or reduced to two upper strings. Any defined chord tone, including thirds, sevenths, and extensions, can be the acoustic bass. Explicit slash basses and inversions override these choices; the bass remains the lowest sounding pitch.
|
||||
|
||||
Shared `ChordRequirements` separate mandatory pitch classes, allowed pitch classes, root-or-fifth alternatives, and bass constraints. Every complete generated guitar grip must contain the root, the fifth, or both, with no preference for the root itself. This rule applies equally to acoustic accompaniment, electric accompaniment, and electric melody chords, not isolated bass/upper attacks or unharmonized melody notes. The fifth follows the chord's actual degree, including diminished or augmented fifths. Explicitly removed degrees are never restored, and a harmony removing both root and fifth cannot generate a guitar chord. Defining thirds/suspensions, sixths/sevenths, alterations, and required extensions remain mandatory; an altered fifth cannot be omitted merely because the root is present.
|
||||
|
||||
Acoustic spans follow the harmony timeline, including changes during silence. Barline crossings, rests, repeated identical harmonies, and section labels do not reset the grip while accompaniment continues. Changed chord kinds, roots, degrees, basses, or inversions start a new span. N.C. and non-accompaniment passages end a span. Returning to a chord after a different harmony starts a new decision, not a song-wide fixed fingering. A span with attacks is placed once as a complete grip, then each bass or upper attack receives its corresponding subset; simultaneous attacks receive both. If no complete grip satisfies the existing harmonic and fretboard constraints, generation fails with passage context without replacing published assets. Span state is build-only and does not add runtime fields.
|
||||
Acoustic spans follow the harmony timeline, including changes during silence. Within an iteration, barlines, rests, and repeated identical harmonies do not reset the voicing. Changed chord kinds, roots, degrees, basses, or inversions start a new span; N.C. and non-accompaniment passages end a span. A formal section label starts a new iteration and independent search, even if the harmony repeats. There is no last-to-first transition or shared song-wide chord dictionary. Rests and no-chord passages add no assignments; the next sounding harmony within the iteration is measured from the preceding assignment. A span with attacks is placed once as a complete four-voice assignment, then each bass or upper attack receives its subset; simultaneous attacks receive all four strings. Every iteration is planned before pitches are materialized, so failure leaves the document unchanged. Existing staged asset publication preserves previously published assets. Iteration and search state are build-only and add no runtime fields.
|
||||
|
||||
Electric chord blocks use strings 1-3 or 1-4, including string 1. Rootless voicings containing the fifth and octave doublings are ordinary candidates. An unaltered fifth may be omitted when the root is present, and unaltered intermediate ninth/eleventh extensions may be omitted. Exact melody pitches, including non-chord tones, remain unchanged.
|
||||
|
||||
`melody.py` treats the full tied duration as one note when testing whether it exceeds one quarter-note beat. Qualifying notes receive a chord at their initial attack and at each subsequent changed harmony, even if a resulting fragment is less than one beat. Changed harmonies break ties and reattack the melody; repeated identical harmonies do not. N.C. releases the added voices while preserving the melody's sustain. Added tones through unchanged harmony retain their own ties. These melody rules are independent of accompaniment duration spelling. If no valid chord fits, the exact melody remains with a diagnostic; it is not octave-wrapped or omitted.
|
||||
|
||||
Placement uses the ordered `VoicingCost` components: electric string shortfall from four, melody covered, number of tones above the melody, combined effort, and missing optional pitch classes. These costs accumulate over the whole passage, so effort cannot outweigh the earlier electric musical priorities. Melody height compares sounding pitch; unison doubling does not cover it. Electric accompaniment uses the same ranking without the melody-height terms. Acoustic does not receive electric fullness penalties: a simpler three-note grip can beat a more awkward four-note grip.
|
||||
Electric placement uses the ordered `VoicingCost` components: string shortfall from four, melody covered, number of tones above the melody, combined effort, and missing optional pitch classes. These costs accumulate over the whole passage, so effort cannot outweigh the earlier electric musical priorities. Melody height compares sounding pitch; unison doubling does not cover it. Electric accompaniment uses the same ranking without the melody-height terms. The acoustic solver does not use this ranking.
|
||||
|
||||
Acoustic candidate selection separates harmonic validity from reach and sequence scoring. `physical_reach()` computes `round(1_000_000 * (2 ** (-lowest_fret / 12) - 2 ** (-highest_fret / 12)))`, normalized to scale length. The preferred limit is the reach from fret 7 to fret 10, inclusive. If any valid grip meets it, wider grips are excluded before movement optimization. Otherwise only the least-reaching valid grips remain, with a passage-specific warning. The hard four-fret difference and frets 1-20 still apply. Among the retained candidates, triads with exactly degrees 1, 3, and 5 prefer all three tones when feasible. Authored omissions are never restored; seventh, extended, and suspended chords retain their existing coverage rules. Complete triads do not justify exceeding the preferred reach when a reduced comfortable grip exists. Candidate filtering is cached independently of rhythmic events and does not alter electric placement.
|
||||
Acoustic candidates are generated from chord-tone positions on the four voices, not a predefined shape dictionary or the electric candidate search. All four positions must satisfy the shared harmonic requirements and acoustic fret constraints, even when only bass or upper notes attack. Triads whose effective degrees are exactly 1, 3, and 5 prefer complete three-tone coverage when feasible; `harmony.is_triad()` examines authored chord semantics rather than voicing size. Doubling chord tones can fill four strings without inventing additional harmony. Authored omissions are never restored. Seventh and extended chords keep their existing coverage rules. Candidate sets are cached by harmonic requirements and triad completeness; no physical-reach filter, fallback widening, or position-center pruning is applied.
|
||||
|
||||
`electric.py` links song accompaniment attacks to harmonized melody events using authored source positions, not displayed measure numbers or a song-wide chord dictionary. References stay inside the corresponding source harmony span and must match its structured chord. Within a span, an attack uses the latest available melody grip at or before its source position, or the first later grip if it precedes all melody chords. This allows different shapes for the same chord in different passages. After guitar placement and melody tie resolution, linked stabs copy the actual melody pitches and TAB positions while retaining their own IDs, timing, and written durations; melody ties and markings are not copied. A melody that remains a single note provides no grip. Passages without a matching playable three- or four-string melody chord, including altered endings without a corresponding reference, retain independently generated electric shapes. No reference metadata reaches runtime JSON.
|
||||
|
||||
After candidate filtering, acoustic effort is `highest_fret + 2 * max(0, highest_fret - 12) + 2 * max(0, distinct_frets - 1)`. There is no raw-span penalty or continuing reward for smaller physical reach within the preferred range. Electric retains the same formula plus `3 * fret_span` and its existing movement metric, the Manhattan distance between doubled fret/string position centers, with the exact small-grid distance transform used for independent attacks. Acoustic still adds twice its per-string movement: fret changes on retained strings plus one unit per added or released string. An unchanged grip costs zero movement. Exact candidate-to-candidate dynamic programming retains all preferred acoustic grips, including different grips with equal centers. Exact, unharmonized melody placement retains `movement + 2 * max(0, highest_fret - 12) + fret_span`.
|
||||
Acoustic transition cost is the sum of absolute fret changes for all four named voices, plus one when the bass switches between strings 5 and 6. For example, bass string 5 fret 7 to string 6 fret 9 costs three steps, not just a string-change charge. An unchanged assignment costs zero. Exact dynamic programming minimizes total travel per iteration; equal travel costs prefer fewer missing optional chord tones, followed by stable position ordering. The starting assignment has no position cost. Harmony spans, not rhythmic attacks, determine the transitions. There are no acoustic register, distinct-fret, span, or physical-reach scoring terms. The three-fret limit and fret-12 anchor are eligibility checks, not preferences.
|
||||
|
||||
Generated chord height contributes one point per fret throughout the allowed range. The shared `PREFERRED_MAX_FRET` remains 12, above which each excess fret adds two more points. Lower positions still win when reach eligibility, shape simplicity, and movement are comparable. Autumn Leaves can use Em7b5/G at `6:3, 4:2, 3:3, 2:3` followed by A7b9/G at `6:3, 4:2, 3:3, 2:2`, moving only one note by one fret. The original mid-neck grips at `5:7, 4:8, 3:7, 2:8` and `5:7, 4:8, 3:6, 2:8` remain valid nearby alternatives. Dm/F at `5:8, 3:7, 2:10` meets the preferred reach limit exactly. These are regression examples, not mandatory song-specific shapes, and generated inversions do not rewrite the source chord labels. Acoustic shape costs are charged once per harmony span, independent of rhythm density, and transitions compare complete grips rather than whichever lane last sounded. Pure melody tie continuations add no fresh shape or movement cost. There is no automatic octave fitting or finger-assignment model. Stable position ordering resolves equal costs.
|
||||
Electric effort remains `highest_fret + 2 * max(0, highest_fret - 12) + 2 * max(0, distinct_frets - 1) + 3 * fret_span`, with Manhattan movement between doubled fret/string position centers. Its small-grid distance transform and exact melody constraints are unchanged. Unharmonized melody placement retains `movement + 2 * max(0, highest_fret - 12) + fret_span`, and pure tie continuations add no fresh shape or movement cost. The acoustic Autumn Leaves lead-in can use Em7b5/G at `6:3, 4:2, 3:3, 2:3` followed by A7b9/G at `6:3, 4:2, 3:3, 2:2`, moving only the second string by one fret. This is a regression example, not a prescribed chord shape; generated bass inversions do not rewrite source chord labels.
|
||||
|
||||
There is no finger assignment, barre logic, or predefined chord-shape dictionary. These are proximity and fretboard-feasibility constraints, not a guarantee of comfortable fingering. Nonstandard tuning, capos, microtonal frets, and unplayable passages fail with source/part/event context; there is no slash fallback for a failed chord. Existing assets remain untouched after failure.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user