Skip to content

Commit 8812ca6

Browse files
authored
Merge pull request #335 from CPJKU/develop
PR for Release 1.4.1
2 parents ef67b95 + 8ee8ba9 commit 8812ca6

File tree

11 files changed

+64
-16
lines changed

11 files changed

+64
-16
lines changed

CHANGES.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
Release Notes
22
=============
33

4+
Version 1.4.1 (Released on 2023-10-25)
5+
--------------------------------------
6+
7+
## Bug Fixes
8+
- remove unnecessary escape characters for correct parsing of sharp accidentals in Nakamura match files.
9+
- don't consider the propriety `doc_order` for sorting notes in the `matchfile_from_alignment` function if it is not present. This propriety is only present in parts from musicxml scores and previously resulted in an exception for other score formats. This solves https://github.com/CPJKU/partitura/issues/326
10+
- during matchfile parsing, voice info is now parsed as follows: If there is no voice info, all notes get assigned voice number 1. If there is only voice info for the solo voice, the non-solo voiced notes get voice 2. If multiple notes have different voices, but not every note has a voice annotated, those with voice annotation get the annotated voice number and those without voice annotation get assigned the max voice+1 voice number. Previously all notes were assigned to voice 1 if there were any None voiced note
11+
- during matchfile parsing, all note classes are now matched correctly. Previously classes `MatchSnoteTrailingScore` and `MatchSnoteNoPlayedNote` were always marked as `MatchSnoteDeletion` and `MatchHammerBounceNote`, `MatchTrailingPlayedNote`, `MatchTrillNote` always ended up as `MatchInsertionNote`. This solves https://github.com/CPJKU/partitura/issues/286
12+
- during matchfile parsing, lines which can't be parsed are removed. Before they ended up as `None` in the output.
13+
414
Version 1.4.0 (Released on 2023-09-22)
515
--------------------------------------
616

docs/source/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
# built documents.
3030
#
3131
# The short X.Y version.
32-
version = "1.4.0" # pkg_resources.get_distribution("partitura").version
32+
version = "1.4.1" # pkg_resources.get_distribution("partitura").version
3333
# The full version, including alpha/beta/rc tags.
34-
release = "1.4.0"
34+
release = "1.4.1"
3535

3636
# # The full version, including alpha/beta/rc tags
3737
# release = pkg_resources.get_distribution("partitura").version

partitura/io/exportmatch.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,10 @@ def matchfile_from_alignment(
358358
offset_in_beats=offset_beats,
359359
score_attributes_list=score_attributes_list,
360360
)
361-
snote_sort_info[snote.id] = (onset_beats, snote.doc_order)
361+
snote_sort_info[snote.id] = (
362+
onset_beats,
363+
snote.doc_order if snote.doc_order is not None else 0,
364+
)
362365

363366
# # NOTE time position is hardcoded, not pretty... Assumes there is only one tempo indication at the beginning of the score
364367
if tempo_indication is not None:

partitura/io/importmatch.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
from partitura.io.matchfile_utils import (
6868
Version,
6969
number_pattern,
70+
vnumber_pattern,
7071
MatchTimeSignature,
7172
MatchKeySignature,
7273
format_pnote_id,
@@ -209,7 +210,9 @@ def load_matchfile(
209210
parse_matchline, version=version, from_matchline_methods=from_matchline_methods
210211
)
211212
f_vec = np.vectorize(f)
212-
parsed_lines = f_vec(np_lines).tolist()
213+
parsed_lines_raw = f_vec(np_lines)
214+
# do not return unparseable lines
215+
parsed_lines = parsed_lines_raw[parsed_lines_raw != None].tolist()
213216
# Create MatchFile instance
214217
mf = MatchFile(lines=parsed_lines)
215218
# Validate match for duplicate snote_ids or pnote_ids
@@ -632,6 +635,15 @@ def part_from_matchfile(
632635

633636
if "s" in note.ScoreAttributesList:
634637
note_attributes["voice"] = 1
638+
elif any(a.startswith("v") for a in note.ScoreAttributesList):
639+
note_attributes["voice"] = next(
640+
(
641+
int(a[1:])
642+
for a in note.ScoreAttributesList
643+
if vnumber_pattern.match(a)
644+
),
645+
None,
646+
)
635647
else:
636648
note_attributes["voice"] = next(
637649
(int(a) for a in note.ScoreAttributesList if number_pattern.match(a)),
@@ -692,9 +704,7 @@ def part_from_matchfile(
692704

693705
else:
694706
part_note = score.Note(**note_attributes)
695-
696707
part.add(part_note, onset_divs, offset_divs)
697-
698708
# Check if the note is tied and if so, add the tie information
699709
if is_tied:
700710
found = False
@@ -717,7 +727,6 @@ def part_from_matchfile(
717727
part_note.id
718728
)
719729
)
720-
721730
# add time signatures
722731
for ts_beat_time, ts_bar, tsg in ts:
723732
ts_beats = tsg.numerator
@@ -729,7 +738,6 @@ def part_from_matchfile(
729738
else:
730739
bar_start_divs = 0
731740
part.add(score.TimeSignature(ts_beats, ts_beat_type), bar_start_divs)
732-
733741
# add key signatures
734742
for ks_beat_time, ks_bar, keys in mf.key_signatures:
735743
if ks_bar in bar_times.keys():
@@ -755,10 +763,16 @@ def part_from_matchfile(
755763
score.tie_notes(part)
756764
score.find_tuplets(part)
757765

758-
if not all([n.voice for n in part.notes_tied]):
766+
n_voices = set([n.voice for n in part.notes])
767+
if len(n_voices) == 1 and None in n_voices:
759768
for note in part.notes_tied:
760769
if note.voice is None:
761770
note.voice = 1
771+
elif len(n_voices) > 1 and None in n_voices:
772+
n_voices.remove(None)
773+
for note in part.notes_tied:
774+
if note.voice is None:
775+
note.voice = max(n_voices) + 1
762776

763777
return part
764778

partitura/io/importnakamura.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,7 @@ def load_nakamuramatch(filename: PathLike) -> Tuple[Union[np.ndarray, list]]:
148148
# load missing notes
149149
missing = np.fromregex(filename, pattern, dtype=dtype_missing)
150150

151-
midi_pitch = np.array(
152-
[note_name_to_midi_pitch(n.replace("#", r"\#")) for n in result["alignSitch"]]
153-
)
151+
midi_pitch = np.array([note_name_to_midi_pitch(n) for n in result["alignSitch"]])
154152

155153
align_valid = result["alignID"] != "*"
156154
n_align = sum(align_valid)

partitura/io/matchfile_base.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@ def prepare_kwargs_from_matchline(
770770

771771
class BaseDeletionLine(MatchLine):
772772
out_pattern = "{SnoteLine}-deletion."
773+
identifier_pattern = re.compile(r"-deletion\.")
773774

774775
def __init__(self, version: Version, snote: BaseSnoteLine) -> None:
775776
super().__init__(version)
@@ -799,7 +800,12 @@ def prepare_kwargs_from_matchline(
799800
matchline: str,
800801
snote_class: BaseSnoteLine,
801802
version: Version,
803+
pos: int = 0,
802804
) -> Dict:
805+
match_pattern = cls.identifier_pattern.search(matchline, pos=pos)
806+
807+
if match_pattern is None:
808+
raise MatchError("Input match line does not fit the expected pattern.")
803809
snote = snote_class.from_matchline(matchline, version=version)
804810

805811
kwargs = dict(
@@ -812,6 +818,7 @@ def prepare_kwargs_from_matchline(
812818

813819
class BaseInsertionLine(MatchLine):
814820
out_pattern = "insertion-{NoteLine}"
821+
identifier_pattern = re.compile(r"insertion-")
815822

816823
def __init__(self, version: Version, note: BaseNoteLine) -> None:
817824
super().__init__(version)
@@ -841,7 +848,13 @@ def prepare_kwargs_from_matchline(
841848
matchline: str,
842849
note_class: BaseNoteLine,
843850
version: Version,
851+
pos: int = 0,
844852
) -> Dict:
853+
match_pattern = cls.identifier_pattern.search(matchline, pos=pos)
854+
855+
if match_pattern is None:
856+
raise MatchError("Input match line does not fit the expected pattern.")
857+
845858
note = note_class.from_matchline(matchline, version=version)
846859

847860
kwargs = dict(
@@ -896,7 +909,7 @@ def prepare_kwargs_from_matchline(
896909
anchor_pattern = cls.ornament_pattern.search(matchline)
897910

898911
if anchor_pattern is None:
899-
raise MatchError("")
912+
raise MatchError("Input match line does not fit the expected pattern.")
900913

901914
anchor = interpret_as_string(anchor_pattern.group("Anchor"))
902915
note = note_class.from_matchline(matchline, version=version)

partitura/io/matchfile_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
pitch_class_pattern = re.compile("(?P<step>[A-Ga-g])(?P<alter>[#bn]*)")
4747

4848
number_pattern = re.compile(r"\d+")
49+
vnumber_pattern = re.compile(r"v\d+")
4950

5051
# For matchfiles before 1.0.0.
5152
old_version_pattern = re.compile(r"^(?P<minor>[0-9]+)\.(?P<patch>[0-9]+)")

partitura/io/matchlines_v0.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,7 @@ def from_matchline(
805805

806806
class MatchSnoteTrailingScore(MatchSnoteDeletion):
807807
out_pattern = "{SnoteLine}-trailing_score_note."
808+
identifier_pattern = re.compile(r"-trailing_score_note\.")
808809

809810
def __init__(self, version: Version, snote: MatchSnote) -> None:
810811
super().__init__(version=version, snote=snote)
@@ -815,6 +816,7 @@ def __init__(self, version: Version, snote: MatchSnote) -> None:
815816

816817
class MatchSnoteNoPlayedNote(MatchSnoteDeletion):
817818
out_pattern = "{SnoteLine}-no_played_note."
819+
identifier_pattern = re.compile(r"-no_played_note\.")
818820

819821
def __init__(self, version: Version, snote: MatchSnote) -> None:
820822
super().__init__(version=version, snote=snote)
@@ -848,6 +850,7 @@ def from_matchline(
848850

849851
class MatchHammerBounceNote(MatchInsertionNote):
850852
out_pattern = "hammer_bounce-{NoteLine}"
853+
identifier_pattern = re.compile(r"hammer_bounce-")
851854

852855
def __init__(self, version: Version, note: MatchNote) -> None:
853856
super().__init__(version=version, note=note)
@@ -856,6 +859,7 @@ def __init__(self, version: Version, note: MatchNote) -> None:
856859

857860
class MatchTrailingPlayedNote(MatchInsertionNote):
858861
out_pattern = "trailing_played_note-{NoteLine}"
862+
identifier_pattern = re.compile(r"trailing_played_note-")
859863

860864
def __init__(self, version: Version, note: MatchNote) -> None:
861865
super().__init__(version=version, note=note)
@@ -890,7 +894,7 @@ def from_matchline(
890894
anchor_pattern = cls.ornament_pattern.search(matchline)
891895

892896
if anchor_pattern is None:
893-
raise MatchError("")
897+
raise MatchError("Input match line does not fit the expected pattern.")
894898
note = MatchNote.from_matchline(matchline, version=version)
895899

896900
return cls(

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
EMAIL = "partitura-users@googlegroups.com"
1717
AUTHOR = "Maarten Grachten, Carlos Cancino-Chacón, Silvan Peter, Emmanouil Karystinaios, Francesco Foscarin, Thassilo Gadermaier, Patricia Hu"
1818
REQUIRES_PYTHON = ">=3.7"
19-
VERSION = "1.4.0"
19+
VERSION = "1.4.1"
2020

2121
# What packages are required for this module to be executed?
2222
REQUIRED = ["numpy", "scipy", "lxml", "lark-parser", "xmlschema", "mido"]

tests/data/match/mozart_k265_var1.match

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ snote(n10,[C,n],4,1:2,0,1/4,1.0000,2.0000,[v5,staff2])-note(n5,60,1122,1160,67,1
1818
snote(n6,[C,n],5,1:2,1/16,1/16,1.2500,1.5000,[v1,staff1])-note(n7,72,1233,1284,44,1,1).
1919
snote(n7,[B,n],4,1:2,1/8,1/16,1.5000,1.7500,[v1,staff1])-note(n8,71,1316,1410,65,1,1).
2020
snote(n8,[C,n],5,1:2,3/16,1/16,1.7500,2.0000,[v1,staff1])-note(n9,72,1420,1490,61,1,1).
21+
badly_formatted_line-note(n11,81,1556,1637,55,1,1).
2122
snote(n11,[A,n],5,2:1,0,1/16,2.0000,2.2500,[v1,staff1])-note(n11,81,1556,1637,55,1,1).
2223
snote(n19,[E,n],4,2:1,0,1/4,2.0000,3.0000,[v5,staff2])-note(n10,64,1541,1614,75,1,1).
2324
snote(n12,[G,n],5,2:1,1/16,1/16,2.2500,2.5000,[v1,staff1])-note(n12,79,1683,1752,62,1,1).

0 commit comments

Comments
 (0)