mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-07-26 14:52:13 +00:00
feed the rabbit
Updated the docstring for _load_gpif to clarify supported file formats and improved error messages for unrecognized containers.L (cherry picked from commit 1866c72e53339a10d6f184d21c2261e9f0b21395)
This commit is contained in:
parent
eb2121b4bc
commit
bd22951874
@ -133,15 +133,35 @@ def _parse_bcfs(bcfs: bytes) -> dict:
|
||||
|
||||
|
||||
def _load_gpif(gp_path: str) -> ET.Element:
|
||||
"""Load and parse score.gpif from a .gpx file."""
|
||||
"""Load and parse score.gpif from a .gpx (GP6) or .gp (GP7/GP8) file.
|
||||
|
||||
GP6 (.gpx): custom BCFZ/BCFS binary container holding score.gpif.
|
||||
GP7/GP8 (.gp): standard ZIP archive holding Content/score.gpif.
|
||||
Both formats use the same GPIF XML schema inside, so a single parser
|
||||
handles all versions once the outer container is unpacked.
|
||||
"""
|
||||
with open(gp_path, 'rb') as fh:
|
||||
raw = fh.read()
|
||||
|
||||
# GP7/GP8: ZIP container (PK magic)
|
||||
if raw[:2] == b'PK':
|
||||
import zipfile
|
||||
import io as _io
|
||||
with zipfile.ZipFile(_io.BytesIO(raw)) as zf:
|
||||
if 'Content/score.gpif' not in zf.namelist():
|
||||
raise ValueError("Content/score.gpif not found in GP7/GP8 ZIP container")
|
||||
return ET.fromstring(zf.read('Content/score.gpif'))
|
||||
|
||||
# GP6 (.gpx): BCFZ compressed or raw BCFS
|
||||
if raw[:4] == b'BCFZ':
|
||||
bcfs = _decompress_bcfz(raw)
|
||||
elif raw[:4] == b'BCFS':
|
||||
bcfs = raw
|
||||
else:
|
||||
raise ValueError(f"Not a GPX file (magic: {raw[:4]!r})")
|
||||
raise ValueError(
|
||||
f"Unrecognised Guitar Pro container (magic: {raw[:4]!r}). "
|
||||
f"Supported: .gpx (GP6, BCFZ/BCFS) and .gp (GP7/GP8, ZIP)."
|
||||
)
|
||||
fs = _parse_bcfs(bcfs)
|
||||
if 'score.gpif' not in fs:
|
||||
raise ValueError("score.gpif not found in GPX container")
|
||||
@ -589,7 +609,8 @@ def list_tracks(gp_path: str) -> list[dict]:
|
||||
and not t['string_pitches'] # no string tuning = not guitar-family
|
||||
and 32 <= t['midi_program'] <= 39
|
||||
) or (
|
||||
t['string_pitches']
|
||||
not t['is_drums'] # explicit guard: drums can have low string pitches
|
||||
and t['string_pitches']
|
||||
and max(t['string_pitches']) <= 48 # bass top string ≤ C3
|
||||
)
|
||||
)
|
||||
@ -1400,7 +1421,7 @@ def convert_file(
|
||||
)
|
||||
# Staff assignment for keys/piano (slopsmith staff schema).
|
||||
# Derived from voice position as authored in the GP tab —
|
||||
# not inferred from pitch — preserving hand crossings exactly.
|
||||
# not inferred from pitch — preserving hand crossings.
|
||||
# Voice 0 = treble/RH staff (staff=1),
|
||||
# Voice 1+ = bass/LH staff (staff=0).
|
||||
if is_keys:
|
||||
@ -1589,7 +1610,7 @@ def convert_file(
|
||||
if _lh_bid != '-1' and _lh_bid:
|
||||
_lh_bar = bars_by_id.get(_lh_bid)
|
||||
if _lh_bar is not None:
|
||||
for _lh_voice_pos, _lh_vid in enumerate(_lh_bar.findtext('Voices', '').split()):
|
||||
for _lh_vid in _lh_bar.findtext('Voices', '').split():
|
||||
if _lh_vid == '-1':
|
||||
continue
|
||||
_lh_voice = voices_dict.get(_lh_vid)
|
||||
@ -1639,8 +1660,10 @@ def convert_file(
|
||||
fret=_lh_midi % 24,
|
||||
sustain=_lh_dur if _lh_dur > 0.2 else 0.0,
|
||||
)
|
||||
# Preserve authored voice-position staff assignment.
|
||||
_lh_rn.staff = 1 if _lh_voice_pos == 0 else 0
|
||||
# LH track notes are always bass clef (staff=0).
|
||||
# The LH track as a whole IS the left hand —
|
||||
# voice position within the LH track is irrelevant.
|
||||
_lh_rn.staff = 0
|
||||
_lh_notes.append(_lh_rn)
|
||||
_lh_last_per_key[_lh_midi] = _lh_rn
|
||||
_lh_vt += _lh_dur
|
||||
|
||||
Loading…
Reference in New Issue
Block a user