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
partitura/utils/music.py CHANGED
@@ -20,13 +20,15 @@ import os
20
20
  try:
21
21
  import miditok
22
22
  from miditok.midi_tokenizer import MIDITokenizer
23
- import miditoolkit
23
+ import miditoolkit
24
24
  except ImportError:
25
25
  miditok = None
26
26
  miditoolkit = None
27
+
27
28
  class MIDITokenizer(object):
28
29
  pass
29
30
 
31
+
30
32
  from partitura.utils.misc import deprecated_alias
31
33
 
32
34
  if TYPE_CHECKING:
@@ -277,13 +279,39 @@ INTERVALCLASSES = [
277
279
  for specific in ["dd", "d", "P", "A", "AA"]
278
280
  ]
279
281
 
280
- INTERVAL_TO_SEMITONES = dict(zip(INTERVALCLASSES, [
281
- generic+specific for generic in [1, 3, 8, 10] for specific in [-2, -1, 0, 1, 2, 3]
282
- ] + [generic+specific for generic in [0, 5, 7] for specific in [-2, -1, 0, 1, 2]]))
283
-
282
+ INTERVAL_TO_SEMITONES = dict(
283
+ zip(
284
+ INTERVALCLASSES,
285
+ [
286
+ generic + specific
287
+ for generic in [1, 3, 8, 10]
288
+ for specific in [-2, -1, 0, 1, 2, 3]
289
+ ]
290
+ + [
291
+ generic + specific
292
+ for generic in [0, 5, 7]
293
+ for specific in [-2, -1, 0, 1, 2]
294
+ ],
295
+ )
296
+ )
284
297
 
285
- STEPS = {"C": 0, "D": 1, "E": 2, "F": 3, "G": 4, "A": 5, "B": 6, 0: "C", 1: "D", 2: "E", 3: "F", 4: "G", 5: "A", 6: "B"}
286
298
 
299
+ STEPS = {
300
+ "C": 0,
301
+ "D": 1,
302
+ "E": 2,
303
+ "F": 3,
304
+ "G": 4,
305
+ "A": 5,
306
+ "B": 6,
307
+ 0: "C",
308
+ 1: "D",
309
+ 2: "E",
310
+ 3: "F",
311
+ 4: "G",
312
+ 5: "A",
313
+ 6: "B",
314
+ }
287
315
 
288
316
 
289
317
  MUSICAL_BEATS = {6: 2, 9: 3, 12: 4}
@@ -406,7 +434,7 @@ def transpose_step(step, interval, direction):
406
434
  if interval == "P1":
407
435
  pass
408
436
  else:
409
- step = STEPS[op(STEPS[step.capitalize()], interval-1)]
437
+ step = STEPS[op(STEPS[step.capitalize()], interval - 1)]
410
438
  return step
411
439
 
412
440
 
@@ -419,7 +447,7 @@ def _transpose_note(note, interval):
419
447
  inverval
420
448
 
421
449
  """
422
- if interval.quality+str(interval.number) == "P1":
450
+ if interval.quality + str(interval.number) == "P1":
423
451
  pass
424
452
  else:
425
453
  # TODO work for arbitrary octave.
@@ -438,7 +466,9 @@ def _transpose_note(note, interval):
438
466
  diff_sm = tmp_pc - prev_pc if tmp_pc >= prev_pc else tmp_pc + 12 - prev_pc
439
467
  else:
440
468
  diff_sm = prev_pc - tmp_pc if prev_pc >= tmp_pc else prev_pc + 12 - tmp_pc
441
- note.alter = INTERVAL_TO_SEMITONES[interval.quality+str(interval.number)] - diff_sm
469
+ note.alter = (
470
+ INTERVAL_TO_SEMITONES[interval.quality + str(interval.number)] - diff_sm
471
+ )
442
472
 
443
473
 
444
474
  def transpose(score: ScoreLike, interval: Interval) -> ScoreLike:
@@ -458,7 +488,15 @@ def transpose(score: ScoreLike, interval: Interval) -> ScoreLike:
458
488
  Transposed score.
459
489
  """
460
490
  import partitura.score as s
491
+ import sys
492
+
493
+ # Copy needs to be deep, otherwise the recursion limit will be exceeded
494
+ old_recursion_depth = sys.getrecursionlimit()
495
+ sys.setrecursionlimit(10000)
496
+ # Deep copy of score
461
497
  new_score = copy.deepcopy(score)
498
+ # Reset recursion limit to previous value to avoid side effects
499
+ sys.setrecursionlimit(old_recursion_depth)
462
500
  if isinstance(score, s.Score):
463
501
  for part in new_score.parts:
464
502
  transpose(part, interval)
@@ -655,6 +693,8 @@ def midi_ticks_to_seconds(
655
693
 
656
694
  SIGN_TO_ALTER = {
657
695
  "n": 0,
696
+ "ns": 1,
697
+ "nf": -1,
658
698
  "#": 1,
659
699
  "s": 1,
660
700
  "ss": 2,
@@ -671,7 +711,6 @@ SIGN_TO_ALTER = {
671
711
 
672
712
 
673
713
  def ensure_pitch_spelling_format(step, alter, octave):
674
-
675
714
  if step.lower() not in MIDI_BASE_CLASS:
676
715
  if step.lower() != "r":
677
716
  raise ValueError("Invalid `step`")
@@ -961,14 +1000,12 @@ def format_symbolic_duration(symbolic_dur):
961
1000
 
962
1001
  """
963
1002
  if symbolic_dur is None:
964
-
965
1003
  return "unknown"
966
1004
 
967
1005
  else:
968
1006
  result = (symbolic_dur.get("type") or "") + "." * symbolic_dur.get("dots", 0)
969
1007
 
970
1008
  if "actual_notes" in symbolic_dur and "normal_notes" in symbolic_dur:
971
-
972
1009
  result += "_{}/{}".format(
973
1010
  symbolic_dur["actual_notes"], symbolic_dur["normal_notes"]
974
1011
  )
@@ -1712,7 +1749,6 @@ def match_note_arrays(
1712
1749
  target_note_array = ensure_notearray(target_note_array)
1713
1750
 
1714
1751
  if fields is not None:
1715
-
1716
1752
  if isinstance(fields, (list, tuple)):
1717
1753
  onset_key, duration_key = fields
1718
1754
  elif isinstance(fields, str):
@@ -1861,7 +1897,6 @@ def remove_silence_from_performed_part(ppart):
1861
1897
  for track in control_dict:
1862
1898
  for channel in control_dict[track]:
1863
1899
  for number, ct in control_dict[track][channel].items():
1864
-
1865
1900
  cta = np.array(ct)
1866
1901
  cinterp = interp1d(
1867
1902
  x=cta[:, 0],
@@ -2567,7 +2602,6 @@ def note_array_from_note_list(
2567
2602
 
2568
2603
  note_array = []
2569
2604
  for note in note_list:
2570
-
2571
2605
  note_info = tuple()
2572
2606
  note_on_div = note.start.t
2573
2607
  note_off_div = note.start.t + note.duration_tied
@@ -2762,7 +2796,6 @@ def rest_array_from_rest_list(
2762
2796
 
2763
2797
  rest_array = []
2764
2798
  for rest in rest_list:
2765
-
2766
2799
  rest_info = tuple()
2767
2800
  rest_on_div = rest.start.t
2768
2801
  rest_off_div = rest.start.t + rest.duration_tied
@@ -2875,14 +2908,12 @@ def rec_collapse_rests(rest_array):
2875
2908
 
2876
2909
 
2877
2910
  def update_note_ids_after_unfolding(part):
2878
-
2879
2911
  note_id_dict = defaultdict(list)
2880
2912
 
2881
2913
  for n in part.notes:
2882
2914
  note_id_dict[n.id].append(n)
2883
2915
 
2884
2916
  for nid, notes in note_id_dict.items():
2885
-
2886
2917
  if nid is None:
2887
2918
  continue
2888
2919
 
@@ -2988,9 +3019,7 @@ def performance_notearray_from_score_notearray(
2988
3019
  pnote_array = np.zeros(len(snote_array), dtype=ppart_fields)
2989
3020
 
2990
3021
  if isinstance(velocity, np.ndarray):
2991
-
2992
3022
  if velocity.ndim == 2:
2993
-
2994
3023
  velocity_fun = interp1d(
2995
3024
  x=velocity[:, 0],
2996
3025
  y=velocity[:, 1],
@@ -3026,7 +3055,6 @@ def performance_notearray_from_score_notearray(
3026
3055
  iois = np.diff(unique_onsets)
3027
3056
 
3028
3057
  if callable(bpm) or isinstance(bpm, np.ndarray):
3029
-
3030
3058
  if callable(bpm):
3031
3059
  # bpm parameter is a callable that returns a bpm value
3032
3060
  # for each score onset
@@ -3036,7 +3064,6 @@ def performance_notearray_from_score_notearray(
3036
3064
  )
3037
3065
 
3038
3066
  elif isinstance(bpm, np.ndarray):
3039
-
3040
3067
  if bpm.ndim != 2:
3041
3068
  raise ValueError("`bpm` should be a 2D array")
3042
3069
 
@@ -3209,7 +3236,7 @@ def slice_ppart_by_time(
3209
3236
  ----------
3210
3237
  ppart : `PerformedPart` object
3211
3238
  start_time : float
3212
- Starting time in seconds
3239
+ Starting time in seconds
3213
3240
  end_time : float
3214
3241
  End time in seconds
3215
3242
  clip_note_off : bool
@@ -3234,90 +3261,98 @@ def slice_ppart_by_time(
3234
3261
  # create a new (empty) instance of a PerformedPart
3235
3262
  # single dummy note added to be able to set sustain_pedal_threshold in __init__
3236
3263
  # -> check `adjust_offsets_w_sustain` in partitura.performance
3237
- ppart_slice = PerformedPart([{'note_on': 0, 'note_off': 0}])
3264
+ # ppart_slice = PerformedPart([{"note_on": 0, "note_off": 0, "pitch": 0}])
3238
3265
 
3239
3266
  # get ppq if PerformedPart contains it,
3240
3267
  # else skip time_tick info when e.g. created with 'load_performance_midi'
3241
3268
  try:
3242
3269
  ppq = ppart.ppq
3243
- ppart_slice.ppq = ppq
3244
3270
  except AttributeError:
3245
3271
  ppq = None
3246
3272
 
3273
+ controls_slice = []
3247
3274
  if ppart.controls:
3248
- controls_slice = []
3249
3275
  for cc in ppart.controls:
3250
- if cc['time'] >= start_time and cc['time'] <= end_time:
3276
+ if cc["time"] >= start_time and cc["time"] <= end_time:
3251
3277
  new_cc = cc.copy()
3252
- new_cc['time'] -= start_time
3278
+ new_cc["time"] -= start_time
3253
3279
  if ppq:
3254
- new_cc['time_tick'] = int(2 * ppq * cc['time'])
3280
+ new_cc["time_tick"] = int(2 * ppq * cc["time"])
3255
3281
  controls_slice.append(new_cc)
3256
- ppart_slice.controls = controls_slice
3257
-
3282
+
3283
+ programs_slice = []
3258
3284
  if ppart.programs:
3259
- programs_slice = []
3260
3285
  for pr in ppart.programs:
3261
- if pr['time'] >= start_time and pr['time'] <= end_time:
3286
+ if pr["time"] >= start_time and pr["time"] <= end_time:
3262
3287
  new_pr = pr.copy()
3263
- new_pr['time'] -= start_time
3288
+ new_pr["time"] -= start_time
3264
3289
  if ppq:
3265
- new_pr['time_tick'] = int(2 * ppq * pr['time'])
3290
+ new_pr["time_tick"] = int(2 * ppq * pr["time"])
3266
3291
  programs_slice.append(new_pr)
3267
- ppart_slice.programs = programs_slice
3268
3292
 
3269
3293
  notes_slice = []
3270
3294
  note_id = 0
3271
- for note in ppart.notes:
3295
+ for note in ppart.notes:
3272
3296
  # collect previous sounding notes at start_time
3273
3297
  if note["note_on"] < start_time and note["note_off"] > start_time:
3274
3298
  new_note = note.copy()
3275
- new_note['note_on'] = 0.
3299
+ new_note["note_on"] = 0.0
3276
3300
  if clip_note_off:
3277
- new_note['note_off'] = min(note['note_off'] - start_time, end_time - start_time)
3278
- else:
3279
- new_note['note_off'] = note['note_off'] - start_time
3301
+ new_note["note_off"] = min(
3302
+ note["note_off"] - start_time, end_time - start_time
3303
+ )
3304
+ else:
3305
+ new_note["note_off"] = note["note_off"] - start_time
3280
3306
  if ppq:
3281
- new_note['note_on_tick'] = 0
3282
- new_note['note_off_tick'] = int(2 * ppq * new_note['note_off'])
3307
+ new_note["note_on_tick"] = 0
3308
+ new_note["note_off_tick"] = int(2 * ppq * new_note["note_off"])
3283
3309
  if reindex_notes:
3284
- new_note['id'] = f"n{note_id}"
3310
+ new_note["id"] = f"n{note_id}"
3285
3311
  note_id += 1
3286
3312
  notes_slice.append(new_note)
3287
3313
  # todo - combine both cases
3288
- if note['note_on'] >= start_time:
3289
- if note['note_on'] < end_time:
3314
+ if note["note_on"] >= start_time:
3315
+ if note["note_on"] < end_time:
3290
3316
  new_note = note.copy()
3291
- new_note['note_on'] -= start_time
3317
+ new_note["note_on"] -= start_time
3292
3318
  if clip_note_off:
3293
- new_note['note_off'] = min(note['note_off'] - start_time, end_time - start_time)
3294
- else:
3295
- new_note['note_off'] = note['note_off'] - start_time
3319
+ new_note["note_off"] = min(
3320
+ note["note_off"] - start_time, end_time - start_time
3321
+ )
3322
+ else:
3323
+ new_note["note_off"] = note["note_off"] - start_time
3296
3324
  if ppq:
3297
- new_note['note_on_tick'] = int(2 * ppq * new_note['note_on'])
3298
- new_note['note_off_tick'] = int(2 * ppq * new_note['note_off'])
3325
+ new_note["note_on_tick"] = int(2 * ppq * new_note["note_on"])
3326
+ new_note["note_off_tick"] = int(2 * ppq * new_note["note_off"])
3299
3327
  if reindex_notes:
3300
- new_note['id'] = 'n' + str(note_id)
3328
+ new_note["id"] = "n" + str(note_id)
3301
3329
  note_id += 1
3302
3330
  notes_slice.append(new_note)
3303
- # assumes notes in list are sorted by onset time
3304
- else:
3305
- break
3306
-
3307
- ppart_slice.notes = notes_slice
3308
-
3309
- # set threshold property after creating notes list to update 'sound_offset' values
3331
+ # assumes notes in list are sorted by onset time
3332
+ else:
3333
+ break
3334
+
3335
+ # Create slice PerformedPart
3336
+ ppart_slice = PerformedPart(
3337
+ notes=notes_slice, programs=programs_slice, controls=controls_slice, ppq=ppq
3338
+ )
3339
+
3340
+ # set threshold property after creating notes list to update 'sound_offset' values
3310
3341
  ppart_slice.sustain_pedal_threshold = ppart.sustain_pedal_threshold
3311
3342
 
3312
3343
  if ppart.id:
3313
- ppart_slice.id = ppart.id + '_slice_{}s_to_{}s'.format(start_time, end_time)
3344
+ ppart_slice.id = ppart.id + "_slice_{}s_to_{}s".format(start_time, end_time)
3314
3345
  if ppart.part_name:
3315
- ppart_slice.part_name = ppart.part_name
3346
+ ppart_slice.part_name = ppart.part_name
3316
3347
 
3317
3348
  return ppart_slice
3318
3349
 
3319
3350
 
3320
- def tokenize(score_data : ScoreLike, tokenizer : MIDITokenizer, incomplete_bar_behaviour : str = "pad_bar"):
3351
+ def tokenize(
3352
+ score_data: ScoreLike,
3353
+ tokenizer: MIDITokenizer,
3354
+ incomplete_bar_behaviour: str = "pad_bar",
3355
+ ):
3321
3356
  """
3322
3357
  Tokenize a score using a tokenizer from miditok.
3323
3358
  Parameters
@@ -3340,16 +3375,23 @@ def tokenize(score_data : ScoreLike, tokenizer : MIDITokenizer, incomplete_bar_b
3340
3375
  """
3341
3376
 
3342
3377
  if miditok is None or miditoolkit is None:
3343
- raise ImportError("Miditok and miditoolkit must be installed for this function to work")
3378
+ raise ImportError(
3379
+ "Miditok and miditoolkit must be installed for this function to work"
3380
+ )
3344
3381
  with TemporaryDirectory() as tmpdir:
3345
3382
  temp_midi_path = os.path.join(tmpdir, "temp_midi.mid")
3346
- partitura.io.exportmidi.save_score_midi(score_data, out = temp_midi_path, anacrusis_behavior=incomplete_bar_behaviour, part_voice_assign_mode = 4, minimum_ppq = 480 )
3383
+ partitura.io.exportmidi.save_score_midi(
3384
+ score_data,
3385
+ out=temp_midi_path,
3386
+ anacrusis_behavior=incomplete_bar_behaviour,
3387
+ part_voice_assign_mode=4,
3388
+ minimum_ppq=480,
3389
+ )
3347
3390
  midi = miditoolkit.MidiFile(temp_midi_path)
3348
3391
  tokens = tokenizer(midi)
3349
3392
  return tokens
3350
3393
 
3351
3394
 
3352
-
3353
3395
  if __name__ == "__main__":
3354
3396
  import doctest
3355
3397
 
@@ -6,20 +6,23 @@ This module contains normalization utilities
6
6
  import numpy as np
7
7
 
8
8
 
9
- EPSILON=0.0001
10
-
11
-
12
- def range_normalize(array,
13
- min_value = None,
14
- max_value = None,
15
- log = False,
16
- exp = False,
17
- hard_clip = True):
18
-
9
+ EPSILON = 0.0001
10
+
11
+
12
+ def range_normalize(
13
+ array,
14
+ min_value=None,
15
+ max_value=None,
16
+ log=False,
17
+ log2=False,
18
+ exp=False,
19
+ exp2=False,
20
+ hard_clip=True,
21
+ ):
19
22
  """
20
23
  Linear mapping a vector from range [min_value, max_value] to [0, 1].
21
24
  Preprocessing possible with log and exp.
22
- Values exceeding the range [0, 1] are clipped to 0 or 1 if
25
+ Values exceeding the range [0, 1] are clipped to 0 or 1 if
23
26
  clip is True, otherwise they are extrapolated.
24
27
  """
25
28
  if min_value is None:
@@ -28,8 +31,12 @@ def range_normalize(array,
28
31
  max_value = array.max()
29
32
  if log:
30
33
  array = np.log(np.abs(array) + EPSILON)
34
+ elif log2:
35
+ array = np.log2(np.abs(array) + EPSILON)
31
36
  if exp:
32
37
  array = np.exp(array)
38
+ elif exp2:
39
+ array = np.exp2(array)
33
40
  # handle div by zero
34
41
  if min_value == max_value:
35
42
  array = np.clip(array, 0, 1)
@@ -41,17 +48,13 @@ def range_normalize(array,
41
48
  return array
42
49
 
43
50
 
44
- def zero_one_normalize(array,
45
- min_value = -3.0,
46
- max_value = 3.0,
47
- log = False,
48
- exp = False,
49
- clip = True):
50
-
51
+ def zero_one_normalize(
52
+ array, min_value=-3.0, max_value=3.0, log=False, exp=False, clip=True
53
+ ):
51
54
  """
52
55
  Compute zero mean and unit variance of a vector.
53
56
  Preprocessing possible with log and exp.
54
- Values exceeding the range [-min_value, max_value]
57
+ Values exceeding the range [-min_value, max_value]
55
58
  are clipped if clip is True.
56
59
  """
57
60
 
@@ -76,41 +79,75 @@ def minmaxrange_normalize(array):
76
79
 
77
80
 
78
81
  DEFAULT_NORM_FUNCS = {
79
- "pitch": {"func": range_normalize, # some normalization function
80
- "kwargs": {"min_value":0, "max_value":127}}, # some keyword arguments
82
+ "pitch": {
83
+ "func": range_normalize,
84
+ "kwargs": {"min_value": 0, "max_value": 127},
85
+ },
86
+ "velocity": {
87
+ "func": range_normalize,
88
+ "kwargs": {"min_value": 0, "max_value": 127},
89
+ },
90
+ "onset_beat": {
91
+ "func": minmaxrange_normalize,
92
+ "kwargs": {},
93
+ },
94
+ "duration_beat": {
95
+ "func": range_normalize,
96
+ "kwargs": {"min_value": -3, "max_value": 3, "log2": True},
97
+ # ref beat = 4th -> -3 = 32nd, 3 = breve
98
+ },
99
+ "beat_period": {
100
+ "func": range_normalize,
101
+ "kwargs": {"min_value": -3, "max_value": 2, "log2": True},
102
+ # ref 1 second / beat -> -3 = 0.125 sec / beat , 2 = 4 sec / beat
103
+ },
104
+ "timing": {
105
+ "func": range_normalize,
106
+ "kwargs": {"min_value": -0.2, "max_value": 0.2},
107
+ # deviation in seconds
108
+ },
109
+ "articulation_log": {
110
+ "func": range_normalize,
111
+ "kwargs": {"min_value": -4, "max_value": 3},
112
+ # thia ia the ratio in base2 log -> just min max clip
113
+ },
81
114
  # fill up with all note and performance features
82
115
  }
83
116
 
84
117
 
85
- def normalize(in_array,
86
- norm_funcs = DEFAULT_NORM_FUNCS,
87
- norm_func_fallback = minmaxrange_normalize,
88
- default_value = np.inf
89
- ):
90
-
118
+ def normalize(
119
+ in_array,
120
+ norm_funcs=DEFAULT_NORM_FUNCS,
121
+ norm_func_fallback=minmaxrange_normalize,
122
+ default_value=np.inf,
123
+ ):
91
124
  """
92
125
  Normalize a note array.
93
126
  May include note features as well as performance features.
94
127
  All input columns must be of numeric types, everything is
95
128
  cast to single precision float.
96
-
129
+
97
130
  Parameters
98
131
  ----------
99
132
  array : np.ndarray
100
133
  The performance array to be normalized.
101
134
  norm_funcs : dict
102
135
  A dictionary of normalization functions for each feature.
103
-
136
+
104
137
  Returns
105
138
  -------
106
139
  array : np.ndarray
107
140
  The normalized performance array.
108
141
  """
109
- dtype_new = np.dtype({'names':in_array.dtype.names, 'formats': [float for k in range(len(in_array.dtype.names))]})
142
+ dtype_new = np.dtype(
143
+ {
144
+ "names": in_array.dtype.names,
145
+ "formats": [float for k in range(len(in_array.dtype.names))],
146
+ }
147
+ )
110
148
  array = in_array.copy().astype(dtype_new)
111
149
 
112
150
  for feature in array.dtype.names:
113
-
114
151
  # use mask for non-default values and don't change default values
115
152
  non_default_mask = array[feature] != default_value
116
153
 
@@ -120,9 +157,12 @@ def normalize(in_array,
120
157
  else:
121
158
  # check whether a normalization function is defined for the feature
122
159
  if feature not in norm_funcs:
123
- array[feature][non_default_mask] = norm_func_fallback(array[feature][non_default_mask])
160
+ array[feature][non_default_mask] = norm_func_fallback(
161
+ array[feature][non_default_mask]
162
+ )
124
163
  else:
125
- array[feature][non_default_mask] = norm_funcs[feature]["func"](array[feature][non_default_mask],
126
- **norm_funcs[feature]["kwargs"])
127
-
164
+ array[feature][non_default_mask] = norm_funcs[feature]["func"](
165
+ array[feature][non_default_mask], **norm_funcs[feature]["kwargs"]
166
+ )
167
+
128
168
  return array
partitura/utils/synth.py CHANGED
@@ -320,7 +320,6 @@ class DistributedHarmonics(object):
320
320
  n_harmonics: int,
321
321
  weights: Union[np.ndarray, str] = "equal",
322
322
  ) -> None:
323
-
324
323
  self.n_harmonics = n_harmonics
325
324
  self.weights = weights
326
325
 
@@ -330,7 +329,6 @@ class DistributedHarmonics(object):
330
329
  self._overtones = np.arange(1, self.n_harmonics + 2)
331
330
 
332
331
  def __call__(self, freq: float) -> Tuple[np.ndarray]:
333
-
334
332
  return self._overtones * freq, self.weights
335
333
 
336
334
 
@@ -344,7 +342,6 @@ class ShepardTones(object):
344
342
  min_freq: Union[float, int] = 77.8,
345
343
  max_freq: Union[float, int] = 2349,
346
344
  ) -> None:
347
-
348
345
  self.min_freq = min_freq
349
346
  self.max_freq = max_freq
350
347
 
@@ -361,7 +358,6 @@ class ShepardTones(object):
361
358
  )
362
359
 
363
360
  def __call__(self, freq) -> Tuple[np.ndarray]:
364
-
365
361
  min_freq = self.min_f(freq)
366
362
 
367
363
  freqs = 2 ** np.arange(5) * min_freq
@@ -485,15 +481,13 @@ def synthesize(
485
481
  return x, 1
486
482
 
487
483
  elif isinstance(harmonic_dist, int):
488
-
489
484
  harmonic_dist = DistributedHarmonics(harmonic_dist)
490
485
 
491
486
  elif isinstance(harmonic_dist, str):
492
487
  if harmonic_dist in ("shepard",):
493
488
  harmonic_dist = ShepardTones()
494
489
 
495
- for (f, oif, dur) in zip(freq_in_hz, onsets_in_frames, duration):
496
-
490
+ for f, oif, dur in zip(freq_in_hz, onsets_in_frames, duration):
497
491
  freqs, weights = harmonic_dist(f)
498
492
 
499
493
  note = additive_synthesis(
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: partitura
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: A package for handling symbolic musical information
5
5
  Home-page: https://github.com/CPJKU/partitura
6
- Author: Maarten Grachten, Carlos Cancino-Chacón, Silvan Peter, Emmanouil Karystinaios, Francesco Foscarin, Thassilo Gadermaier
6
+ Author: Maarten Grachten, Carlos Cancino-Chacón, Silvan Peter, Emmanouil Karystinaios, Francesco Foscarin, Thassilo Gadermaier, Patricia Hu
7
7
  Author-email: partitura-users@googlegroups.com
8
8
  License: Apache 2.0
9
9
  Keywords: music notation musicxml midi
@@ -0,0 +1,51 @@
1
+ partitura/__init__.py,sha256=pwZEYD4DiL5_xm7rioL1UsHkeMUYE9gu-063KGvkcZM,2194
2
+ partitura/directions.py,sha256=F5Au1u6DB0vzxscNZF5pqva73gHQzSLQ2syahyrByeY,14163
3
+ partitura/display.py,sha256=QPfdbvKvivfsCRSjZnWztMwRryefVn_vjuQO2BCRRxM,5599
4
+ partitura/performance.py,sha256=7tXXfuSbc7GPRbyg5VES-NtSrMiOFVcR3g3tO8c8n5U,21230
5
+ partitura/score.py,sha256=2jzdwOZG93S6_L7kCe6MRNO9W6Xe6vNm9aZlj68SSw8,156031
6
+ partitura/assets/musicxml.xsd,sha256=Sa6eNOBLpbcgBGh5lPcNWYMj6zNT6tti-u3Mnp3EvX8,335762
7
+ partitura/assets/score_example.krn,sha256=-sdx5JEZrkOyP26bmXG6XdPdgNYwHedXvM-rch5C_6Y,104
8
+ partitura/assets/score_example.mei,sha256=YMmQ07gztEAlkeXayTY53SSzoXVPLwoY-n4M3zpUgUY,2436
9
+ partitura/assets/score_example.mid,sha256=X-c10L0ore-dQu6fH67XV5LoFuSJERI_6vC0bl6JD-0,56
10
+ partitura/assets/score_example.musicxml,sha256=EUGM9PJzoazJLnaIqAWFFWThd7NmrZnabhkX6BSG3t8,1589
11
+ partitura/io/__init__.py,sha256=GWDIEmgVKYLxPaaWzEWppHHvV-VmbONab8Xz6PWaoPA,6364
12
+ partitura/io/exportaudio.py,sha256=3YzLFT0bKOdxLZnMwzMlp9_b9PFWBNKmiuLn5gNcLvs,3985
13
+ partitura/io/exportmatch.py,sha256=Wxnw54wcnN-zwPvXH7ThP7D0MLXAiHJ_NK59fwXMrlw,20946
14
+ partitura/io/exportmei.py,sha256=51kzU5WB41j-d2HSbNcMS6zTl4fgS-rF0bj-IOysmLQ,71850
15
+ partitura/io/exportmidi.py,sha256=tftlWDqFfgVYZ8j9FnOblVicFOv0zdO5sMlcZGcfILw,19725
16
+ partitura/io/exportmusicxml.py,sha256=d3atEddXecKUtPtdaINZMpGnu5RoNSbSrFG3J8RHEKg,35318
17
+ partitura/io/exportparangonada.py,sha256=AFZeYWRPFkoMoF4eMRDyZavC7v3H4Crs9bCkow2QO9s,9056
18
+ partitura/io/importkern.py,sha256=vwbh9Y9RlDAD5OzZywNmRQKJhtIkek8_wHfXHUB43ao,22394
19
+ partitura/io/importmatch.py,sha256=90spvpvUEcF3M-7vt42IwHwkpkTobyXfDS8TeUg33ZM,29868
20
+ partitura/io/importmei.py,sha256=wkfCmJYAZSUy-uSh1mxmvs3iTtOH5aeQxb0Cf5Rn7r8,47584
21
+ partitura/io/importmidi.py,sha256=Y75pfCQ_ZNrluNajhOhtS40geiNkA9RhxLc9NvxiNuY,27235
22
+ partitura/io/importmusic21.py,sha256=SZEnKukfHohys3vzVzRVJj88NWok9OTJ_a89gcQSmRY,8201
23
+ partitura/io/importmusicxml.py,sha256=T_CnwnIXmtwCgOXdN6gGu4fM8Tz2u1Z33lfbqZC2NJc,57658
24
+ partitura/io/importnakamura.py,sha256=jEBOLRhGXFcsfFVfxm7cerF0ap_jCt9PmcDp0VHNFYc,8432
25
+ partitura/io/importparangonada.py,sha256=9VKkwvBB66rwbiv_8URItFuvQ5X9N0ybpL0eHYdAMeg,5927
26
+ partitura/io/matchfile_base.py,sha256=mkHwL9IxJ3JhU86ob2yi1FyNKxEeXxhInLi0gTCA7sg,31670
27
+ partitura/io/matchfile_utils.py,sha256=ug-c9J_xP-_gvDufBPSw9PAjTFEmqE56Vr89zdcT6dE,26601
28
+ partitura/io/matchlines_v0.py,sha256=TVJN0YUevmSpANNjBdaoGtN-c3IrhTCcGk7WAuoOdTA,29228
29
+ partitura/io/matchlines_v1.py,sha256=kHxaeOQTs87yZyNTHRth5Z9BEug0-o2YUpF9pPr9P54,40486
30
+ partitura/io/musescore.py,sha256=kaWpRnNIxSSyfHanQa6c6CxKSDYNfWhLUbhETzLJzyU,8853
31
+ partitura/musicanalysis/__init__.py,sha256=XQDeUrjitlzybIP1l8CU6vOLqNm7C7B7vhe0pySwuVY,1236
32
+ partitura/musicanalysis/key_identification.py,sha256=Kl4hx_AkuRQuBGvNlpGAE3MqpznmWLGFo68Yx3rqSss,6991
33
+ partitura/musicanalysis/meter.py,sha256=ORynu2foZmmedj1je-em1xCvzPfIj9RqnZBFWnnwe5k,11189
34
+ partitura/musicanalysis/note_array_to_score.py,sha256=sCFxJS98t8mpL4hNHCcvArduqm6isNnQ_Zhfw7RLwVQ,21781
35
+ partitura/musicanalysis/note_features.py,sha256=XUOC1jUgddyTyxP5yVCLcygtY44e1tJzFcafmKdsMu0,37809
36
+ partitura/musicanalysis/performance_codec.py,sha256=wkf_lPLfGkWKKU-rEsWSqHj-AJAuSURRJDWawnthnXA,34663
37
+ partitura/musicanalysis/performance_features.py,sha256=beRKADPJefzQ2rZxM_31s_bwmlr5MTX__cvqNbOcZsc,17909
38
+ partitura/musicanalysis/pitch_spelling.py,sha256=u3-r_1oTOz87aEDtEkS_jVbtzrJmAo1quPqgZfmsiAk,8928
39
+ partitura/musicanalysis/tonal_tension.py,sha256=0e_w6E4zp3Un_ctrUc5GeLti0qZHupywzh9e2w7o3Fs,17350
40
+ partitura/musicanalysis/voice_separation.py,sha256=Uxy04j-Tar_hVFUY9gIcEG9qr7o-ya8ZSauuX6q_G5A,35740
41
+ partitura/utils/__init__.py,sha256=WebirkSldT9htYdiUwemm5Vt9uXRsaYGSDRWUm4NeTI,1973
42
+ partitura/utils/generic.py,sha256=T-gtDIF_qxcUgq9BUhHmsIiYLYSyyAs6Qu25DZ1EL3c,19050
43
+ partitura/utils/misc.py,sha256=CQrIfETS-__2ZGz0eV2BDZtd9FbUHgevQT1PSRL9VvU,7064
44
+ partitura/utils/music.py,sha256=TJkF6L7_gQbxLIjFWwvtcdCi6kPWsmdbZyhI5_C6LMM,111276
45
+ partitura/utils/normalize.py,sha256=18OvJBiYOQoefedgxpX8TEwxEqoO7hQ31XXx3JjfYps,4667
46
+ partitura/utils/synth.py,sha256=9xg6sVRmz7KWGlNTWFp3bo-7bT1wRwNRdi-ODr8H4PI,15568
47
+ partitura-1.4.0.dist-info/LICENSE,sha256=mfxqxedyDV9qko2GrppTJVlVnpK7qkUE5sPUkGK_a9I,11429
48
+ partitura-1.4.0.dist-info/METADATA,sha256=lQDI6LrW9bLmKh5Kk9r5CP6MCbdNNprGs98KHLpYaO4,9423
49
+ partitura-1.4.0.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
50
+ partitura-1.4.0.dist-info/top_level.txt,sha256=oUqKOhAhzAD7e9Al23ZKsGssQFCu9FpYj_DHGC15euU,10
51
+ partitura-1.4.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.40.0)
2
+ Generator: bdist_wheel (0.41.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5