Summary
lib/gp2rs.py (the binary Guitar Pro → arrangement-XML converter, used for GP3/GP4/GP5 import) never reads or propagates the arpeggio flag that Guitar Pro authors attach to a beat/chord. As a result, every GP-sourced chart imports its arpeggiated passages as ordinary strummed chords, and the downstream .feedpak handshape data (handshapes[].arp) is always false for GP imports — even when the source GP file explicitly marks the chord as an arpeggio.
This is not a request for a new wire-format concept — the arp field already exists and is spec-legal (see "Where this fits" below). It's a bug/gap in one converter: the flag exists in pyguitarpro's beat data, and there's a place downstream ready to receive it, but gp2rs.py never wires the two together.
Where this fits (already spec-legal, no FEP needed)
feedpak-spec/spec/feedpak-v1.md §6.5/§6.6 already define handshape.arp (boolean — "treat as an arpeggio span rather than a strummed hold") and chord-template arp.
feedback-plugin-feedpakr's feedpakr_handshapes.py (derive_handshapes()) already reads arp straight off the chord template the wire arrangement provides — i.e. the downstream consumer is correctly implemented and just waiting for the flag to actually be set.
- The break is entirely upstream, in this repo.
What's happening in lib/gp2rs.py
-
ChordTemplate (around line 111) is defined as:
@dataclass
class ChordTemplate:
name: str
frets: list[int] # per string, -1 = unused
fingers: list[int] # per string, -1 = unused
There is no arp/arpeggio field at all.
-
Chord templates are built and appended around line 1027 (chord_templates.append(ChordTemplate(name="", frets=list(frets), fingers=[-1] * width))) with no arpeggio detection anywhere in that code path.
-
gp2rs.py does already read other per-beat effect data off pyguitarpro's guitarpro.BeatEffect / guitarpro.NoteEffect objects in this same function — e.g.:
_gp_pick_direction() (line ~274) reads effect.stroke.direction / effect.pickStroke for strum direction, with detailed comments on which pyguitarpro field GP writes for authored chord strums vs. individual note picks.
getattr(eff, "letRing", False) (line ~911) is read and mapped to link_next.
So the plumbing pattern for "read a pyguitarpro beat/note effect flag → set it on the wire model" is already established in this file; arpeggio just isn't one of the flags being read.
-
The only place in the codebase that currently sets arp/arpeggio on a chord template or handshape is the legacy arrangement-XML path (RS2014/EOF <handShape> elements with a displayName ending in -arp or an explicit arp attribute) — i.e. the loose-folder importer, not the binary GP parser. GP-authored arpeggio data specifically is what's being lost.
What needs to happen
- Identify the pyguitarpro field(s) that carry arpeggio/"let ring as arpeggio" semantics for a chord beat. (pyguitarpro exposes GP's
BeatStroke with a "brush"/arpeggio-style stroke distinct from a simple down/up strum — worth checking guitarpro.BeatStrokeDirection and any arpeggio-specific enum/flag alongside it, and cross-checking against how EOF/RS2014 authoring tools decide when to emit arp="1" on a <handShape>, since that's the semantics we're trying to match.)
- Add an
arp: bool = False field to ChordTemplate in gp2rs.py.
- In the chord-template construction/enrichment code (~line 1000-1045), set
arp=True when the source GP beat carries that flag — following the existing "enrich from the GP chord diagram, only when it matches the actually-played voicing" guard pattern already used for name/fingers back-fill.
- Thread
arp through to the arrangement XML output (wherever ChordTemplate fields are currently serialized — the fret/finger writing near the XML-emission code, mirroring how linkNext/pickDirection attrs are written per-note around line 1277/1316).
- Verify
feedpakr_handshapes.py's derive_handshapes() picks it up correctly with no changes needed on the feedpakr side (per the earlier investigation, it already reads templates[cid].get('arp') — this should "just work" once gp2rs.py sets the flag).
- Add a regression test in
tests/ (this repo uses pytest, tests/test_*.py, config in pyproject.toml) importing a small fixture GP file with a known authored arpeggio and asserting the resulting ChordTemplate.arp / arrangement-XML output.
Context / mental model
For anyone unfamiliar with the RS/GP arpeggio convention: an arpeggio marker in Rocksmith-style notation is a "hold this chord shape" indicator, not an instruction to strike all strings at once. The shape shown establishes the fretting-hand handshape; only the individually highlighted notes crossing the strike line are actually picked at that moment, in sequence. Rocksmith 2014 arrangements generally represent this via the handshape mechanism (arp flag) rather than a dedicated arpeggio note-type — which is exactly the mechanism feedpak's handshape.arp already models. The gap here is purely that GP-sourced imports never populate it.
Repos involved (for reference, no action needed elsewhere)
get-flashbacks/feedpak-spec — format already supports this (§6.5/§6.6), no changes needed.
get-flashbacks/feedback-plugin-feedpakr — feedpakr_handshapes.py already correctly consumes arp from chord templates, no changes needed.
get-flashbacks/feedback (this repo) — lib/gp2rs.py is where the fix belongs.
Summary
lib/gp2rs.py(the binary Guitar Pro → arrangement-XML converter, used for GP3/GP4/GP5 import) never reads or propagates the arpeggio flag that Guitar Pro authors attach to a beat/chord. As a result, every GP-sourced chart imports its arpeggiated passages as ordinary strummed chords, and the downstream.feedpakhandshape data (handshapes[].arp) is alwaysfalsefor GP imports — even when the source GP file explicitly marks the chord as an arpeggio.This is not a request for a new wire-format concept — the
arpfield already exists and is spec-legal (see "Where this fits" below). It's a bug/gap in one converter: the flag exists in pyguitarpro's beat data, and there's a place downstream ready to receive it, butgp2rs.pynever wires the two together.Where this fits (already spec-legal, no FEP needed)
feedpak-spec/spec/feedpak-v1.md§6.5/§6.6 already definehandshape.arp(boolean — "treat as an arpeggio span rather than a strummed hold") and chord-templatearp.feedback-plugin-feedpakr'sfeedpakr_handshapes.py(derive_handshapes()) already readsarpstraight off the chord template the wire arrangement provides — i.e. the downstream consumer is correctly implemented and just waiting for the flag to actually be set.What's happening in
lib/gp2rs.pyChordTemplate(around line 111) is defined as:There is no
arp/arpeggio field at all.Chord templates are built and appended around line 1027 (
chord_templates.append(ChordTemplate(name="", frets=list(frets), fingers=[-1] * width))) with no arpeggio detection anywhere in that code path.gp2rs.pydoes already read other per-beat effect data off pyguitarpro'sguitarpro.BeatEffect/guitarpro.NoteEffectobjects in this same function — e.g.:_gp_pick_direction()(line ~274) readseffect.stroke.direction/effect.pickStrokefor strum direction, with detailed comments on which pyguitarpro field GP writes for authored chord strums vs. individual note picks.getattr(eff, "letRing", False)(line ~911) is read and mapped tolink_next.So the plumbing pattern for "read a pyguitarpro beat/note effect flag → set it on the wire model" is already established in this file; arpeggio just isn't one of the flags being read.
The only place in the codebase that currently sets
arp/arpeggioon a chord template or handshape is the legacy arrangement-XML path (RS2014/EOF<handShape>elements with adisplayNameending in-arpor an explicitarpattribute) — i.e. the loose-folder importer, not the binary GP parser. GP-authored arpeggio data specifically is what's being lost.What needs to happen
BeatStrokewith a "brush"/arpeggio-style stroke distinct from a simple down/up strum — worth checkingguitarpro.BeatStrokeDirectionand any arpeggio-specific enum/flag alongside it, and cross-checking against how EOF/RS2014 authoring tools decide when to emitarp="1"on a<handShape>, since that's the semantics we're trying to match.)arp: bool = Falsefield toChordTemplateingp2rs.py.arp=Truewhen the source GP beat carries that flag — following the existing "enrich from the GP chord diagram, only when it matches the actually-played voicing" guard pattern already used for name/fingers back-fill.arpthrough to the arrangement XML output (whereverChordTemplatefields are currently serialized — the fret/finger writing near the XML-emission code, mirroring howlinkNext/pickDirectionattrs are written per-note around line 1277/1316).feedpakr_handshapes.py'sderive_handshapes()picks it up correctly with no changes needed on the feedpakr side (per the earlier investigation, it already readstemplates[cid].get('arp')— this should "just work" once gp2rs.py sets the flag).tests/(this repo usespytest,tests/test_*.py, config inpyproject.toml) importing a small fixture GP file with a known authored arpeggio and asserting the resultingChordTemplate.arp/ arrangement-XML output.Context / mental model
For anyone unfamiliar with the RS/GP arpeggio convention: an arpeggio marker in Rocksmith-style notation is a "hold this chord shape" indicator, not an instruction to strike all strings at once. The shape shown establishes the fretting-hand handshape; only the individually highlighted notes crossing the strike line are actually picked at that moment, in sequence. Rocksmith 2014 arrangements generally represent this via the handshape mechanism (
arpflag) rather than a dedicated arpeggio note-type — which is exactly the mechanismfeedpak'shandshape.arpalready models. The gap here is purely that GP-sourced imports never populate it.Repos involved (for reference, no action needed elsewhere)
get-flashbacks/feedpak-spec— format already supports this (§6.5/§6.6), no changes needed.get-flashbacks/feedback-plugin-feedpakr—feedpakr_handshapes.pyalready correctly consumesarpfrom chord templates, no changes needed.get-flashbacks/feedback(this repo) —lib/gp2rs.pyis where the fix belongs.