fix(core): GPIF imports use string 1 = highest and read staff tunings - #198
Merged
Merged
Conversation
…pitch GPIF (GP6 .gpx, GP7 .gp) lists a tuning low string first and numbers a note's string from 0 = lowest; griff's model is string 1 = highest. Two defects, measured on a 410-file Guitar Pro corpus against the GPIF `Midi` note property: - track-level tuning (the GP6 shape) imports low string first and numbers positions from the low string: pitches right, every position mirrored (177 GP6 tracks); - staff-level tuning only (the GP7 shape) is never reached by the guitarpro crate, which falls back to a high-first Standard E while notes stay numbered from the low string: 739 of 344,274 GP7 notes carried the pitch their GPIF `Midi` value states (314 GP7 tracks). Four failing tests over authored GPIF text (no copyrighted tab) packed with the crate's public BCFS/BCFZ writer: track-level tuning, staff-only tuning, staff tuning beside a tuning-less track <Properties>, and a seven-string tuning. Each pins tuning high-first, positions renumbered, and pitch_at(position) == pitch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GPIF (GP6 .gpx, GP7/8 .gp) lists a tuning lowest string first and numbers a note's string from 0 = lowest; GP3/4/5 and griff (ADR-0018) number from 1 = highest. The adapter now reads the GPIF document itself (`guitarpro::io::gpx::read_gpx` / `read_gp`), runs the crate's `read_gpif` on it, and renumbers every track once at the boundary: - the tuning comes from the GPIF track — its own properties (GP6) or else the first staff carrying one (GP7/8). The guitarpro crate reaches the staff tuning only when a track has an empty property block, so GP7 tracks without track properties silently fell back to a high-first Standard E while their notes stayed numbered from the low string: wrong pitch on nearly every GP7 note; - `track.strings` becomes highest string first and each note's raw string r of n becomes n − r; a raw string outside the tuning becomes 0 and is refused like any invalid GP string. A track with no GPIF tuning (drums, keys) keeps the crate's fallback, read in GPIF order. With every source sharing one convention, the per-format `zero_indexed` plumbing (gp_one_indexed_string, StringCtx::zero_indexed, the extra parameters) is removed. The unit tests that pinned the mirrored numbering (GP6 raw string 0 → griff string 1) are replaced by tests of the renumbering, including the fallback and out-of-range cases. Verified against the GPIF `Midi` note property over a 410-file corpus (314 tuned GP7 tracks, 329,501 non-tie notes): (string, fret, pitch) now matches tuning + fret for 100% of notes and the stated `Midi` for 98.1% (the rest are transposed or percussion parts whose `Midi` is not tuning + fret); before, 0.2% of GP7 notes had their `Midi` pitch. All 177 tuned GP6 tracks now import highest string first; GP6 notes carry no `Midi` property to check against. cargo test --workspace green (1,692 tests; `missing_file_golden` skipped locally only — its golden holds the English OS error text and this host reports it in Russian); clippy -D warnings clean for griff-core. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PhysShell
pushed a commit
that referenced
this pull request
Sep 16, 2026
The audit's corpus import gave nearly every GP7 note the wrong pitch (fallback Standard E tuning, notes numbered from the low string; fixed in #198). Adds a dated Correction section with the re-measured numbers on the fixed importer — refitted weights, holdout agreement for all four models, human-optimal rates, and CP-SAT-verified ceilings for v1 (36.2% vs DP 35.8%) and v1-fit (55.5% vs 44.1%) with zero solver gap on all 1,954 holdout lines — and states which conclusions hold (all), which got stronger (v1-fit is too flat), which shifted (absolute agreement, fitted weights; the hand model no longer beats fitted v1 on agreement), and which results were not re-run (repeat consistency, hand-model oracle). The side-finding section now points at the GP7 half, and the decision record flags its numbers as pre-fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PhysShell
pushed a commit
that referenced
this pull request
Sep 17, 2026
# Conflicts: # docs/decisions.log.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
GPIF imports (GP6
.gpx, GP7/8.gp) now follow griff's string convention — string 1 = highest (ADR-0018) — and GP7 imports get the right pitch.GPIF lists a tuning lowest string first and numbers a note's string from 0 = lowest. Two defects followed:
<Staves><Staff>(314 tracks)guitarpro0.4.2 never reads the staff tuning, falls back to a high-first Standard E while notes stay numbered from the low string — 0.2% of notes had the pitch their GPIFMidiproperty statesMidifor 98.1%The remaining 1.9%
Midimismatches are notes where GPIF'sMidiis not tuning + fret at all (octave-transposed and percussion parts) — out of scope here.How
import_gp_scorereads the GPIF document itself (guitarpro::io::gpx::read_gpx/read_gp), runs the crate'sread_gpif, then renumbers each track once at the boundary:track.stringshighest first; a note's raw stringrofnbecomesn − r; out-of-range → 0, refused like any invalid GP string;Every source now shares the GP3/4/5 convention, so the per-format
zero_indexedplumbing is gone. The unit tests that pinned the mirrored numbering (GP6 raw string 0 → griff string 1) are replaced by tests of the renumbering.Tests
1af6df3), then green (8d1dcb2).core/tests/gp_gpif_strings.rs: authored GPIF text (no copyrighted tab) packed with the crate's public BCFS/BCFZ writer — track-level tuning, staff-only tuning, staff tuning beside a tuning-less track property block, seven strings. Each asserts tuning order, positions, pitches, andpitch_at(position) == pitch.mirror_gpif_stringandnormalise_track_strings(GPIF tuning, crate fallback, out-of-range strings).Midiproperty as above (local, corpus not committed).cargo test --workspace: green locally (1,692 tests).missing_file_goldenwas skipped locally only: its golden holds the English OS error text and the test host reports it in Russian — unrelated to this change.cargo clippy -p griff-core --all-targets -- -D warningsandcargo fmt --checkclean.Notes
guitarprocrate defect; this adapter no longer depends on it. No upstream issue filed yet.🤖 Generated with Claude Code