partitura 1.3.0__py3-none-any.whl → 1.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- partitura/directions.py +3 -0
- partitura/display.py +0 -1
- partitura/io/__init__.py +41 -35
- partitura/io/exportmatch.py +52 -10
- partitura/io/exportmidi.py +37 -19
- partitura/io/exportmusicxml.py +6 -92
- partitura/io/exportparangonada.py +18 -19
- partitura/io/importkern.py +2 -4
- partitura/io/importmatch.py +121 -39
- partitura/io/importmei.py +161 -34
- partitura/io/importmidi.py +23 -14
- partitura/io/importmusic21.py +0 -1
- partitura/io/importmusicxml.py +48 -63
- partitura/io/importparangonada.py +0 -1
- partitura/io/matchfile_base.py +0 -21
- partitura/io/matchfile_utils.py +29 -17
- partitura/io/matchlines_v0.py +0 -22
- partitura/io/matchlines_v1.py +8 -42
- partitura/io/musescore.py +68 -41
- partitura/musicanalysis/__init__.py +1 -1
- partitura/musicanalysis/note_array_to_score.py +147 -92
- partitura/musicanalysis/note_features.py +66 -51
- partitura/musicanalysis/performance_codec.py +140 -96
- partitura/musicanalysis/performance_features.py +190 -129
- partitura/musicanalysis/pitch_spelling.py +0 -2
- partitura/musicanalysis/tonal_tension.py +0 -6
- partitura/musicanalysis/voice_separation.py +1 -22
- partitura/performance.py +178 -5
- partitura/score.py +154 -74
- partitura/utils/__init__.py +1 -1
- partitura/utils/generic.py +3 -7
- partitura/utils/misc.py +0 -1
- partitura/utils/music.py +108 -66
- partitura/utils/normalize.py +75 -35
- partitura/utils/synth.py +1 -7
- {partitura-1.3.0.dist-info → partitura-1.4.0.dist-info}/METADATA +2 -2
- partitura-1.4.0.dist-info/RECORD +51 -0
- {partitura-1.3.0.dist-info → partitura-1.4.0.dist-info}/WHEEL +1 -1
- partitura-1.3.0.dist-info/RECORD +0 -51
- {partitura-1.3.0.dist-info → partitura-1.4.0.dist-info}/LICENSE +0 -0
- {partitura-1.3.0.dist-info → partitura-1.4.0.dist-info}/top_level.txt +0 -0
partitura/io/matchlines_v1.py
CHANGED
|
@@ -58,6 +58,9 @@ from partitura.io.matchfile_utils import (
|
|
|
58
58
|
format_key_signature_v1_0_0,
|
|
59
59
|
to_snake_case,
|
|
60
60
|
get_kwargs_from_matchline,
|
|
61
|
+
MatchTempoIndication,
|
|
62
|
+
interpret_as_tempo_indication,
|
|
63
|
+
format_tempo_indication,
|
|
61
64
|
)
|
|
62
65
|
|
|
63
66
|
# Define current version of the match file format
|
|
@@ -127,7 +130,6 @@ class MatchInfo(BaseInfoLine):
|
|
|
127
130
|
value_type: type,
|
|
128
131
|
format_fun: Callable[Any, str],
|
|
129
132
|
) -> None:
|
|
130
|
-
|
|
131
133
|
if version < Version(1, 0, 0):
|
|
132
134
|
raise ValueError("The version must be >= 1.0.0")
|
|
133
135
|
|
|
@@ -195,7 +197,6 @@ class MatchInfo(BaseInfoLine):
|
|
|
195
197
|
def from_instance(
|
|
196
198
|
cls, instance: BaseInfoLine, version: Version = LATEST_VERSION
|
|
197
199
|
) -> MatchInfo:
|
|
198
|
-
|
|
199
200
|
if version < Version(1, 0, 0):
|
|
200
201
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
201
202
|
|
|
@@ -239,6 +240,11 @@ SCOREPROP_LINE = {
|
|
|
239
240
|
format_key_signature_v1_0_0,
|
|
240
241
|
MatchKeySignature,
|
|
241
242
|
),
|
|
243
|
+
"tempoIndication": (
|
|
244
|
+
interpret_as_tempo_indication,
|
|
245
|
+
format_tempo_indication,
|
|
246
|
+
MatchTempoIndication,
|
|
247
|
+
),
|
|
242
248
|
"beatSubDivision": (interpret_as_list_int, format_list, list),
|
|
243
249
|
"directions": (interpret_as_list, format_list, list),
|
|
244
250
|
}
|
|
@@ -250,7 +256,6 @@ SCOREPROP_ATTRIBUTE_EQUIVALENCES = dict(
|
|
|
250
256
|
|
|
251
257
|
|
|
252
258
|
class MatchScoreProp(MatchLine):
|
|
253
|
-
|
|
254
259
|
field_names = (
|
|
255
260
|
"Attribute",
|
|
256
261
|
"Value",
|
|
@@ -285,7 +290,6 @@ class MatchScoreProp(MatchLine):
|
|
|
285
290
|
offset: FractionalSymbolicDuration,
|
|
286
291
|
time_in_beats: float,
|
|
287
292
|
) -> None:
|
|
288
|
-
|
|
289
293
|
if version < Version(1, 0, 0):
|
|
290
294
|
raise ValueError("The version must be >= 1.0.0")
|
|
291
295
|
|
|
@@ -351,7 +355,6 @@ class MatchScoreProp(MatchLine):
|
|
|
351
355
|
class_dict = SCOREPROP_LINE[version]
|
|
352
356
|
|
|
353
357
|
if match_pattern is not None:
|
|
354
|
-
|
|
355
358
|
(
|
|
356
359
|
attribute,
|
|
357
360
|
value_str,
|
|
@@ -401,7 +404,6 @@ class MatchScoreProp(MatchLine):
|
|
|
401
404
|
offset: Optional[FractionalSymbolicDuration] = None,
|
|
402
405
|
time_in_beats: Optional[float] = None,
|
|
403
406
|
) -> MatchScoreProp:
|
|
404
|
-
|
|
405
407
|
if version < Version(1, 0, 0):
|
|
406
408
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
407
409
|
|
|
@@ -511,7 +513,6 @@ class MatchSection(MatchLine):
|
|
|
511
513
|
end_in_beats_original: float,
|
|
512
514
|
repeat_end_type: List[str],
|
|
513
515
|
) -> None:
|
|
514
|
-
|
|
515
516
|
if version not in SECTION_LINE:
|
|
516
517
|
raise ValueError(
|
|
517
518
|
f"Unknown version {version}!. "
|
|
@@ -549,7 +550,6 @@ class MatchSection(MatchLine):
|
|
|
549
550
|
class_dict = SECTION_LINE[version]
|
|
550
551
|
|
|
551
552
|
if match_pattern is not None:
|
|
552
|
-
|
|
553
553
|
kwargs = dict(
|
|
554
554
|
[
|
|
555
555
|
(to_snake_case(fn), class_dict[fn][0](match_pattern.group(fn)))
|
|
@@ -588,7 +588,6 @@ class MatchStime(BaseStimeLine):
|
|
|
588
588
|
onset_in_beats: float,
|
|
589
589
|
annotation_type: List[str],
|
|
590
590
|
) -> None:
|
|
591
|
-
|
|
592
591
|
if version < Version(1, 0, 0):
|
|
593
592
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
594
593
|
|
|
@@ -613,7 +612,6 @@ class MatchStime(BaseStimeLine):
|
|
|
613
612
|
pos: int = 0,
|
|
614
613
|
version: Version = LATEST_VERSION,
|
|
615
614
|
) -> MatchStime:
|
|
616
|
-
|
|
617
615
|
if version not in STIME_LINE:
|
|
618
616
|
raise ValueError(
|
|
619
617
|
f"Unknown version {version}!. "
|
|
@@ -647,7 +645,6 @@ class MatchPtime(BasePtimeLine):
|
|
|
647
645
|
version: Version,
|
|
648
646
|
onsets: List[int],
|
|
649
647
|
) -> None:
|
|
650
|
-
|
|
651
648
|
if version < Version(1, 0, 0):
|
|
652
649
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
653
650
|
|
|
@@ -668,7 +665,6 @@ class MatchPtime(BasePtimeLine):
|
|
|
668
665
|
pos: int = 0,
|
|
669
666
|
version: Version = LATEST_VERSION,
|
|
670
667
|
) -> MatchStime:
|
|
671
|
-
|
|
672
668
|
if version not in PTIME_LINE:
|
|
673
669
|
raise ValueError(
|
|
674
670
|
f"Unknown version {version}!. "
|
|
@@ -690,7 +686,6 @@ class MatchPtime(BasePtimeLine):
|
|
|
690
686
|
|
|
691
687
|
|
|
692
688
|
class MatchSnote(BaseSnoteLine):
|
|
693
|
-
|
|
694
689
|
format_fun = dict(
|
|
695
690
|
Anchor=format_string,
|
|
696
691
|
NoteName=lambda x: str(x.upper()),
|
|
@@ -720,7 +715,6 @@ class MatchSnote(BaseSnoteLine):
|
|
|
720
715
|
offset_in_beats: float,
|
|
721
716
|
score_attributes_list: List[str],
|
|
722
717
|
) -> None:
|
|
723
|
-
|
|
724
718
|
if version < Version(1, 0, 0):
|
|
725
719
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
726
720
|
super().__init__(
|
|
@@ -816,7 +810,6 @@ NOTE_LINE = {
|
|
|
816
810
|
|
|
817
811
|
|
|
818
812
|
class MatchNote(BaseNoteLine):
|
|
819
|
-
|
|
820
813
|
field_names = (
|
|
821
814
|
"Id",
|
|
822
815
|
"MidiPitch",
|
|
@@ -852,7 +845,6 @@ class MatchNote(BaseNoteLine):
|
|
|
852
845
|
channel: int,
|
|
853
846
|
track: int,
|
|
854
847
|
) -> None:
|
|
855
|
-
|
|
856
848
|
if version not in NOTE_LINE:
|
|
857
849
|
raise ValueError(
|
|
858
850
|
f"Unknown version {version}!. "
|
|
@@ -883,7 +875,6 @@ class MatchNote(BaseNoteLine):
|
|
|
883
875
|
pos: int = 0,
|
|
884
876
|
version: Version = LATEST_VERSION,
|
|
885
877
|
) -> MatchNote:
|
|
886
|
-
|
|
887
878
|
if version < Version(1, 0, 0):
|
|
888
879
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
889
880
|
|
|
@@ -907,7 +898,6 @@ class MatchNote(BaseNoteLine):
|
|
|
907
898
|
instance: BaseNoteLine,
|
|
908
899
|
version: Version = LATEST_VERSION,
|
|
909
900
|
) -> MatchNote:
|
|
910
|
-
|
|
911
901
|
if version < Version(1, 0, 0):
|
|
912
902
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
913
903
|
|
|
@@ -915,7 +905,6 @@ class MatchNote(BaseNoteLine):
|
|
|
915
905
|
raise ValueError("`instance` needs to be a subclass of `BaseNoteLine`")
|
|
916
906
|
|
|
917
907
|
if instance.version < Version(1, 0, 0):
|
|
918
|
-
|
|
919
908
|
return cls(
|
|
920
909
|
version=version,
|
|
921
910
|
id=instance.Id,
|
|
@@ -947,7 +936,6 @@ class MatchStimePtime(BaseStimePtimeLine):
|
|
|
947
936
|
matchline: str,
|
|
948
937
|
version: Version = LATEST_VERSION,
|
|
949
938
|
) -> MatchSnoteNote:
|
|
950
|
-
|
|
951
939
|
if version < Version(1, 0, 0):
|
|
952
940
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
953
941
|
|
|
@@ -968,7 +956,6 @@ class MatchSnoteNote(BaseSnoteNoteLine):
|
|
|
968
956
|
snote: BaseSnoteLine,
|
|
969
957
|
note: BaseNoteLine,
|
|
970
958
|
) -> None:
|
|
971
|
-
|
|
972
959
|
super().__init__(
|
|
973
960
|
version=version,
|
|
974
961
|
snote=snote,
|
|
@@ -981,7 +968,6 @@ class MatchSnoteNote(BaseSnoteNoteLine):
|
|
|
981
968
|
matchline: str,
|
|
982
969
|
version: Version = LATEST_VERSION,
|
|
983
970
|
) -> MatchSnoteNote:
|
|
984
|
-
|
|
985
971
|
if version < Version(1, 0, 0):
|
|
986
972
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
987
973
|
|
|
@@ -998,7 +984,6 @@ class MatchSnoteNote(BaseSnoteNoteLine):
|
|
|
998
984
|
def from_instance(
|
|
999
985
|
cls, instance: BaseSnoteNoteLine, version: Version
|
|
1000
986
|
) -> MatchSnoteNote:
|
|
1001
|
-
|
|
1002
987
|
if version < Version(1, 0, 0):
|
|
1003
988
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1004
989
|
|
|
@@ -1014,7 +999,6 @@ class MatchSnoteNote(BaseSnoteNoteLine):
|
|
|
1014
999
|
|
|
1015
1000
|
class MatchSnoteDeletion(BaseDeletionLine):
|
|
1016
1001
|
def __init__(self, version: Version, snote: MatchSnote) -> None:
|
|
1017
|
-
|
|
1018
1002
|
super().__init__(
|
|
1019
1003
|
version=version,
|
|
1020
1004
|
snote=snote,
|
|
@@ -1026,7 +1010,6 @@ class MatchSnoteDeletion(BaseDeletionLine):
|
|
|
1026
1010
|
matchline: str,
|
|
1027
1011
|
version: Version = LATEST_VERSION,
|
|
1028
1012
|
) -> MatchSnoteDeletion:
|
|
1029
|
-
|
|
1030
1013
|
if version < Version(1, 0, 0):
|
|
1031
1014
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1032
1015
|
|
|
@@ -1042,7 +1025,6 @@ class MatchSnoteDeletion(BaseDeletionLine):
|
|
|
1042
1025
|
def from_instance(
|
|
1043
1026
|
cls, instance: BaseDeletionLine, version: Version
|
|
1044
1027
|
) -> MatchSnoteNote:
|
|
1045
|
-
|
|
1046
1028
|
if version < Version(1, 0, 0):
|
|
1047
1029
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1048
1030
|
|
|
@@ -1057,7 +1039,6 @@ class MatchSnoteDeletion(BaseDeletionLine):
|
|
|
1057
1039
|
|
|
1058
1040
|
class MatchInsertionNote(BaseInsertionLine):
|
|
1059
1041
|
def __init__(self, version: Version, note: MatchNote) -> None:
|
|
1060
|
-
|
|
1061
1042
|
super().__init__(
|
|
1062
1043
|
version=version,
|
|
1063
1044
|
note=note,
|
|
@@ -1069,7 +1050,6 @@ class MatchInsertionNote(BaseInsertionLine):
|
|
|
1069
1050
|
matchline: str,
|
|
1070
1051
|
version: Version = LATEST_VERSION,
|
|
1071
1052
|
) -> MatchInsertionNote:
|
|
1072
|
-
|
|
1073
1053
|
if version < Version(1, 0, 0):
|
|
1074
1054
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1075
1055
|
|
|
@@ -1085,7 +1065,6 @@ class MatchInsertionNote(BaseInsertionLine):
|
|
|
1085
1065
|
def from_instance(
|
|
1086
1066
|
cls, instance: BaseInsertionLine, version: Version
|
|
1087
1067
|
) -> MatchInsertionNote:
|
|
1088
|
-
|
|
1089
1068
|
if version < Version(1, 0, 0):
|
|
1090
1069
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1091
1070
|
|
|
@@ -1099,7 +1078,6 @@ class MatchInsertionNote(BaseInsertionLine):
|
|
|
1099
1078
|
|
|
1100
1079
|
|
|
1101
1080
|
class MatchOrnamentNote(BaseOrnamentLine):
|
|
1102
|
-
|
|
1103
1081
|
field_names = (
|
|
1104
1082
|
"Anchor",
|
|
1105
1083
|
"OrnamentType",
|
|
@@ -1142,7 +1120,6 @@ class MatchOrnamentNote(BaseOrnamentLine):
|
|
|
1142
1120
|
matchline: str,
|
|
1143
1121
|
version: Version = LATEST_VERSION,
|
|
1144
1122
|
) -> MatchOrnamentNote:
|
|
1145
|
-
|
|
1146
1123
|
if version < Version(1, 0, 0):
|
|
1147
1124
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1148
1125
|
|
|
@@ -1163,7 +1140,6 @@ class MatchOrnamentNote(BaseOrnamentLine):
|
|
|
1163
1140
|
def from_instance(
|
|
1164
1141
|
cls, instance: BaseOrnamentLine, version: Version
|
|
1165
1142
|
) -> MatchOrnamentNote:
|
|
1166
|
-
|
|
1167
1143
|
if version < Version(1, 0, 0):
|
|
1168
1144
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1169
1145
|
|
|
@@ -1187,7 +1163,6 @@ class MatchSustainPedal(BaseSustainPedalLine):
|
|
|
1187
1163
|
time: int,
|
|
1188
1164
|
value: int,
|
|
1189
1165
|
) -> None:
|
|
1190
|
-
|
|
1191
1166
|
super().__init__(
|
|
1192
1167
|
version=version,
|
|
1193
1168
|
time=time,
|
|
@@ -1201,7 +1176,6 @@ class MatchSustainPedal(BaseSustainPedalLine):
|
|
|
1201
1176
|
version: Version = LATEST_VERSION,
|
|
1202
1177
|
pos: int = 0,
|
|
1203
1178
|
) -> MatchSustainPedal:
|
|
1204
|
-
|
|
1205
1179
|
if version < Version(1, 0, 0):
|
|
1206
1180
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1207
1181
|
|
|
@@ -1220,7 +1194,6 @@ class MatchSustainPedal(BaseSustainPedalLine):
|
|
|
1220
1194
|
def from_instance(
|
|
1221
1195
|
cls, instance: BaseSustainPedalLine, version: Version
|
|
1222
1196
|
) -> MatchOrnamentNote:
|
|
1223
|
-
|
|
1224
1197
|
if version < Version(1, 0, 0):
|
|
1225
1198
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1226
1199
|
|
|
@@ -1243,7 +1216,6 @@ class MatchSoftPedal(BaseSoftPedalLine):
|
|
|
1243
1216
|
time: int,
|
|
1244
1217
|
value: int,
|
|
1245
1218
|
) -> None:
|
|
1246
|
-
|
|
1247
1219
|
super().__init__(
|
|
1248
1220
|
version=version,
|
|
1249
1221
|
time=time,
|
|
@@ -1257,7 +1229,6 @@ class MatchSoftPedal(BaseSoftPedalLine):
|
|
|
1257
1229
|
version: Version = LATEST_VERSION,
|
|
1258
1230
|
pos: int = 0,
|
|
1259
1231
|
) -> MatchSoftPedal:
|
|
1260
|
-
|
|
1261
1232
|
if version < Version(1, 0, 0):
|
|
1262
1233
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1263
1234
|
|
|
@@ -1278,7 +1249,6 @@ class MatchSoftPedal(BaseSoftPedalLine):
|
|
|
1278
1249
|
instance: BaseSoftPedalLine,
|
|
1279
1250
|
version: Version,
|
|
1280
1251
|
) -> MatchOrnamentNote:
|
|
1281
|
-
|
|
1282
1252
|
if version < Version(1, 0, 0):
|
|
1283
1253
|
raise ValueError(f"{version} < Version(1, 0, 0)")
|
|
1284
1254
|
|
|
@@ -1344,7 +1314,6 @@ def make_scoreprop(
|
|
|
1344
1314
|
offset: FractionalSymbolicDuration,
|
|
1345
1315
|
time_in_beats: float,
|
|
1346
1316
|
) -> MatchScoreProp:
|
|
1347
|
-
|
|
1348
1317
|
class_dict = SCOREPROP_LINE[version]
|
|
1349
1318
|
|
|
1350
1319
|
_, format_fun, dtype = class_dict[attribute]
|
|
@@ -1372,7 +1341,6 @@ def make_section(
|
|
|
1372
1341
|
end_in_beats_original: float,
|
|
1373
1342
|
repeat_end_type: Union[str, List[str]],
|
|
1374
1343
|
) -> MatchSection:
|
|
1375
|
-
|
|
1376
1344
|
ml = MatchSection(
|
|
1377
1345
|
version=version,
|
|
1378
1346
|
start_in_beats_unfolded=start_in_beats_unfolded,
|
|
@@ -1406,7 +1374,6 @@ def to_v1(matchline: MatchLine, version: Version = LATEST_VERSION) -> MatchLine:
|
|
|
1406
1374
|
from partitura.io.matchlines_v0 import MatchMeta
|
|
1407
1375
|
|
|
1408
1376
|
if isinstance(matchline, BaseInfoLine):
|
|
1409
|
-
|
|
1410
1377
|
if (
|
|
1411
1378
|
matchline.Attribute in INFO_LINE[version]
|
|
1412
1379
|
or matchline.Attribute in INFO_ATTRIBUTE_EQUIVALENCES
|
|
@@ -1417,7 +1384,6 @@ def to_v1(matchline: MatchLine, version: Version = LATEST_VERSION) -> MatchLine:
|
|
|
1417
1384
|
matchline.Attribute in SCOREPROP_LINE[version]
|
|
1418
1385
|
or matchline.Attribute in SCOREPROP_ATTRIBUTE_EQUIVALENCES
|
|
1419
1386
|
):
|
|
1420
|
-
|
|
1421
1387
|
return MatchScoreProp.from_instance(instance=matchline, version=version)
|
|
1422
1388
|
|
|
1423
1389
|
if isinstance(matchline, MatchMeta):
|
partitura/io/musescore.py
CHANGED
|
@@ -36,39 +36,70 @@ class FileImportException(Exception):
|
|
|
36
36
|
pass
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# break
|
|
46
|
-
|
|
47
|
-
result = shutil.which("musescore")
|
|
48
|
-
|
|
49
|
-
if result is None:
|
|
50
|
-
result = shutil.which("musescore3")
|
|
51
|
-
|
|
52
|
-
if result is None:
|
|
53
|
-
result = shutil.which("mscore")
|
|
54
|
-
|
|
39
|
+
def find_musescore_version(version=4):
|
|
40
|
+
"""Find the path to the MuseScore executable for a specific version.
|
|
41
|
+
If version is a empty string it tries to find an unspecified version of
|
|
42
|
+
MuseScore which is used in some systems.
|
|
43
|
+
"""
|
|
44
|
+
result = shutil.which(f"musescore{version}")
|
|
55
45
|
if result is None:
|
|
56
|
-
result = shutil.which("
|
|
57
|
-
|
|
46
|
+
result = shutil.which(f"mscore{version}")
|
|
58
47
|
if result is None:
|
|
59
48
|
if platform.system() == "Linux":
|
|
60
49
|
pass
|
|
61
|
-
|
|
62
50
|
elif platform.system() == "Darwin":
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
result = shutil.which(
|
|
52
|
+
f"/Applications/MuseScore {version}.app/Contents/MacOS/mscore"
|
|
53
|
+
)
|
|
66
54
|
elif platform.system() == "Windows":
|
|
67
|
-
result = shutil.which(
|
|
55
|
+
result = shutil.which(
|
|
56
|
+
rf"C:\Program Files\MuseScore {version}\bin\MuseScore{version}.exe"
|
|
57
|
+
)
|
|
68
58
|
|
|
69
59
|
return result
|
|
70
60
|
|
|
71
61
|
|
|
62
|
+
def find_musescore():
|
|
63
|
+
"""Find the path to the MuseScore executable.
|
|
64
|
+
|
|
65
|
+
This function first tries to find the executable for MuseScore 4,
|
|
66
|
+
then for MuseScore 3, and finally for any version of MuseScore.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
str
|
|
71
|
+
Path to the MuseScore executable
|
|
72
|
+
|
|
73
|
+
Raises
|
|
74
|
+
------
|
|
75
|
+
MuseScoreNotFoundException
|
|
76
|
+
When no MuseScore executable was found
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
mscore_exec = find_musescore_version(version=4)
|
|
80
|
+
if not mscore_exec:
|
|
81
|
+
mscore_exec = find_musescore_version(version=3)
|
|
82
|
+
if mscore_exec:
|
|
83
|
+
warnings.warn(
|
|
84
|
+
"Only Musescore 3 is installed. Consider upgrading to musescore 4."
|
|
85
|
+
)
|
|
86
|
+
else:
|
|
87
|
+
mscore_exec = find_musescore_version(version="")
|
|
88
|
+
if mscore_exec:
|
|
89
|
+
warnings.warn(
|
|
90
|
+
"A unspecified version of MuseScore was found. Consider upgrading to musescore 4."
|
|
91
|
+
)
|
|
92
|
+
else:
|
|
93
|
+
raise MuseScoreNotFoundException()
|
|
94
|
+
# check if a screen is available (only on Linux)
|
|
95
|
+
if "DISPLAY" not in os.environ and platform.system() == "Linux":
|
|
96
|
+
raise MuseScoreNotFoundException(
|
|
97
|
+
"Musescore Executable was found, but a screen is missing. Musescore needs a screen to load scores"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return mscore_exec
|
|
101
|
+
|
|
102
|
+
|
|
72
103
|
@deprecated_alias(fn="filename")
|
|
73
104
|
@deprecated_parameter("ensure_list")
|
|
74
105
|
def load_via_musescore(
|
|
@@ -104,30 +135,33 @@ or a list of these
|
|
|
104
135
|
One or more part or partgroup objects
|
|
105
136
|
|
|
106
137
|
"""
|
|
138
|
+
if filename.endswith(".mscz"):
|
|
139
|
+
pass
|
|
140
|
+
else:
|
|
141
|
+
# open the file as text and check if the first symbol is "<" to avoid
|
|
142
|
+
# further processing in case of non-XML files
|
|
143
|
+
with open(filename, "r") as f:
|
|
144
|
+
if f.read(1) != "<":
|
|
145
|
+
raise FileImportException(
|
|
146
|
+
"File {} is not a valid XML file.".format(filename)
|
|
147
|
+
)
|
|
107
148
|
|
|
108
|
-
mscore_exec =
|
|
109
|
-
|
|
110
|
-
if not mscore_exec:
|
|
111
|
-
|
|
112
|
-
raise MuseScoreNotFoundException()
|
|
149
|
+
mscore_exec = find_musescore()
|
|
113
150
|
|
|
114
151
|
xml_fh = os.path.splitext(os.path.basename(filename))[0] + ".musicxml"
|
|
115
152
|
|
|
116
|
-
cmd = [mscore_exec, "-o", xml_fh, filename]
|
|
153
|
+
cmd = [mscore_exec, "-o", xml_fh, filename, "-f"]
|
|
117
154
|
|
|
118
155
|
try:
|
|
119
|
-
|
|
120
156
|
ps = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
|
|
121
157
|
|
|
122
158
|
if ps.returncode != 0:
|
|
123
|
-
|
|
124
159
|
raise FileImportException(
|
|
125
160
|
(
|
|
126
161
|
"Command {} failed with code {}. MuseScore " "error messages:\n {}"
|
|
127
162
|
).format(cmd, ps.returncode, ps.stderr.decode("UTF-8"))
|
|
128
163
|
)
|
|
129
164
|
except FileNotFoundError as f:
|
|
130
|
-
|
|
131
165
|
raise FileImportException(
|
|
132
166
|
'Executing "{}" returned {}.'.format(" ".join(cmd), f)
|
|
133
167
|
)
|
|
@@ -172,14 +206,9 @@ def render_musescore(
|
|
|
172
206
|
out : Optional[PathLike]
|
|
173
207
|
Path to the output generated image (or None if no image was generated)
|
|
174
208
|
"""
|
|
175
|
-
mscore_exec =
|
|
176
|
-
|
|
177
|
-
if not mscore_exec:
|
|
178
|
-
|
|
179
|
-
return None
|
|
209
|
+
mscore_exec = find_musescore()
|
|
180
210
|
|
|
181
211
|
if fmt not in ("png", "pdf"):
|
|
182
|
-
|
|
183
212
|
warnings.warn("warning: unsupported output format")
|
|
184
213
|
return None
|
|
185
214
|
|
|
@@ -200,9 +229,9 @@ def render_musescore(
|
|
|
200
229
|
"-o",
|
|
201
230
|
os.fspath(img_fh),
|
|
202
231
|
os.fspath(xml_fh),
|
|
232
|
+
"-f",
|
|
203
233
|
]
|
|
204
234
|
try:
|
|
205
|
-
|
|
206
235
|
ps = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
207
236
|
|
|
208
237
|
if ps.returncode != 0:
|
|
@@ -219,7 +248,6 @@ def render_musescore(
|
|
|
219
248
|
return None
|
|
220
249
|
|
|
221
250
|
except FileNotFoundError as f:
|
|
222
|
-
|
|
223
251
|
warnings.warn(
|
|
224
252
|
'Executing "{}" returned {}.'.format(" ".join(cmd), f),
|
|
225
253
|
ImportWarning,
|
|
@@ -232,7 +260,6 @@ def render_musescore(
|
|
|
232
260
|
# ps.stderr.decode('UTF-8')))
|
|
233
261
|
|
|
234
262
|
if fmt == "png":
|
|
235
|
-
|
|
236
263
|
if PIL_EXISTS:
|
|
237
264
|
# get all generated image files
|
|
238
265
|
img_files = glob.glob(
|