diff --git a/src/guitarpro/gp3.py b/src/guitarpro/gp3.py index 23e49f7..6e54a10 100644 --- a/src/guitarpro/gp3.py +++ b/src/guitarpro/gp3.py @@ -899,7 +899,9 @@ def readNote(self, note, guitarString, track): """ flags = self.readU8() note.string = guitarString.number + note.effect.heavyAccentuatedNote = bool(flags & 0x02) note.effect.ghostNote = bool(flags & 0x04) + note.effect.accentuatedNote = bool(flags & 0x40) if flags & 0x20: note.type = gp.NoteType(self.readU8()) if flags & 0x01: @@ -1443,6 +1445,8 @@ def packNoteFlags(self, note): if note.velocity != gp.Velocities.default: flags |= 0x10 flags |= 0x20 + if note.effect.accentuatedNote: + flags |= 0x40 return flags def writeNoteEffects(self, note): diff --git a/src/guitarpro/gp4.py b/src/guitarpro/gp4.py index 78bc305..31a6814 100644 --- a/src/guitarpro/gp4.py +++ b/src/guitarpro/gp4.py @@ -655,8 +655,6 @@ def writeNote(self, note): def packNoteFlags(self, note): flags = super().packNoteFlags(note) - if note.effect.accentuatedNote: - flags |= 0x40 if note.effect.isFingering: flags |= 0x80 return flags diff --git a/tests/test_conversion.py b/tests/test_conversion.py index 19b4649..e6115a7 100644 --- a/tests/test_conversion.py +++ b/tests/test_conversion.py @@ -126,6 +126,37 @@ def testChord(tmpdir, caplog, filename): assert song == song2 +@pytest.mark.parametrize('filename', ['Effects.gp3', 'Effects.gp4', 'Effects.gp5']) +def testNoteAccentuationRoundtrip(tmpdir, filename): + """Regression test for GP3/GP4 note accent flag extraction. + + `GP3File.readNote` historically did not extract flag bits 0x02 (heavy + accent) and 0x40 (normal accent), while `writeNote` *does* write them. + GP4 inherits the broken read path; only GP5 read them correctly. + + This caused a reader/writer asymmetry: accent flags were silently + dropped on every parse, even though PGP could write them. + """ + filepath = LOCATION / filename + song = gp.parse(filepath) + note = song.tracks[0].measures[0].voices[0].beats[0].notes[0] + + note.effect.accentuatedNote = True + note.effect.heavyAccentuatedNote = True + + destpath = str(tmpdir.join(filename)) + gp.write(song, destpath) + song2 = gp.parse(destpath) + note2 = song2.tracks[0].measures[0].voices[0].beats[0].notes[0] + + assert note2.effect.accentuatedNote is True, ( + f'{filename}: accentuatedNote not preserved on round-trip' + ) + assert note2.effect.heavyAccentuatedNote is True, ( + f'{filename}: heavyAccentuatedNote not preserved on round-trip' + ) + + @pytest.mark.parametrize('version', ['gp3', 'gp4', 'gp5']) def testReadErrorAnnotation(version): def writeToBytesIO(song):