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.
Files changed (41) hide show
  1. partitura/directions.py +3 -0
  2. partitura/display.py +0 -1
  3. partitura/io/__init__.py +41 -35
  4. partitura/io/exportmatch.py +52 -10
  5. partitura/io/exportmidi.py +37 -19
  6. partitura/io/exportmusicxml.py +6 -92
  7. partitura/io/exportparangonada.py +18 -19
  8. partitura/io/importkern.py +2 -4
  9. partitura/io/importmatch.py +121 -39
  10. partitura/io/importmei.py +161 -34
  11. partitura/io/importmidi.py +23 -14
  12. partitura/io/importmusic21.py +0 -1
  13. partitura/io/importmusicxml.py +48 -63
  14. partitura/io/importparangonada.py +0 -1
  15. partitura/io/matchfile_base.py +0 -21
  16. partitura/io/matchfile_utils.py +29 -17
  17. partitura/io/matchlines_v0.py +0 -22
  18. partitura/io/matchlines_v1.py +8 -42
  19. partitura/io/musescore.py +68 -41
  20. partitura/musicanalysis/__init__.py +1 -1
  21. partitura/musicanalysis/note_array_to_score.py +147 -92
  22. partitura/musicanalysis/note_features.py +66 -51
  23. partitura/musicanalysis/performance_codec.py +140 -96
  24. partitura/musicanalysis/performance_features.py +190 -129
  25. partitura/musicanalysis/pitch_spelling.py +0 -2
  26. partitura/musicanalysis/tonal_tension.py +0 -6
  27. partitura/musicanalysis/voice_separation.py +1 -22
  28. partitura/performance.py +178 -5
  29. partitura/score.py +154 -74
  30. partitura/utils/__init__.py +1 -1
  31. partitura/utils/generic.py +3 -7
  32. partitura/utils/misc.py +0 -1
  33. partitura/utils/music.py +108 -66
  34. partitura/utils/normalize.py +75 -35
  35. partitura/utils/synth.py +1 -7
  36. {partitura-1.3.0.dist-info → partitura-1.4.0.dist-info}/METADATA +2 -2
  37. partitura-1.4.0.dist-info/RECORD +51 -0
  38. {partitura-1.3.0.dist-info → partitura-1.4.0.dist-info}/WHEEL +1 -1
  39. partitura-1.3.0.dist-info/RECORD +0 -51
  40. {partitura-1.3.0.dist-info → partitura-1.4.0.dist-info}/LICENSE +0 -0
  41. {partitura-1.3.0.dist-info → partitura-1.4.0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,10 @@
1
1
  from partitura.score import ScoreLike, Part
2
- from partitura.utils import (estimate_symbolic_duration, estimate_clef_properties, key_name_to_fifths_mode, fifths_mode_to_key_name)
2
+ from partitura.utils import (
3
+ estimate_symbolic_duration,
4
+ estimate_clef_properties,
5
+ key_name_to_fifths_mode,
6
+ fifths_mode_to_key_name,
7
+ )
3
8
  import warnings
4
9
  import numpy as np
5
10
  from typing import Union
@@ -12,14 +17,14 @@ import partitura.score as score
12
17
  def create_divs_from_beats(note_array: np.ndarray):
13
18
  """
14
19
  Append onset_div and duration_div fields to the note array.
15
- Assumes beats are in uniform units across the whole array
20
+ Assumes beats are in uniform units across the whole array
16
21
  (no time signature change that modifies beat unit, e.g., 4/4 to 6/8).
17
22
 
18
23
  This function may result in an error if time signature changes that affect the ratio of beat/div are present.
19
24
  Parameters
20
25
  ----------
21
26
  note_array: np.ndarray
22
- The note array to which the divs fields will be added.
27
+ The note array to which the divs fields will be added.
23
28
  Normally only beat onset and duration are provided.
24
29
 
25
30
  Returns
@@ -28,18 +33,33 @@ def create_divs_from_beats(note_array: np.ndarray):
28
33
  The note array with the divs fields added.
29
34
  divs: int
30
35
  the divs per beat
31
-
36
+
32
37
  """
33
- duration_fractions = [Fraction(float(ix)).limit_denominator(256) for ix in note_array["duration_beat"]]
34
- onset_fractions = [Fraction(float(ix)).limit_denominator(256) for ix in note_array["onset_beat"]]
38
+ duration_fractions = [
39
+ Fraction(float(ix)).limit_denominator(256) for ix in note_array["duration_beat"]
40
+ ]
41
+ onset_fractions = [
42
+ Fraction(float(ix)).limit_denominator(256) for ix in note_array["onset_beat"]
43
+ ]
35
44
  divs = np.lcm.reduce(
36
- [Fraction(float(ix)).limit_denominator(256).denominator for ix in np.unique(note_array["duration_beat"])])
37
- onset_divs = list(map(lambda r: int(divs * r.numerator / r.denominator), onset_fractions))
45
+ [
46
+ Fraction(float(ix)).limit_denominator(256).denominator
47
+ for ix in np.unique(note_array["duration_beat"])
48
+ ]
49
+ )
50
+ onset_divs = list(
51
+ map(lambda r: int(divs * r.numerator / r.denominator), onset_fractions)
52
+ )
38
53
  min_onset_div = min(onset_divs)
39
54
  if min_onset_div < 0:
40
55
  onset_divs = list(map(lambda x: x - min_onset_div, onset_divs))
41
- duration_divs = list(map(lambda r: int(divs * r.numerator / r.denominator), duration_fractions))
42
- na_divs = np.array(list(zip(onset_divs, duration_divs)), dtype=[("onset_div", int), ("duration_div", int)])
56
+ duration_divs = list(
57
+ map(lambda r: int(divs * r.numerator / r.denominator), duration_fractions)
58
+ )
59
+ na_divs = np.array(
60
+ list(zip(onset_divs, duration_divs)),
61
+ dtype=[("onset_div", int), ("duration_div", int)],
62
+ )
43
63
  return rfn.merge_arrays((note_array, na_divs), flatten=True, usemask=False), divs
44
64
 
45
65
 
@@ -51,7 +71,7 @@ def create_beats_from_divs(note_array: np.ndarray, divs: int):
51
71
  Parameters
52
72
  ----------
53
73
  note_array: np.ndarray
54
- The note array to which the divs fields will be added.
74
+ The note array to which the divs fields will be added.
55
75
  Normally only beat onset and duration are provided.
56
76
  divs: int
57
77
  Divs/ticks per quarter note.
@@ -60,24 +80,27 @@ def create_beats_from_divs(note_array: np.ndarray, divs: int):
60
80
  -------
61
81
  note_array: np.ndarray
62
82
  The note array with the divs fields added.
63
-
83
+
64
84
  """
65
- onset_beats = list(note_array["onset_div"]/divs)
66
- duration_beats = list(note_array["duration_div"]/divs)
67
- na_beats = np.array(list(zip(onset_beats, duration_beats)), dtype=[("onset_beat", float), ("duration_beat", float)])
85
+ onset_beats = list(note_array["onset_div"] / divs)
86
+ duration_beats = list(note_array["duration_div"] / divs)
87
+ na_beats = np.array(
88
+ list(zip(onset_beats, duration_beats)),
89
+ dtype=[("onset_beat", float), ("duration_beat", float)],
90
+ )
68
91
  return rfn.merge_arrays((note_array, na_beats), flatten=True, usemask=False)
69
92
 
70
93
 
71
94
  def create_part(
72
- ticks: int,
73
- note_array: np.ndarray,
74
- key_sigs: list = None,
75
- time_sigs: list = None,
76
- part_id: str = None,
77
- part_name: str = None,
78
- sanitize: bool = True,
79
- anacrusis_divs: int = 0,
80
- barebones: bool = False,
95
+ ticks: int,
96
+ note_array: np.ndarray,
97
+ key_sigs: list = None,
98
+ time_sigs: list = None,
99
+ part_id: str = None,
100
+ part_name: str = None,
101
+ sanitize: bool = True,
102
+ anacrusis_divs: int = 0,
103
+ barebones: bool = False,
81
104
  ):
82
105
  """
83
106
  Create a part from a note array and a list of key signatures.
@@ -109,15 +132,15 @@ def create_part(
109
132
  The part created from the note array and key signatures.
110
133
  """
111
134
 
112
-
113
135
  warnings.warn("create_part", stacklevel=2)
114
136
 
115
- part = Part(part_id, part_name=part_name, )
137
+ part = Part(
138
+ part_id,
139
+ part_name=part_name,
140
+ )
116
141
  part.set_quarter_duration(0, ticks)
117
142
 
118
- clef = score.Clef(
119
- staff=1, **estimate_clef_properties(note_array["pitch"])
120
- )
143
+ clef = score.Clef(staff=1, **estimate_clef_properties(note_array["pitch"]))
121
144
  part.add(clef, 0)
122
145
 
123
146
  # key sig
@@ -128,7 +151,7 @@ def create_part(
128
151
  part.add(score.KeySignature(fifths, mode), t_start, t_end)
129
152
  else:
130
153
  warnings.warn("No key signatures added")
131
-
154
+
132
155
  # time sig
133
156
  if time_sigs is not None:
134
157
  for ts_start, num, den, ts_end in time_sigs:
@@ -149,7 +172,7 @@ def create_part(
149
172
  alter=n["alter"],
150
173
  voice=int(n["voice"] or 0),
151
174
  id=n["id"],
152
- symbolic_duration=estimate_symbolic_duration(n["duration_div"], ticks)
175
+ symbolic_duration=estimate_symbolic_duration(n["duration_div"], ticks),
153
176
  )
154
177
  else:
155
178
  note = score.GraceNote(
@@ -190,17 +213,18 @@ def create_part(
190
213
 
191
214
 
192
215
  def note_array_to_score(
193
- note_array: Union[np.ndarray, list],
194
- name_id: str = "",
195
- divs: int = None,
196
- key_sigs: list = None,
197
- time_sigs: list = None,
198
- part_name: str = "",
199
- assign_note_ids: bool = True,
200
- estimate_key: bool = False,
201
- estimate_time: bool = False,
202
- sanitize: bool = True,
203
- return_part: bool = False) -> ScoreLike:
216
+ note_array: Union[np.ndarray, list],
217
+ name_id: str = "",
218
+ divs: int = None,
219
+ key_sigs: list = None,
220
+ time_sigs: list = None,
221
+ part_name: str = "",
222
+ assign_note_ids: bool = True,
223
+ estimate_key: bool = False,
224
+ estimate_time: bool = False,
225
+ sanitize: bool = True,
226
+ return_part: bool = False,
227
+ ) -> ScoreLike:
204
228
  """
205
229
  A generic function to transform an enriched note_array to part or Score.
206
230
 
@@ -263,7 +287,7 @@ def note_array_to_score(
263
287
  - key_fifths(optional)
264
288
  - id (optional)
265
289
  divs : int (optional)
266
- Divs/ticks per quarter note.
290
+ Divs/ticks per quarter note.
267
291
  If not given, it is estimated assuming a beats in quarters.
268
292
  key_sigs: list (optional)
269
293
  A list of key signatures. Each key signature is a tuple of the form (onset, key_name, offset).
@@ -292,10 +316,18 @@ def note_array_to_score(
292
316
 
293
317
  if isinstance(note_array, list):
294
318
  parts = [
295
- note_array_to_score(note_array=x, name_id=str(i), assign_note_ids=assign_note_ids,
296
- return_part=True, divs=divs, estimate_key=estimate_key, sanitize=sanitize,
297
- part_name=name_id+"_P"+str(i)) for
298
- i, x in enumerate(note_array)]
319
+ note_array_to_score(
320
+ note_array=x,
321
+ name_id=str(i),
322
+ assign_note_ids=assign_note_ids,
323
+ return_part=True,
324
+ divs=divs,
325
+ estimate_key=estimate_key,
326
+ sanitize=sanitize,
327
+ part_name=name_id + "_P" + str(i),
328
+ )
329
+ for i, x in enumerate(note_array)
330
+ ]
299
331
  return score.Score(partlist=parts)
300
332
 
301
333
  # Input validation
@@ -311,14 +343,14 @@ def note_array_to_score(
311
343
  ks_case = ["key_fifths", "key_mode"]
312
344
 
313
345
  case1 = ["onset_beat", "duration_beat", "pitch"]
314
- case1_ex = ["onset_div", "duration_div"]
346
+ case1_ex = ["onset_div", "duration_div"]
315
347
  case2 = ["onset_div", "duration_div", "pitch"]
316
- case2_ex = ["onset_beat", "duration_beat"]
348
+ case2_ex = ["onset_beat", "duration_beat"]
317
349
  # case3 = ["onset_div", "duration_div", "onset_beat", "duration_beat", "pitch"]
318
350
 
319
351
  if not (all([x in dtypes for x in case1]) or all([x in dtypes for x in case2])):
320
352
  raise ValueError("not all necessary note array fields are available")
321
-
353
+
322
354
  # sort the array
323
355
  onset_time = "onset_div"
324
356
  duration_time = "duration_div"
@@ -327,7 +359,9 @@ def note_array_to_score(
327
359
  duration_time = "duration_beat"
328
360
 
329
361
  # Order Lexicographically
330
- sort_idx = np.lexsort((note_array[duration_time], note_array["pitch"], note_array[onset_time]))
362
+ sort_idx = np.lexsort(
363
+ (note_array[duration_time], note_array["pitch"], note_array[onset_time])
364
+ )
331
365
  note_array = note_array[sort_idx]
332
366
 
333
367
  # case 1, estimate divs
@@ -336,37 +370,37 @@ def note_array_to_score(
336
370
  note_array, divs_ = create_divs_from_beats(note_array)
337
371
  if divs is not None and divs != divs_:
338
372
  raise ValueError("estimated divs don't correspond to input divs")
339
- else:
373
+ else:
340
374
  divs = divs_
341
375
 
342
- # case 1: convert key sig times to divs
376
+ # case 1: convert key sig times to divs
343
377
  if key_sigs is not None:
344
378
  key_sigs = np.array(key_sigs)
345
379
  if key_sigs.shape[1] == 2:
346
- key_sigs[:,0] = (key_sigs[:,0] / divs).astype(int)
380
+ key_sigs[:, 0] = (key_sigs[:, 0] / divs).astype(int)
347
381
  elif key_sigs.shape[1] == 3:
348
- key_sigs[:,0] = (key_sigs[:,0] / divs).astype(int)
349
- key_sigs[:,2] = (key_sigs[:,2] / divs).astype(int)
382
+ key_sigs[:, 0] = (key_sigs[:, 0] / divs).astype(int)
383
+ key_sigs[:, 2] = (key_sigs[:, 2] / divs).astype(int)
350
384
  else:
351
385
  raise ValueError("key_sigs is given in a wrong format")
352
-
353
- # case 1: convert time sig times to divs
386
+
387
+ # case 1: convert time sig times to divs
354
388
  if time_sigs is not None:
355
389
  time_sigs = np.array(time_sigs)
356
390
  if time_sigs.shape[1] == 3:
357
- time_sigs[:,0] = (time_sigs[:,0] / divs).astype(int)
391
+ time_sigs[:, 0] = (time_sigs[:, 0] / divs).astype(int)
358
392
  elif time_sigs.shape[1] == 4:
359
- time_sigs[:,0] = (time_sigs[:,0] / divs).astype(int)
360
- time_sigs[:,3] = (time_sigs[:,3] / divs).astype(int)
393
+ time_sigs[:, 0] = (time_sigs[:, 0] / divs).astype(int)
394
+ time_sigs[:, 3] = (time_sigs[:, 3] / divs).astype(int)
361
395
  else:
362
396
  raise ValueError("time_sigs is given in a wrong format")
363
397
 
364
398
  # case 2, estimate beats
365
399
  if all([x in dtypes for x in case2] and [x not in dtypes for x in case2_ex]):
366
400
  # estimate onset_beats and duration_beats in quarters
367
- if divs is None :
401
+ if divs is None:
368
402
  raise ValueError("Divs/ticks need to be specified")
369
- else:
403
+ else:
370
404
  note_array = create_beats_from_divs(note_array, divs)
371
405
 
372
406
  if divs is None:
@@ -375,40 +409,50 @@ def note_array_to_score(
375
409
  if dur != 0:
376
410
  break
377
411
  if all([x in dtypes for x in ts_case]):
378
- divs = int((note_array[idx]["duration_div"] / note_array[idx]["duration_beat"]) /
379
- (4 / note_array[idx]["ts_beat_type"] ))
380
- else:
381
- divs = int(note_array[idx]["duration_div"] / note_array[idx]["duration_beat"])
412
+ divs = int(
413
+ (note_array[idx]["duration_div"] / note_array[idx]["duration_beat"])
414
+ / (4 / note_array[idx]["ts_beat_type"])
415
+ )
416
+ else:
417
+ divs = int(
418
+ note_array[idx]["duration_div"] / note_array[idx]["duration_beat"]
419
+ )
382
420
 
383
421
  # Test Note array for negative durations
384
422
  if not np.all(note_array["duration_div"] >= 0):
385
423
  raise ValueError("Note array contains negative durations.")
386
424
  if not np.all(note_array["duration_beat"] >= 0):
387
425
  raise ValueError("Note array contains negative durations.")
388
-
426
+
389
427
  # Test for negative divs
390
428
  if not np.all(note_array["onset_div"] >= 0):
391
429
  raise ValueError("Negative divs found in note_array.")
392
-
430
+
393
431
  # handle time signatures
394
- if all([x in dtypes for x in ts_case]):
432
+ if all([x in dtypes for x in ts_case]):
395
433
  time_sigs = [[0, note_array[0]["ts_beats"], note_array[0]["ts_beat_type"]]]
396
434
  for n in note_array:
397
- if n["ts_beats"] != time_sigs[-1][1] or n["ts_beat_type"] != time_sigs[-1][2]:
435
+ if (
436
+ n["ts_beats"] != time_sigs[-1][1]
437
+ or n["ts_beat_type"] != time_sigs[-1][2]
438
+ ):
398
439
  time_sigs.append([n["onset_div"], n["ts_beats"], n["ts_beat_type"]])
399
440
  global_time_sigs = np.array(time_sigs)
400
441
  elif time_sigs is not None:
401
442
  global_time_sigs = time_sigs
402
443
  elif estimate_time:
403
444
  global_time_sigs = [[0, 4, 4]]
404
- else:
445
+ else:
405
446
  global_time_sigs = None
406
447
 
407
448
  if global_time_sigs is not None:
408
449
  global_time_sigs = np.array(global_time_sigs)
409
450
  if global_time_sigs.shape[1] == 3:
410
451
  # for convenience, we add the end times for each time signature
411
- ts_end_times = np.r_[global_time_sigs[1:, 0], np.max(note_array["onset_div"]+note_array["duration_div"])]
452
+ ts_end_times = np.r_[
453
+ global_time_sigs[1:, 0],
454
+ np.max(note_array["onset_div"] + note_array["duration_div"]),
455
+ ]
412
456
  global_time_sigs = np.column_stack((global_time_sigs, ts_end_times))
413
457
  elif global_time_sigs.shape[1] == 4:
414
458
  pass
@@ -417,19 +461,17 @@ def note_array_to_score(
417
461
 
418
462
  # make sure there is a time signature from the beginning
419
463
  global_time_sigs[0, 0] = 0
420
-
421
-
422
464
 
423
465
  # Note id creation or re-assignment
424
466
  if "id" not in dtypes:
425
467
  note_ids = ["{}n{:4d}".format(name_id, i) for i in range(len(note_array))]
426
- note_array = rfn.append_fields(note_array, "id", np.array(note_ids, dtype='<U256'))
468
+ note_array = rfn.append_fields(
469
+ note_array, "id", np.array(note_ids, dtype="<U256")
470
+ )
427
471
  elif assign_note_ids or np.all(note_array["id"] == note_array["id"][0]):
428
472
  note_ids = ["{}n{:4d}".format(name_id, i) for i in range(len(note_array))]
429
473
  note_array["id"] = np.array(note_ids)
430
474
 
431
-
432
-
433
475
  # estimate voice
434
476
  if "voice" in dtypes:
435
477
  estimate_voice_info = False
@@ -444,23 +486,36 @@ def note_array_to_score(
444
486
  # Zero duration notes are currently deleted
445
487
  estimated_voices = analysis.estimate_voices(note_array)
446
488
  assert len(part_voice_list) == len(estimated_voices)
447
- for i, (part_voice, voice_est) in enumerate(zip(part_voice_list, estimated_voices)):
489
+ for i, (part_voice, voice_est) in enumerate(
490
+ zip(part_voice_list, estimated_voices)
491
+ ):
448
492
  # Not sure if correct.
449
493
  if part_voice != np.inf:
450
494
  estimated_voices[i] = part_voice
451
- note_array = rfn.append_fields(note_array, "voice", np.array(estimated_voices, dtype=int))
495
+ note_array = rfn.append_fields(
496
+ note_array, "voice", np.array(estimated_voices, dtype=int)
497
+ )
452
498
 
453
499
  # estimate pitch spelling
454
- if not all(x in dtypes for x in ['step', 'alter', 'octave']):
500
+ if not all(x in dtypes for x in ["step", "alter", "octave"]):
455
501
  warnings.warn("pitch spelling")
456
502
  spelling_global = analysis.estimate_spelling(note_array)
457
503
  note_array = rfn.merge_arrays((note_array, spelling_global), flatten=True)
458
504
 
459
505
  # handle or estimate key signature
460
- if all([x in dtypes for x in ks_case]):
461
- global_key_sigs = [[0, fifths_mode_to_key_name(note_array[0]["ks_fifths"], note_array[0]["ks_mode"])]]
506
+ if all([x in dtypes for x in ks_case]):
507
+ global_key_sigs = [
508
+ [
509
+ 0,
510
+ fifths_mode_to_key_name(
511
+ note_array[0]["ks_fifths"], note_array[0]["ks_mode"]
512
+ ),
513
+ ]
514
+ ]
462
515
  for n in note_array:
463
- global_key_sigs.append([n["onset_div"], fifths_mode_to_key_name(n["ks_fifths"], n["ks_mode"])])
516
+ global_key_sigs.append(
517
+ [n["onset_div"], fifths_mode_to_key_name(n["ks_fifths"], n["ks_mode"])]
518
+ )
464
519
  else:
465
520
  global_key_sigs = key_sigs
466
521
  elif key_sigs is not None:
@@ -475,16 +530,19 @@ def note_array_to_score(
475
530
  global_key_sigs = np.array(global_key_sigs)
476
531
  if global_key_sigs.shape[1] == 2:
477
532
  # for convenience, we add the end times for each time signature
478
- ks_end_times = np.r_[global_key_sigs[1:, 0], np.max(note_array["onset_div"]+note_array["duration_div"])]
533
+ ks_end_times = np.r_[
534
+ global_key_sigs[1:, 0],
535
+ np.max(note_array["onset_div"] + note_array["duration_div"]),
536
+ ]
479
537
  global_key_sigs = np.column_stack((global_key_sigs, ks_end_times))
480
538
  elif global_key_sigs.shape[1] == 3:
481
539
  pass
482
540
  else:
483
541
  raise ValueError("key_sigs is given in a wrong format")
484
-
542
+
485
543
  # make sure there is a key signature from the beginning
486
544
  global_key_sigs[0, 0] = 0
487
-
545
+
488
546
  # Steps for dealing with anacrusis measure.
489
547
  anacrusis_mask = np.zeros(len(note_array), dtype=bool)
490
548
  anacrusis_mask[note_array["onset_beat"] < 0] = True
@@ -494,15 +552,13 @@ def note_array_to_score(
494
552
  else:
495
553
  last_neg_beat = np.max(note_array[anacrusis_mask]["onset_beat"])
496
554
  last_neg_divs = np.max(note_array[anacrusis_mask]["onset_div"])
497
- if all([x in dtypes for x in ts_case]):
555
+ if all([x in dtypes for x in ts_case]):
498
556
  beat_type = np.max(note_array[anacrusis_mask]["ts_beat_type"])
499
557
  else:
500
558
  beat_type = 4
501
559
  difference_from_zero = (0 - last_neg_beat) * divs * (4 / beat_type)
502
560
  anacrusis_divs = int(last_neg_divs + difference_from_zero)
503
561
 
504
-
505
-
506
562
  # Create the part
507
563
  part = create_part(
508
564
  ticks=divs,
@@ -512,11 +568,10 @@ def note_array_to_score(
512
568
  part_id=name_id,
513
569
  part_name=part_name,
514
570
  sanitize=sanitize,
515
- anacrusis_divs=anacrusis_divs
571
+ anacrusis_divs=anacrusis_divs,
516
572
  )
517
573
  # Return Part or Score
518
574
  if return_part:
519
575
  return part
520
576
  else:
521
577
  return score.Score(partlist=[part], id=name_id)
522
-