Skip to content

feat(gp): extract GP chord-diagram fingerings + GP8 chord names (E3)#522

Merged
byrongamatos merged 1 commit into
mainfrom
feat/gp-chord-diagram-fingerings
Jun 20, 2026
Merged

feat(gp): extract GP chord-diagram fingerings + GP8 chord names (E3)#522
byrongamatos merged 1 commit into
mainfrom
feat/gp-chord-diagram-fingerings

Conversation

@byrongamatos

Copy link
Copy Markdown
Contributor

What

GP imports landed chord templates with blank fingerings (GP5 + GP8) and blank names (GP8). E0 (merged) preserves authored chord-template metadata across save and E1 (merged) lets users author chord name + per-string fingering keyed by fret pattern, and the highway renderers display those fingerings — but imports had nothing to show. E3 extracts the real chord-diagram data so imports arrive rich, keyed on the same fret-pattern join key the editor (E0) and GP5 already use.

How

GP8 — lib/gp2rs_gpx.py

  • New _parse_chord_diagrams(track_el, string_pitches) parses the per-track GPIF Property[@name="DiagramCollection"] (each Item @name + <Diagram> with <Fret> / <Fingering><Position>) into a fret-pattern → {name, fingers} map.
  • Enriches the matching played voicing at the chord-template build site.
  • Diagram string indices live in the same positional space as note String indices, so they go through the same pitch-rank transform (_rs_string_order) — robust to GP6 .gpx (high→low) vs GP8 .gp (low→high). <Fret fret> is treated as the absolute fret (baseFret is display-only).

GP5 — lib/gp2rs.py

  • pyguitarpro exposes the voicing on beat.effect.chord (.strings indexed 0 = highest string; .fingerings the parallel Fingering enum, already RS finger ints). New _chord_fingers maps these into RS string order.
  • The template enrich back-fills any still-blank template, so the annotated chord attaches even when an earlier unannotated strum of the same voicing created the template first (a real case in joplin-janis-piece_of_my_heart.gp4).

Invariants

  • Finger encoding none/open=-1, thumb=0, index=1, middle=2, ring=3, pinky=4 — matches the editor E1 + RS serializer (verified against feedback-plugin-editor chord_relink.test.js).
  • Only enriches on exact (width-normalized) fret-pattern match — never invents fingers.
  • No regression: charts without diagram data import identically (blank name/fingers).

Tests

tests/test_gp2rs_gpx.py (GP8 enrich + no-diagram negative), tests/test_gp2rs.py (GP5 enrich, no-diagram negative, blank-template back-fill). Fixture-free, matching existing style.

PYTHONPATH=lib python -m pytest tests/test_gp2rs.py tests/test_gp2rs_gpx.py tests/test_gp2rs_drums.py -q
# 170 passed

Also verified end-to-end against real files: GP8_Test.gpchordName="G" + fingers [2,1,-1,-1,3,4]; joplin-janis-piece_of_my_heart.gp4 → A/B/F#m barre chords with correct fingerings.

Codex preflight (read-only): no P1/P2 issues; independently confirmed the parser output against the real GP8 sample.

Closes #335. Part of #334.

🤖 Generated with Claude Code

GP imports previously landed chord templates with blank fingerings (GP5 +
GP8) and blank names (GP8), so the editor/highway had nothing to show even
though E0 preserves and E1 authors that data. E3 extracts the real chord
diagrams so imports arrive rich, keyed on the same fret-pattern join key the
editor (E0) and GP5 already use.

GP8 (lib/gp2rs_gpx.py): parse the per-track GPIF DiagramCollection
(Item @name + Diagram Fret/Fingering) into a fret-pattern -> {name, fingers}
map and enrich matching played voicings at the template build site. Diagram
string indices share the note String index space, so they go through the same
pitch-rank transform; <Fret fret> is treated as absolute.

GP5 (lib/gp2rs.py): pyguitarpro exposes the voicing on beat.effect.chord
(.strings indexed 0=highest string, .fingerings the parallel Fingering enum,
already RS finger ints). New _chord_fingers maps them to RS string order; the
template enrich now back-fills any still-blank template so the annotated chord
attaches even when an earlier unannotated strum of the same voicing created it.

Finger encoding (none/open=-1, thumb=0, index=1, middle=2, ring=3, pinky=4)
matches the editor E1 + RS serializer. Only enriches on exact fret-pattern
match; diagram-less charts import identically (blank). Verified end-to-end
against real files (GP8_Test.gp, joplin-janis-piece_of_my_heart.gp4).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@byrongamatos
byrongamatos merged commit c557742 into main Jun 20, 2026
0 of 3 checks passed
@byrongamatos
byrongamatos deleted the feat/gp-chord-diagram-fingerings branch June 20, 2026 18:44
byrongamatos added a commit that referenced this pull request Jun 20, 2026
…uple name/fingers (#523)

Post-merge Codex review of E3 (PR #522) flagged two GP5 edge cases:

- P2: enrichment applied the diagram's name/fingers to the played template
  without checking the diagram described the voicing actually played. A
  mismatched chord label/diagram could mis-name/finger the played template, and
  the back-fill spread it to other strums of the same played pattern. Now gated
  on an exact, full-span fret-pattern match (new _chord_diagram_frets), mirroring
  the GP8 guard — and comparing over max(played width, num_strings) so a
  7/8-string diagram can't falsely match a narrower played voicing.
- P3: name and fingers back-fill were coupled (a name-only first annotation
  blocked a later beat's fingers). Now independent.

Codex re-reviewed twice (the first match-gate trimmed extended strings; fixed by
the full-span compare); final pass clean. +4 tests (mismatch-not-applied,
name-then-fingers decoupled, higher-position absolute match, 7-string extended
string regression). 163 GP tests pass.

Follow-up to #522. Part of #334.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GP import: extract chord-diagram fingerings (GP5/GP8) + GP8 chord names

1 participant