projectlosangeles commited on
Commit
8681dc6
·
verified ·
1 Parent(s): dc9910b

Upload TMIDIX.py

Browse files
Files changed (1) hide show
  1. TMIDIX.py +1442 -19
TMIDIX.py CHANGED
@@ -51,7 +51,7 @@ r'''############################################################################
51
 
52
  ###################################################################################
53
 
54
- __version__ = "25.7.8"
55
 
56
  print('=' * 70)
57
  print('TMIDIX Python module')
@@ -1485,10 +1485,13 @@ import multiprocessing
1485
 
1486
  from itertools import zip_longest
1487
  from itertools import groupby
 
 
1488
 
1489
  from collections import Counter
1490
  from collections import defaultdict
1491
  from collections import OrderedDict
 
1492
 
1493
  from operator import itemgetter
1494
 
@@ -1498,6 +1501,9 @@ from difflib import SequenceMatcher as SM
1498
 
1499
  import statistics
1500
  import math
 
 
 
1501
 
1502
  import matplotlib.pyplot as plt
1503
 
@@ -3903,7 +3909,8 @@ def chordify_score(score,
3903
 
3904
  def fix_monophonic_score_durations(monophonic_score,
3905
  min_notes_gap=1,
3906
- min_notes_dur=1
 
3907
  ):
3908
 
3909
  fixed_score = []
@@ -3918,7 +3925,11 @@ def fix_monophonic_score_durations(monophonic_score,
3918
  if note[1]+note[2] >= nmt:
3919
  note_dur = max(1, nmt-note[1]-min_notes_gap)
3920
  else:
3921
- note_dur = note[2]
 
 
 
 
3922
 
3923
  new_note = [note[0], note[1], note_dur] + note[3:]
3924
 
@@ -3936,9 +3947,13 @@ def fix_monophonic_score_durations(monophonic_score,
3936
  nmt = monophonic_score[i+1][0]
3937
 
3938
  if note[0]+note[1] >= nmt:
3939
- note_dur = max(1, nmt-note[0]-min_notes_gap)
3940
  else:
3941
- note_dur = note[1]
 
 
 
 
3942
 
3943
  new_note = [note[0], note_dur] + note[2:]
3944
 
@@ -3952,8 +3967,6 @@ def fix_monophonic_score_durations(monophonic_score,
3952
 
3953
  ###################################################################################
3954
 
3955
- from itertools import product
3956
-
3957
  ALL_CHORDS = [[0], [7], [5], [9], [2], [4], [11], [10], [8], [6], [3], [1], [0, 9], [2, 5],
3958
  [4, 7], [7, 10], [2, 11], [0, 3], [6, 9], [1, 4], [8, 11], [5, 8], [1, 10],
3959
  [3, 6], [0, 4], [5, 9], [7, 11], [0, 7], [0, 5], [2, 10], [2, 7], [2, 9],
@@ -7128,7 +7141,8 @@ def escore_notes_to_binary_matrix(escore_notes,
7128
  channel=0,
7129
  patch=0,
7130
  flip_matrix=False,
7131
- reverse_matrix=False
 
7132
  ):
7133
 
7134
  escore = [e for e in escore_notes if e[3] == channel and e[6] == patch]
@@ -7152,14 +7166,17 @@ def escore_notes_to_binary_matrix(escore_notes,
7152
  duration = max(1, duration)
7153
  chan = max(0, min(15, chan))
7154
  pitch = max(0, min(127, pitch))
7155
- velocity = max(0, min(127, velocity))
7156
  pat = max(0, min(128, pat))
7157
 
7158
  if channel == chan and patch == pat:
7159
 
7160
  for t in range(time, min(time + duration, time_range)):
7161
-
7162
- escore_matrix[t][pitch] = 1
 
 
 
7163
 
7164
  if flip_matrix:
7165
 
@@ -7183,7 +7200,8 @@ def escore_notes_to_binary_matrix(escore_notes,
7183
  def binary_matrix_to_original_escore_notes(binary_matrix,
7184
  channel=0,
7185
  patch=0,
7186
- velocity=-1
 
7187
  ):
7188
 
7189
  result = []
@@ -7222,8 +7240,11 @@ def binary_matrix_to_original_escore_notes(binary_matrix,
7222
 
7223
  for r in result:
7224
 
7225
- if velocity == -1:
7226
- vel = max(40, r[2])
 
 
 
7227
 
7228
  original_escore_notes.append(['note', r[0], r[1], channel, r[2], vel, patch])
7229
 
@@ -8048,7 +8069,7 @@ def solo_piano_escore_notes(escore_notes,
8048
  keep_drums=False,
8049
  ):
8050
 
8051
- cscore = chordify_score([1000, escore_notes])
8052
 
8053
  sp_escore_notes = []
8054
 
@@ -9720,7 +9741,14 @@ def escore_notes_to_text_description(escore_notes,
9720
  song_name='',
9721
  artist_name='',
9722
  timings_divider=16,
 
 
9723
  ):
 
 
 
 
 
9724
 
9725
  #==============================================================================
9726
 
@@ -9734,6 +9762,9 @@ def escore_notes_to_text_description(escore_notes,
9734
 
9735
  elif song_time_min >= 2.5:
9736
  song_length = 'long'
 
 
 
9737
 
9738
  #==============================================================================
9739
 
@@ -9745,18 +9776,25 @@ def escore_notes_to_text_description(escore_notes,
9745
  if len(escore_times) == len(set(escore_times)):
9746
  comp_type = 'monophonic melody'
9747
  ctype = 'melody'
 
9748
 
9749
  elif len(escore_times) >= len(set(escore_times)) and 1 in Counter(escore_times).values():
9750
  comp_type = 'melody and accompaniment'
9751
  ctype = 'song'
 
9752
 
9753
  elif len(escore_times) >= len(set(escore_times)) and 1 not in Counter(escore_times).values():
9754
  comp_type = 'accompaniment'
9755
  ctype = 'song'
 
9756
 
9757
  else:
9758
  comp_type = 'drum track'
9759
  ctype = 'drum track'
 
 
 
 
9760
 
9761
  #==============================================================================
9762
 
@@ -9771,6 +9809,13 @@ def escore_notes_to_text_description(escore_notes,
9771
  nd_patches_counts = Counter([p for p in all_patches if p < 128]).most_common()
9772
 
9773
  dominant_instrument = alpha_str(Number2patch[nd_patches_counts[0][0]])
 
 
 
 
 
 
 
9774
 
9775
  if 128 in patches:
9776
  drums_present = True
@@ -9778,9 +9823,16 @@ def escore_notes_to_text_description(escore_notes,
9778
  drums_pitches = [e[4] for e in escore_notes if e[3] == 9]
9779
 
9780
  most_common_drums = [alpha_str(Notenum2percussion[p[0]]) for p in Counter(drums_pitches).most_common(3) if p[0] in Notenum2percussion]
 
 
 
9781
 
9782
  else:
9783
  drums_present = False
 
 
 
 
9784
 
9785
  #==============================================================================
9786
 
@@ -9790,60 +9842,111 @@ def escore_notes_to_text_description(escore_notes,
9790
 
9791
  if pitches:
9792
  key = SEMITONES[statistics.mode(pitches) % 12]
 
 
 
 
 
 
 
9793
 
9794
  #==============================================================================
9795
 
9796
  scale = ''
9797
  mood = ''
9798
 
 
 
 
 
 
9799
  if pitches:
9800
 
9801
  result = escore_notes_scale(escore_notes)
9802
 
9803
  scale = result[0]
9804
  mood = result[1].split(' ')[0].lower()
 
 
 
 
 
 
 
9805
 
9806
  #==============================================================================
9807
-
 
 
 
 
 
 
 
 
 
 
9808
  if pitches:
9809
 
9810
  escore_averages = escore_notes_averages(escore_notes, return_ptcs_and_vels=True)
9811
 
9812
  if escore_averages[0] < (128 / timings_divider):
9813
  rythm = 'fast'
 
9814
 
9815
  elif (128 / timings_divider) <= escore_averages[0] <= (192 / timings_divider):
9816
  rythm = 'average'
 
9817
 
9818
  elif escore_averages[0] > (192 / timings_divider):
9819
  rythm = 'slow'
 
9820
 
9821
  if escore_averages[1] < (256 / timings_divider):
9822
  tempo = 'fast'
 
9823
 
9824
  elif (256 / timings_divider) <= escore_averages[1] <= (384 / timings_divider):
9825
  tempo = 'average'
 
9826
 
9827
  elif escore_averages[1] > (384 / timings_divider):
9828
  tempo = 'slow'
 
9829
 
9830
  if escore_averages[2] < 50:
9831
  tone = 'bass'
 
9832
 
9833
  elif 50 <= escore_averages[2] <= 70:
9834
  tone = 'midrange'
 
9835
 
9836
  elif escore_averages[2] > 70:
9837
  tone = 'treble'
 
9838
 
9839
  if escore_averages[3] < 64:
9840
  dynamics = 'quiet'
 
9841
 
9842
  elif 64 <= escore_averages[3] <= 96:
9843
  dynamics = 'average'
 
9844
 
9845
  elif escore_averages[3] > 96:
9846
  dynamics = 'loud'
 
 
 
 
 
 
 
 
 
 
 
9847
 
9848
  #==============================================================================
9849
 
@@ -9851,6 +9954,12 @@ def escore_notes_to_text_description(escore_notes,
9851
 
9852
  lead_melodies = []
9853
  base_melodies = []
 
 
 
 
 
 
9854
 
9855
  if mono_melodies:
9856
 
@@ -9860,15 +9969,19 @@ def escore_notes_to_text_description(escore_notes,
9860
 
9861
  if mel[0] in LEAD_INSTRUMENTS and escore_avgs[3] > 60:
9862
  lead_melodies.append([Number2patch[mel[0]], mel[1]])
 
9863
 
9864
  elif mel[0] in BASE_INSTRUMENTS and escore_avgs[3] <= 60:
9865
  base_melodies.append([Number2patch[mel[0]], mel[1]])
 
9866
 
9867
  if lead_melodies:
9868
  lead_melodies.sort(key=lambda x: x[1], reverse=True)
 
9869
 
9870
  if base_melodies:
9871
  base_melodies.sort(key=lambda x: x[1], reverse=True)
 
9872
 
9873
  #==============================================================================
9874
 
@@ -10055,8 +10168,20 @@ def escore_notes_to_text_description(escore_notes,
10055
  description += '\n'
10056
 
10057
  #==============================================================================
10058
-
10059
- return description
 
 
 
 
 
 
 
 
 
 
 
 
10060
 
10061
  ###################################################################################
10062
 
@@ -11288,7 +11413,7 @@ def multiprocessing_wrapper(function, data_list, verbose=True):
11288
 
11289
  results = []
11290
 
11291
- for result in tqdm.tqdm(pool.imap_unordered(function, data_list),
11292
  total=len(data_list),
11293
  disable=not verbose
11294
  ):
@@ -13604,6 +13729,1304 @@ PERCUSSION_GROUPS = {
13604
 
13605
  ###################################################################################
13606
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13607
  print('Module loaded!')
13608
  print('=' * 70)
13609
  print('Enjoy! :)')
 
51
 
52
  ###################################################################################
53
 
54
+ __version__ = "25.9.22"
55
 
56
  print('=' * 70)
57
  print('TMIDIX Python module')
 
1485
 
1486
  from itertools import zip_longest
1487
  from itertools import groupby
1488
+ from itertools import cycle
1489
+ from itertools import product
1490
 
1491
  from collections import Counter
1492
  from collections import defaultdict
1493
  from collections import OrderedDict
1494
+ from collections import deque
1495
 
1496
  from operator import itemgetter
1497
 
 
1501
 
1502
  import statistics
1503
  import math
1504
+ from math import gcd
1505
+
1506
+ from functools import reduce
1507
 
1508
  import matplotlib.pyplot as plt
1509
 
 
3909
 
3910
  def fix_monophonic_score_durations(monophonic_score,
3911
  min_notes_gap=1,
3912
+ min_notes_dur=1,
3913
+ extend_durs=False
3914
  ):
3915
 
3916
  fixed_score = []
 
3925
  if note[1]+note[2] >= nmt:
3926
  note_dur = max(1, nmt-note[1]-min_notes_gap)
3927
  else:
3928
+ if extend_durs:
3929
+ note_dur = max(1, nmt-note[1]-min_notes_gap)
3930
+
3931
+ else:
3932
+ note_dur = note[2]
3933
 
3934
  new_note = [note[0], note[1], note_dur] + note[3:]
3935
 
 
3947
  nmt = monophonic_score[i+1][0]
3948
 
3949
  if note[0]+note[1] >= nmt:
3950
+ note_dur = max(1, nmt-note[0]-min_notes_gap)
3951
  else:
3952
+ if extend_durs:
3953
+ note_dur = max(1, nmt-note[0]-min_notes_gap)
3954
+
3955
+ else:
3956
+ note_dur = note[1]
3957
 
3958
  new_note = [note[0], note_dur] + note[2:]
3959
 
 
3967
 
3968
  ###################################################################################
3969
 
 
 
3970
  ALL_CHORDS = [[0], [7], [5], [9], [2], [4], [11], [10], [8], [6], [3], [1], [0, 9], [2, 5],
3971
  [4, 7], [7, 10], [2, 11], [0, 3], [6, 9], [1, 4], [8, 11], [5, 8], [1, 10],
3972
  [3, 6], [0, 4], [5, 9], [7, 11], [0, 7], [0, 5], [2, 10], [2, 7], [2, 9],
 
7141
  channel=0,
7142
  patch=0,
7143
  flip_matrix=False,
7144
+ reverse_matrix=False,
7145
+ encode_velocities=False
7146
  ):
7147
 
7148
  escore = [e for e in escore_notes if e[3] == channel and e[6] == patch]
 
7166
  duration = max(1, duration)
7167
  chan = max(0, min(15, chan))
7168
  pitch = max(0, min(127, pitch))
7169
+ velocity = max(1, min(127, velocity))
7170
  pat = max(0, min(128, pat))
7171
 
7172
  if channel == chan and patch == pat:
7173
 
7174
  for t in range(time, min(time + duration, time_range)):
7175
+ if encode_velocities:
7176
+ escore_matrix[t][pitch] = velocity
7177
+
7178
+ else:
7179
+ escore_matrix[t][pitch] = 1
7180
 
7181
  if flip_matrix:
7182
 
 
7200
  def binary_matrix_to_original_escore_notes(binary_matrix,
7201
  channel=0,
7202
  patch=0,
7203
+ velocity=-1,
7204
+ decode_velocities=False
7205
  ):
7206
 
7207
  result = []
 
7240
 
7241
  for r in result:
7242
 
7243
+ if velocity == -1 and not decode_velocities:
7244
+ vel = max(40, r[2])
7245
+
7246
+ if decode_velocities:
7247
+ vel = r[3]
7248
 
7249
  original_escore_notes.append(['note', r[0], r[1], channel, r[2], vel, patch])
7250
 
 
8069
  keep_drums=False,
8070
  ):
8071
 
8072
+ cscore = chordify_score([1000, copy.deepcopy(escore_notes)])
8073
 
8074
  sp_escore_notes = []
8075
 
 
9741
  song_name='',
9742
  artist_name='',
9743
  timings_divider=16,
9744
+ return_feat_dict=False,
9745
+ return_feat_dict_vals=False
9746
  ):
9747
+
9748
+ #==============================================================================
9749
+
9750
+ feat_dict = {}
9751
+ feat_dict_vals = {}
9752
 
9753
  #==============================================================================
9754
 
 
9762
 
9763
  elif song_time_min >= 2.5:
9764
  song_length = 'long'
9765
+
9766
+ feat_dict['song_len'] = song_length.capitalize()
9767
+ feat_dict_vals['song_len'] = song_time_min
9768
 
9769
  #==============================================================================
9770
 
 
9776
  if len(escore_times) == len(set(escore_times)):
9777
  comp_type = 'monophonic melody'
9778
  ctype = 'melody'
9779
+ ctv = 0
9780
 
9781
  elif len(escore_times) >= len(set(escore_times)) and 1 in Counter(escore_times).values():
9782
  comp_type = 'melody and accompaniment'
9783
  ctype = 'song'
9784
+ ctv = 1
9785
 
9786
  elif len(escore_times) >= len(set(escore_times)) and 1 not in Counter(escore_times).values():
9787
  comp_type = 'accompaniment'
9788
  ctype = 'song'
9789
+ ctv = 2
9790
 
9791
  else:
9792
  comp_type = 'drum track'
9793
  ctype = 'drum track'
9794
+ ctv = 3
9795
+
9796
+ feat_dict['song_type'] = comp_type.capitalize()
9797
+ feat_dict_vals['song_type'] = ctv
9798
 
9799
  #==============================================================================
9800
 
 
9809
  nd_patches_counts = Counter([p for p in all_patches if p < 128]).most_common()
9810
 
9811
  dominant_instrument = alpha_str(Number2patch[nd_patches_counts[0][0]])
9812
+
9813
+ feat_dict['most_com_instr'] = instruments
9814
+ feat_dict_vals['most_com_instr'] = [p for p in patches if p < 128]
9815
+
9816
+ else:
9817
+ feat_dict['most_com_instr'] = None
9818
+ feat_dict_vals['most_com_instr'] = []
9819
 
9820
  if 128 in patches:
9821
  drums_present = True
 
9823
  drums_pitches = [e[4] for e in escore_notes if e[3] == 9]
9824
 
9825
  most_common_drums = [alpha_str(Notenum2percussion[p[0]]) for p in Counter(drums_pitches).most_common(3) if p[0] in Notenum2percussion]
9826
+
9827
+ feat_dict['most_com_drums'] = most_common_drums
9828
+ feat_dict_vals['most_com_drums'] = [p[0] for p in Counter(drums_pitches).most_common(3)]
9829
 
9830
  else:
9831
  drums_present = False
9832
+
9833
+ feat_dict['most_com_drums'] = None
9834
+
9835
+ feat_dict_vals['most_com_drums'] = []
9836
 
9837
  #==============================================================================
9838
 
 
9842
 
9843
  if pitches:
9844
  key = SEMITONES[statistics.mode(pitches) % 12]
9845
+
9846
+ feat_dict['key'] = key.title()
9847
+ feat_dict_vals['key'] = statistics.mode(pitches) % 12
9848
+
9849
+ else:
9850
+ feat_dict['key'] = None
9851
+ feat_dict_vals['key'] = -1
9852
 
9853
  #==============================================================================
9854
 
9855
  scale = ''
9856
  mood = ''
9857
 
9858
+ feat_dict['scale'] = None
9859
+ feat_dict['mood'] = None
9860
+ feat_dict_vals['scale'] = -1
9861
+ feat_dict_vals['mood'] = -1
9862
+
9863
  if pitches:
9864
 
9865
  result = escore_notes_scale(escore_notes)
9866
 
9867
  scale = result[0]
9868
  mood = result[1].split(' ')[0].lower()
9869
+
9870
+ feat_dict['scale'] = scale.title()
9871
+ feat_dict['mood'] = mood.title()
9872
+
9873
+ res = escore_notes_scale(escore_notes, return_scale_indexes=True)
9874
+ feat_dict_vals['scale'] = res[0]
9875
+ feat_dict_vals['mood'] = res[1]
9876
 
9877
  #==============================================================================
9878
+
9879
+ feat_dict['rythm'] = None
9880
+ feat_dict['tempo'] = None
9881
+ feat_dict['tone'] = None
9882
+ feat_dict['dynamics'] = None
9883
+
9884
+ feat_dict_vals['rythm'] = -1
9885
+ feat_dict_vals['tempo'] = -1
9886
+ feat_dict_vals['tone'] = -1
9887
+ feat_dict_vals['dynamics'] = -1
9888
+
9889
  if pitches:
9890
 
9891
  escore_averages = escore_notes_averages(escore_notes, return_ptcs_and_vels=True)
9892
 
9893
  if escore_averages[0] < (128 / timings_divider):
9894
  rythm = 'fast'
9895
+ ryv = 0
9896
 
9897
  elif (128 / timings_divider) <= escore_averages[0] <= (192 / timings_divider):
9898
  rythm = 'average'
9899
+ ryv = 1
9900
 
9901
  elif escore_averages[0] > (192 / timings_divider):
9902
  rythm = 'slow'
9903
+ ryv = 2
9904
 
9905
  if escore_averages[1] < (256 / timings_divider):
9906
  tempo = 'fast'
9907
+ tev = 0
9908
 
9909
  elif (256 / timings_divider) <= escore_averages[1] <= (384 / timings_divider):
9910
  tempo = 'average'
9911
+ tev = 1
9912
 
9913
  elif escore_averages[1] > (384 / timings_divider):
9914
  tempo = 'slow'
9915
+ tev = 2
9916
 
9917
  if escore_averages[2] < 50:
9918
  tone = 'bass'
9919
+ tov = 0
9920
 
9921
  elif 50 <= escore_averages[2] <= 70:
9922
  tone = 'midrange'
9923
+ tov = 1
9924
 
9925
  elif escore_averages[2] > 70:
9926
  tone = 'treble'
9927
+ tov = 2
9928
 
9929
  if escore_averages[3] < 64:
9930
  dynamics = 'quiet'
9931
+ dyn = 0
9932
 
9933
  elif 64 <= escore_averages[3] <= 96:
9934
  dynamics = 'average'
9935
+ dyn = 1
9936
 
9937
  elif escore_averages[3] > 96:
9938
  dynamics = 'loud'
9939
+ dyn = 2
9940
+
9941
+ feat_dict['rythm'] = rythm.title()
9942
+ feat_dict['tempo'] = tempo.title()
9943
+ feat_dict['tone'] = tone.title()
9944
+ feat_dict['dynamics'] = dynamics.title()
9945
+
9946
+ feat_dict_vals['rythm'] = ryv
9947
+ feat_dict_vals['tempo'] = tev
9948
+ feat_dict_vals['tone'] = tov
9949
+ feat_dict_vals['dynamics'] = dyn
9950
 
9951
  #==============================================================================
9952
 
 
9954
 
9955
  lead_melodies = []
9956
  base_melodies = []
9957
+
9958
+ feat_dict['lead_mono_mels'] = None
9959
+ feat_dict['base_mono_mels'] = None
9960
+
9961
+ feat_dict_vals['lead_mono_mels'] = []
9962
+ feat_dict_vals['base_mono_mels'] = []
9963
 
9964
  if mono_melodies:
9965
 
 
9969
 
9970
  if mel[0] in LEAD_INSTRUMENTS and escore_avgs[3] > 60:
9971
  lead_melodies.append([Number2patch[mel[0]], mel[1]])
9972
+ feat_dict_vals['lead_mono_mels'].append(mel[0])
9973
 
9974
  elif mel[0] in BASE_INSTRUMENTS and escore_avgs[3] <= 60:
9975
  base_melodies.append([Number2patch[mel[0]], mel[1]])
9976
+ feat_dict_vals['base_mono_mels'].append(mel[0])
9977
 
9978
  if lead_melodies:
9979
  lead_melodies.sort(key=lambda x: x[1], reverse=True)
9980
+ feat_dict['lead_mono_mels'] = lead_melodies
9981
 
9982
  if base_melodies:
9983
  base_melodies.sort(key=lambda x: x[1], reverse=True)
9984
+ feat_dict['base_mono_mels'] = base_melodies
9985
 
9986
  #==============================================================================
9987
 
 
10168
  description += '\n'
10169
 
10170
  #==============================================================================
10171
+
10172
+ final_feat_dict = []
10173
+
10174
+ if return_feat_dict:
10175
+ final_feat_dict.append(feat_dict)
10176
+
10177
+ if return_feat_dict_vals:
10178
+ final_feat_dict.append(feat_dict_vals)
10179
+
10180
+ if return_feat_dict or return_feat_dict_vals:
10181
+ return final_feat_dict
10182
+
10183
+ else:
10184
+ return description
10185
 
10186
  ###################################################################################
10187
 
 
11413
 
11414
  results = []
11415
 
11416
+ for result in tqdm.tqdm(pool.imap(function, data_list),
11417
  total=len(data_list),
11418
  disable=not verbose
11419
  ):
 
13729
 
13730
  ###################################################################################
13731
 
13732
+ def escore_notes_to_expanded_binary_matrix(escore_notes,
13733
+ channel=0,
13734
+ patch=0,
13735
+ flip_matrix=False,
13736
+ reverse_matrix=False,
13737
+ encode_velocities=True
13738
+ ):
13739
+
13740
+ escore = [e for e in escore_notes if e[3] == channel and e[6] == patch]
13741
+
13742
+ if escore:
13743
+ last_time = escore[-1][1]
13744
+ last_notes = [e for e in escore if e[1] == last_time]
13745
+ max_last_dur = max([e[2] for e in last_notes])
13746
+
13747
+ time_range = last_time+max_last_dur
13748
+
13749
+ escore_matrix = []
13750
+
13751
+ escore_matrix = [[(0, 0)] * 128 for _ in range(time_range)]
13752
+
13753
+ for note in escore:
13754
+
13755
+ etype, time, duration, chan, pitch, velocity, pat = note
13756
+
13757
+ time = max(0, time)
13758
+ duration = max(1, duration)
13759
+ chan = max(0, min(15, chan))
13760
+ pitch = max(0, min(127, pitch))
13761
+ velocity = max(1, min(127, velocity))
13762
+ pat = max(0, min(128, pat))
13763
+
13764
+ if channel == chan and patch == pat:
13765
+
13766
+ count = 0
13767
+
13768
+ for t in range(time, min(time + duration, time_range)):
13769
+ if encode_velocities:
13770
+ escore_matrix[t][pitch] = velocity, count
13771
+
13772
+ else:
13773
+ escore_matrix[t][pitch] = 1, count
13774
+ count += 1
13775
+
13776
+ if flip_matrix:
13777
+
13778
+ temp_matrix = []
13779
+
13780
+ for m in escore_matrix:
13781
+ temp_matrix.append(m[::-1])
13782
+
13783
+ escore_matrix = temp_matrix
13784
+
13785
+ if reverse_matrix:
13786
+ escore_matrix = escore_matrix[::-1]
13787
+
13788
+ return escore_matrix
13789
+
13790
+ else:
13791
+ return None
13792
+
13793
+ ###################################################################################
13794
+
13795
+ def transpose_list(lst):
13796
+ return [list(row) for row in zip(*lst)]
13797
+
13798
+ ###################################################################################
13799
+
13800
+ def chunk_list(lst, size):
13801
+ return [lst[i:i + size] for i in range(0, len(lst), size)]
13802
+
13803
+ ###################################################################################
13804
+
13805
+ def flip_list_rows(lst):
13806
+ return [row[::-1] for row in lst]
13807
+
13808
+ ###################################################################################
13809
+
13810
+ def flip_list_columns(lst):
13811
+ return lst[::-1]
13812
+
13813
+ ###################################################################################
13814
+
13815
+ def exists(sub, lst):
13816
+ sub_len = len(sub)
13817
+ return any(lst[i:i + sub_len] == sub for i in range(len(lst) - sub_len + 1))
13818
+
13819
+ ###################################################################################
13820
+
13821
+ def exists_noncontig(sub, lst):
13822
+ it = iter(lst)
13823
+ return all(x in it for x in sub)
13824
+
13825
+ ###################################################################################
13826
+
13827
+ def exists_ratio(sub, lst, ratio):
13828
+ matches = sum(x in set(lst) for x in sub)
13829
+ return matches / len(sub) >= ratio
13830
+
13831
+ ###################################################################################
13832
+
13833
+ def top_k_list_value(lst, k, reverse=True):
13834
+ return sorted(lst, reverse=reverse)[k]
13835
+
13836
+ ###################################################################################
13837
+
13838
+ def top_k_list_values(lst, k, reverse=True):
13839
+ return sorted(lst, reverse=reverse)[:k]
13840
+
13841
+ ###################################################################################
13842
+
13843
+ def concat_rows(lst_A, lst_B):
13844
+ return [a + b for a, b in zip(lst_A, lst_B)]
13845
+
13846
+ ###################################################################################
13847
+
13848
+ def concat_cols(lst_A, lst_B):
13849
+ return [[ra + rb for ra, rb in zip(a, b)] for a, b in zip(lst_A, lst_B)]
13850
+
13851
+ ###################################################################################
13852
+
13853
+ def chunk_by_threshold_mode(nums, threshold=0, normalize=False):
13854
+
13855
+ if not nums:
13856
+ return []
13857
+
13858
+ chunks = []
13859
+ chunk = []
13860
+ freq = defaultdict(int)
13861
+ max_freq = 0
13862
+ mode_val = None
13863
+
13864
+ def try_add_and_validate(value):
13865
+
13866
+ nonlocal max_freq, mode_val
13867
+
13868
+ chunk.append(value)
13869
+ freq[value] += 1
13870
+ new_max_freq = max_freq
13871
+ candidate_mode = mode_val
13872
+
13873
+ if freq[value] > new_max_freq:
13874
+ new_max_freq = freq[value]
13875
+ candidate_mode = value
13876
+
13877
+ mode = candidate_mode
13878
+ valid = True
13879
+
13880
+ for v in chunk:
13881
+ if abs(v - mode) > threshold:
13882
+ valid = False
13883
+ break
13884
+
13885
+ if not valid:
13886
+
13887
+ chunk.pop()
13888
+ freq[value] -= 1
13889
+ if freq[value] == 0:
13890
+ del freq[value]
13891
+
13892
+ return False
13893
+
13894
+ max_freq = new_max_freq
13895
+ mode_val = mode
13896
+ return True
13897
+
13898
+ for num in nums:
13899
+ if not chunk:
13900
+ chunk.append(num)
13901
+ freq[num] = 1
13902
+ mode_val = num
13903
+ max_freq = 1
13904
+
13905
+ else:
13906
+ if not try_add_and_validate(num):
13907
+ if normalize:
13908
+ normalized_chunk = [mode_val] * len(chunk)
13909
+ chunks.append(normalized_chunk)
13910
+
13911
+ else:
13912
+ chunks.append(chunk[:])
13913
+
13914
+ chunk.clear()
13915
+ freq.clear()
13916
+
13917
+ chunk.append(num)
13918
+ freq[num] = 1
13919
+ mode_val = num
13920
+ max_freq = 1
13921
+
13922
+ if chunk:
13923
+ if normalize:
13924
+ normalized_chunk = [mode_val] * len(chunk)
13925
+ chunks.append(normalized_chunk)
13926
+
13927
+ else:
13928
+ chunks.append(chunk)
13929
+
13930
+ return chunks
13931
+
13932
+ ###################################################################################
13933
+
13934
+ def proportional_adjust(values, target_sum, threshold):
13935
+
13936
+ n = len(values)
13937
+ if n == 0:
13938
+ return []
13939
+
13940
+ locked_idx = [i for i, v in enumerate(values) if v < threshold]
13941
+ adj_idx = [i for i in range(n) if i not in locked_idx]
13942
+
13943
+ locked_sum = sum(values[i] for i in locked_idx)
13944
+ adj_original_sum = sum(values[i] for i in adj_idx)
13945
+ adj_target_sum = target_sum - locked_sum
13946
+
13947
+ def _proportional_scale(idxs, original, target):
13948
+
13949
+ scaled_vals = {i: original[i] * (target / sum(original[i] for i in idxs))
13950
+ if sum(original[i] for i in idxs) > 0 else 0
13951
+ for i in idxs}
13952
+
13953
+ floored = {i: math.floor(scaled_vals[i]) for i in idxs}
13954
+ rem = target - sum(floored.values())
13955
+
13956
+ fracs = sorted(
13957
+ ((scaled_vals[i] - floored[i], i) for i in idxs),
13958
+ key=lambda x: (x[0], -x[1]),
13959
+ reverse=True
13960
+ )
13961
+
13962
+ for _, idx in fracs[:rem]:
13963
+ floored[idx] += 1
13964
+
13965
+ result = original.copy()
13966
+
13967
+ for i in idxs:
13968
+ result[i] = floored[i]
13969
+
13970
+ return result
13971
+
13972
+ if not adj_idx:
13973
+ if locked_sum == target_sum:
13974
+ return values.copy()
13975
+
13976
+ return _proportional_scale(locked_idx, values, target_sum)
13977
+
13978
+ if adj_target_sum < 0:
13979
+ return _proportional_scale(range(n), values, target_sum)
13980
+
13981
+ if adj_original_sum == 0:
13982
+ base = adj_target_sum // len(adj_idx)
13983
+ rem = adj_target_sum - base * len(adj_idx)
13984
+ result = values.copy()
13985
+
13986
+ for j, idx in enumerate(sorted(adj_idx)):
13987
+ increment = base + (1 if j < rem else 0)
13988
+ result[idx] = values[idx] + increment
13989
+
13990
+ return result
13991
+
13992
+ result = values.copy()
13993
+ scaled = {i: values[i] * (adj_target_sum / adj_original_sum) for i in adj_idx}
13994
+ floored = {i: math.floor(scaled[i]) for i in adj_idx}
13995
+ floor_sum = sum(floored.values())
13996
+ rem = adj_target_sum - floor_sum
13997
+
13998
+ fracs = sorted(
13999
+ ((scaled[i] - floored[i], i) for i in adj_idx),
14000
+ key=lambda x: (x[0], -x[1]),
14001
+ reverse=True
14002
+ )
14003
+
14004
+ for _, idx in fracs[:rem]:
14005
+ floored[idx] += 1
14006
+
14007
+ for i in adj_idx:
14008
+ result[i] = floored[i]
14009
+
14010
+ return result
14011
+
14012
+ ###################################################################################
14013
+
14014
+ def advanced_align_escore_notes_to_bars(escore_notes,
14015
+ bar_dtime=200,
14016
+ dtimes_adj_thresh=4,
14017
+ min_dur_gap=0
14018
+ ):
14019
+
14020
+ #========================================================
14021
+
14022
+ escore_notes = recalculate_score_timings(escore_notes)
14023
+
14024
+ cscore = chordify_score([1000, escore_notes])
14025
+
14026
+ #========================================================
14027
+
14028
+ dtimes = [0] + [min(199, b[1]-a[1]) for a, b in zip(escore_notes[:-1], escore_notes[1:]) if b[1]-a[1] != 0]
14029
+
14030
+ score_times = sorted(set([e[1] for e in escore_notes]))
14031
+
14032
+ #========================================================
14033
+
14034
+ dtimes_chunks = []
14035
+
14036
+ time = 0
14037
+ dtime = []
14038
+
14039
+ for i, dt in enumerate(dtimes):
14040
+ time += dt
14041
+ dtime.append(dt)
14042
+
14043
+ if time >= bar_dtime:
14044
+ dtimes_chunks.append(dtime)
14045
+
14046
+ time = 0
14047
+ dtime = []
14048
+
14049
+ dtimes_chunks.append(dtime)
14050
+
14051
+ #========================================================
14052
+
14053
+ fixed_times = []
14054
+
14055
+ time = 0
14056
+
14057
+ for i, dt in enumerate(dtimes_chunks):
14058
+
14059
+ adj_dt = proportional_adjust(dt,
14060
+ bar_dtime,
14061
+ dtimes_adj_thresh
14062
+ )
14063
+
14064
+ for t in adj_dt:
14065
+
14066
+ time += t
14067
+
14068
+ fixed_times.append(time)
14069
+
14070
+ #========================================================
14071
+
14072
+ output_score = []
14073
+
14074
+ for i, c in enumerate(cscore):
14075
+
14076
+ cc = copy.deepcopy(c)
14077
+ time = fixed_times[i]
14078
+
14079
+ for e in cc:
14080
+ e[1] = time
14081
+
14082
+ output_score.append(e)
14083
+
14084
+ #========================================================
14085
+
14086
+ output_score = fix_escore_notes_durations(output_score,
14087
+ min_notes_gap=min_dur_gap
14088
+ )
14089
+
14090
+ #========================================================
14091
+
14092
+ return output_score
14093
+
14094
+ ###################################################################################
14095
+
14096
+ def check_monophonic_melody(escore_notes,
14097
+ times_idx=1,
14098
+ durs_idx=2
14099
+ ):
14100
+
14101
+ bcount = 0
14102
+
14103
+ for i in range(len(escore_notes)-1):
14104
+ if escore_notes[i][times_idx]+escore_notes[i][durs_idx] > escore_notes[i+1][times_idx]:
14105
+ bcount += 1
14106
+
14107
+ return bcount / len(escore_notes)
14108
+
14109
+ ###################################################################################
14110
+
14111
+ def longest_common_chunk(list1, list2):
14112
+
14113
+ base, mod = 257, 10**9 + 7
14114
+ max_len = min(len(list1), len(list2))
14115
+
14116
+ def get_hashes(seq, size):
14117
+
14118
+ h, power = 0, 1
14119
+ hashes = set()
14120
+
14121
+ for i in range(size):
14122
+ h = (h * base + seq[i]) % mod
14123
+ power = (power * base) % mod
14124
+
14125
+ hashes.add(h)
14126
+
14127
+ for i in range(size, len(seq)):
14128
+ h = (h * base - seq[i - size] * power + seq[i]) % mod
14129
+ hashes.add(h)
14130
+
14131
+ return hashes
14132
+
14133
+ def find_match(size):
14134
+
14135
+ hashes2 = get_hashes(list2, size)
14136
+ h, power = 0, 1
14137
+
14138
+ for i in range(size):
14139
+ h = (h * base + list1[i]) % mod
14140
+ power = (power * base) % mod
14141
+
14142
+ if h in hashes2:
14143
+ return list1[:size]
14144
+
14145
+ for i in range(size, len(list1)):
14146
+ h = (h * base - list1[i - size] * power + list1[i]) % mod
14147
+ if h in hashes2:
14148
+ return list1[i - size + 1:i + 1]
14149
+
14150
+ return []
14151
+
14152
+ left, right = 0, max_len
14153
+ result = []
14154
+
14155
+ while left <= right:
14156
+ mid = (left + right) // 2
14157
+ chunk = find_match(mid)
14158
+
14159
+ if chunk:
14160
+ result = chunk
14161
+ left = mid + 1
14162
+ else:
14163
+
14164
+ right = mid - 1
14165
+
14166
+ return result
14167
+
14168
+ ###################################################################################
14169
+
14170
+ def detect_plateaus(data, min_len=2, tol=0.0):
14171
+
14172
+ plateaus = []
14173
+ n = len(data)
14174
+ if n < min_len:
14175
+ return plateaus
14176
+
14177
+ min_deque = deque()
14178
+ max_deque = deque()
14179
+
14180
+ start = 0
14181
+ idx = 0
14182
+
14183
+ while idx < n:
14184
+ v = data[idx]
14185
+
14186
+ if not isinstance(v, (int, float)) or math.isnan(v):
14187
+
14188
+ if idx - start >= min_len:
14189
+ plateaus.append(data[start:idx])
14190
+
14191
+ idx += 1
14192
+ start = idx
14193
+ min_deque.clear()
14194
+ max_deque.clear()
14195
+
14196
+ continue
14197
+
14198
+ while max_deque and data[max_deque[-1]] <= v:
14199
+ max_deque.pop()
14200
+
14201
+ max_deque.append(idx)
14202
+
14203
+ while min_deque and data[min_deque[-1]] >= v:
14204
+ min_deque.pop()
14205
+
14206
+ min_deque.append(idx)
14207
+
14208
+ if data[max_deque[0]] - data[min_deque[0]] > tol:
14209
+
14210
+ if idx - start >= min_len:
14211
+ plateaus.append(data[start:idx])
14212
+
14213
+ start = idx
14214
+
14215
+ min_deque.clear()
14216
+ max_deque.clear()
14217
+
14218
+ max_deque.append(idx)
14219
+ min_deque.append(idx)
14220
+
14221
+ idx += 1
14222
+
14223
+ if n - start >= min_len:
14224
+ plateaus.append(data[start:n])
14225
+
14226
+ return plateaus
14227
+
14228
+ ###################################################################################
14229
+
14230
+ def alpha_str_to_toks(s, shift=0, add_seos=False):
14231
+
14232
+ tokens = []
14233
+
14234
+ if add_seos:
14235
+ tokens = [53+shift]
14236
+
14237
+ for char in s:
14238
+ if char == ' ':
14239
+ tokens.append(52+shift)
14240
+
14241
+ elif char.isalpha():
14242
+ base = 0 if char.isupper() else 26
14243
+ offset = ord(char.upper()) - ord('A')
14244
+ token = (base + offset + shift) % 52 # wrap A–Z/a–z
14245
+ tokens.append(token)
14246
+
14247
+ if add_seos:
14248
+ tokens.append(53+shift)
14249
+
14250
+ return tokens
14251
+
14252
+ ###################################################################################
14253
+
14254
+ def toks_to_alpha_str(tokens, shift=0, sep=''):
14255
+
14256
+ chars = []
14257
+
14258
+ for token in tokens:
14259
+ if token == 53+shift:
14260
+ continue
14261
+
14262
+ elif token == 52+shift:
14263
+ chars.append(' ')
14264
+
14265
+ elif 0 <= token <= 25:
14266
+ original = (token - shift) % 52
14267
+ chars.append(chr(ord('A') + original))
14268
+
14269
+ elif 26 <= token <= 51:
14270
+ original = (token - shift) % 52
14271
+ chars.append(chr(ord('a') + (original - 26)))
14272
+
14273
+ return sep.join(chars)
14274
+
14275
+ ###################################################################################
14276
+
14277
+ def insert_caps_newlines(text):
14278
+
14279
+ if bool(re.search(r'\b[A-Z][a-z]+\b', text)):
14280
+ pattern = re.compile(r'\s+(?=[A-Z])')
14281
+
14282
+ return pattern.sub('\n', text)
14283
+
14284
+ ###################################################################################
14285
+
14286
+ def insert_newlines(text, every=4):
14287
+
14288
+ count = 0
14289
+ result = []
14290
+
14291
+ for char in text:
14292
+ result.append(char)
14293
+
14294
+ if char == '\n':
14295
+ count += 1
14296
+
14297
+ if count % every == 0:
14298
+ result.append('\n')
14299
+
14300
+ return ''.join(result)
14301
+
14302
+ ###################################################################################
14303
+
14304
+ def symmetric_match_ratio(list_a, list_b, threshold=0):
14305
+
14306
+ a_sorted = sorted(list_a)
14307
+ b_sorted = sorted(list_b)
14308
+
14309
+ i, j = 0, 0
14310
+ matches = 0
14311
+
14312
+ used_a = set()
14313
+ used_b = set()
14314
+
14315
+ while i < len(a_sorted) and j < len(b_sorted):
14316
+ diff = abs(a_sorted[i] - b_sorted[j])
14317
+
14318
+ if diff <= threshold:
14319
+ matches += 1
14320
+ used_a.add(i)
14321
+ used_b.add(j)
14322
+ i += 1
14323
+ j += 1
14324
+
14325
+ elif a_sorted[i] < b_sorted[j]:
14326
+ i += 1
14327
+
14328
+ else:
14329
+ j += 1
14330
+
14331
+ avg_len = (len(list_a) + len(list_b)) / 2
14332
+
14333
+ return matches / avg_len if avg_len > 0 else 0.0
14334
+
14335
+ ###################################################################################
14336
+
14337
+ def escore_notes_to_chords(escore_notes,
14338
+ use_full_chords=False,
14339
+ repair_bad_chords=True,
14340
+ skip_pitches=False,
14341
+ convert_pitches=True,
14342
+ shift_chords=False,
14343
+ return_tones_chords=False
14344
+ ):
14345
+
14346
+ if use_full_chords:
14347
+ CHORDS = ALL_CHORDS_FULL
14348
+
14349
+ else:
14350
+ CHORDS = ALL_CHORDS_SORTED
14351
+
14352
+ sp_score = solo_piano_escore_notes(escore_notes)
14353
+
14354
+ cscore = chordify_score([1000, sp_score])
14355
+
14356
+ chords = []
14357
+
14358
+ for c in cscore:
14359
+ pitches = sorted(set([e[4] for e in c]))
14360
+
14361
+ tones_chord = sorted(set([p % 12 for p in pitches]))
14362
+
14363
+ if repair_bad_chords:
14364
+ if tones_chord not in CHORDS:
14365
+ tones_chord = check_and_fix_tones_chord(tones_chord,
14366
+ use_full_chords=use_full_chords
14367
+ )
14368
+
14369
+ if return_tones_chords:
14370
+ if convert_pitches:
14371
+ chords.append(tones_chord)
14372
+
14373
+ else:
14374
+ if len(pitches) > 1:
14375
+ chords.append(tones_chord)
14376
+
14377
+ else:
14378
+ chords.append([-pitches[0]])
14379
+
14380
+ else:
14381
+ if skip_pitches:
14382
+ if tones_chord in CHORDS:
14383
+ cho_tok = CHORDS.index(tones_chord)
14384
+
14385
+ else:
14386
+ cho_tok = -1
14387
+
14388
+ if len(pitches) > 1:
14389
+ chords.append(cho_tok)
14390
+
14391
+ else:
14392
+ if tones_chord in CHORDS:
14393
+ cho_tok = CHORDS.index(tones_chord)
14394
+
14395
+ else:
14396
+ cho_tok = -1
14397
+
14398
+ if cho_tok != -1:
14399
+ if convert_pitches:
14400
+ if shift_chords:
14401
+ if len(pitches) > 1:
14402
+ chords.append(cho_tok+12)
14403
+
14404
+ else:
14405
+ chords.append(pitches[0] % 12)
14406
+
14407
+ else:
14408
+ chords.append(cho_tok)
14409
+
14410
+ else:
14411
+ if len(pitches) > 1:
14412
+ chords.append(cho_tok+128)
14413
+
14414
+ else:
14415
+ chords.append(pitches[0])
14416
+
14417
+ return chords
14418
+
14419
+ ###################################################################################
14420
+
14421
+ def replace_chords_in_escore_notes(escore_notes,
14422
+ chords_list=[-1],
14423
+ use_full_chords=False,
14424
+ use_shifted_chords=False
14425
+ ):
14426
+
14427
+ if use_full_chords:
14428
+ CHORDS = ALL_CHORDS_FULL
14429
+
14430
+ else:
14431
+ CHORDS = ALL_CHORDS_SORTED
14432
+
14433
+ if use_shifted_chords:
14434
+ shift = 12
14435
+
14436
+ else:
14437
+ shift = 0
14438
+
14439
+ if min(chords_list) >= 0 and max(chords_list) <= len(CHORDS)+shift:
14440
+
14441
+ chords_list_iter = cycle(chords_list)
14442
+
14443
+ nd_score = [e for e in escore_notes if e[3] != 9]
14444
+ d_score = [e for e in escore_notes if e[3] == 9]
14445
+
14446
+ cscore = chordify_score([1000, nd_score])
14447
+
14448
+ new_score = []
14449
+
14450
+ for i, c in enumerate(cscore):
14451
+
14452
+ cur_chord = next(chords_list_iter)
14453
+
14454
+ cc = copy.deepcopy(c)
14455
+
14456
+ if use_shifted_chords:
14457
+ if cur_chord < 12:
14458
+ sub_tones_chord = [cur_chord]
14459
+
14460
+ else:
14461
+ sub_tones_chord = CHORDS[cur_chord-12]
14462
+ else:
14463
+ sub_tones_chord = CHORDS[cur_chord]
14464
+
14465
+ stcho = cycle(sub_tones_chord)
14466
+
14467
+ if len(sub_tones_chord) > len(c):
14468
+ cc = [copy.deepcopy(e) for e in cc for _ in range(len(sub_tones_chord))]
14469
+
14470
+ pseen = []
14471
+
14472
+ for e in cc:
14473
+ st = next(stcho)
14474
+ new_pitch = ((e[4] // 12) * 12) + st
14475
+
14476
+ if [new_pitch, e[6]] not in pseen:
14477
+ e[4] = new_pitch
14478
+
14479
+ new_score.append(e)
14480
+ pseen.append([new_pitch, e[6]])
14481
+
14482
+ final_score = sorted(new_score+d_score, key=lambda x: x[1])
14483
+
14484
+ return final_score
14485
+
14486
+ else:
14487
+ return []
14488
+
14489
+ ###################################################################################
14490
+
14491
+ class Cell:
14492
+ def __init__(self, cost, segments, gaps, prev_dir):
14493
+ self.cost = cost
14494
+ self.segments = segments
14495
+ self.gaps = gaps
14496
+ self.prev_dir = prev_dir
14497
+
14498
+ def align_integer_lists(seq1, seq2):
14499
+
14500
+ n, m = len(seq1), len(seq2)
14501
+
14502
+ if n == 0:
14503
+ return [None]*m, seq2.copy(), sum(abs(x) for x in seq2)
14504
+ if m == 0:
14505
+ return seq1.copy(), [None]*n, sum(abs(x) for x in seq1)
14506
+
14507
+ priority = {'diag': 0, 'up': 1, 'left': 2}
14508
+
14509
+ dp = [
14510
+ [Cell(cost=math.inf, segments=math.inf, gaps=math.inf, prev_dir='') for _ in range(m+1)]
14511
+ for _ in range(n+1)
14512
+ ]
14513
+ dp[0][0] = Cell(cost=0, segments=0, gaps=0, prev_dir='')
14514
+
14515
+ for i in range(1, n+1):
14516
+ prev = dp[i-1][0]
14517
+ new_cost = prev.cost + abs(seq1[i-1])
14518
+ new_seg = prev.segments + (1 if prev.prev_dir != 'up' else 0)
14519
+ new_gaps = prev.gaps + 1
14520
+ dp[i][0] = Cell(new_cost, new_seg, new_gaps, 'up')
14521
+
14522
+ for j in range(1, m+1):
14523
+ prev = dp[0][j-1]
14524
+ new_cost = prev.cost + abs(seq2[j-1])
14525
+ new_seg = prev.segments + (1 if prev.prev_dir != 'left' else 0)
14526
+ new_gaps = prev.gaps + 1
14527
+ dp[0][j] = Cell(new_cost, new_seg, new_gaps, 'left')
14528
+
14529
+ for i in range(1, n+1):
14530
+ for j in range(1, m+1):
14531
+ a, b = seq1[i-1], seq2[j-1]
14532
+
14533
+ c0 = dp[i-1][j-1]
14534
+ cand_diag = Cell(
14535
+ cost = c0.cost + abs(a - b),
14536
+ segments = c0.segments,
14537
+ gaps = c0.gaps,
14538
+ prev_dir = 'diag'
14539
+ )
14540
+
14541
+ c1 = dp[i-1][j]
14542
+ seg1 = c1.segments + (1 if c1.prev_dir != 'up' else 0)
14543
+ cand_up = Cell(
14544
+ cost = c1.cost + abs(a),
14545
+ segments = seg1,
14546
+ gaps = c1.gaps + 1,
14547
+ prev_dir = 'up'
14548
+ )
14549
+
14550
+ c2 = dp[i][j-1]
14551
+ seg2 = c2.segments + (1 if c2.prev_dir != 'left' else 0)
14552
+ cand_left = Cell(
14553
+ cost = c2.cost + abs(b),
14554
+ segments = seg2,
14555
+ gaps = c2.gaps + 1,
14556
+ prev_dir = 'left'
14557
+ )
14558
+
14559
+ best = min(
14560
+ (cand_diag, cand_up, cand_left),
14561
+ key=lambda c: (c.cost, c.segments, c.gaps, priority[c.prev_dir])
14562
+ )
14563
+ dp[i][j] = best
14564
+
14565
+ aligned1 = []
14566
+ aligned2 = []
14567
+ i, j = n, m
14568
+
14569
+ while i > 0 or j > 0:
14570
+ cell = dp[i][j]
14571
+
14572
+ if cell.prev_dir == 'diag':
14573
+ aligned1.append(seq1[i-1])
14574
+ aligned2.append(seq2[j-1])
14575
+ i, j = i-1, j-1
14576
+
14577
+ elif cell.prev_dir == 'up':
14578
+ aligned1.append(seq1[i-1])
14579
+ aligned2.append(None)
14580
+ i -= 1
14581
+
14582
+ else:
14583
+ aligned1.append(None)
14584
+ aligned2.append(seq2[j-1])
14585
+ j -= 1
14586
+
14587
+ aligned1.reverse()
14588
+ aligned2.reverse()
14589
+
14590
+ total_cost = int(dp[n][m].cost)
14591
+
14592
+ return aligned1, aligned2, total_cost
14593
+
14594
+ ###################################################################################
14595
+
14596
+ def most_common_delta_time(escore_notes):
14597
+
14598
+ dscore = delta_score_notes(escore_notes)
14599
+
14600
+ dtimes = [t[1] for t in dscore if t[1] != 0]
14601
+
14602
+ cdtime, count = Counter(dtimes).most_common(1)[0]
14603
+
14604
+ return [cdtime, count / len(dtimes)]
14605
+
14606
+ ###################################################################################
14607
+
14608
+ def delta_tones(escore_notes,
14609
+ ptcs_idx=4
14610
+ ):
14611
+
14612
+ pitches = [p[ptcs_idx] for p in escore_notes]
14613
+ tones = [p % 12 for p in pitches]
14614
+
14615
+ return [b-a for a, b in zip(tones[:-1], tones[1:])]
14616
+
14617
+ ###################################################################################
14618
+
14619
+ def find_divisors(val,
14620
+ reverse=False
14621
+ ):
14622
+
14623
+ if val == 0:
14624
+ return []
14625
+
14626
+ n = abs(val)
14627
+ divisors = set()
14628
+
14629
+ for i in range(1, int(n**0.5) + 1):
14630
+ if n % i == 0:
14631
+ divisors.add(i)
14632
+ divisors.add(n // i)
14633
+
14634
+ return sorted(divisors, reverse=reverse)
14635
+
14636
+ ###################################################################################
14637
+
14638
+ def find_common_divisors(values,
14639
+ reverse=False
14640
+ ):
14641
+
14642
+ if not values:
14643
+ return []
14644
+
14645
+ non_zero = [abs(v) for v in values if v != 0]
14646
+ if not non_zero:
14647
+ return []
14648
+
14649
+ overall_gcd = reduce(gcd, non_zero)
14650
+
14651
+ divisors = set()
14652
+
14653
+ for i in range(1, int(overall_gcd**0.5) + 1):
14654
+ if overall_gcd % i == 0:
14655
+ divisors.add(i)
14656
+ divisors.add(overall_gcd // i)
14657
+
14658
+ return sorted(divisors, reverse=reverse)
14659
+
14660
+ ###################################################################################
14661
+
14662
+ def strings_dict(list_of_strings,
14663
+ verbose=False
14664
+ ):
14665
+
14666
+ str_set = set()
14667
+
14668
+ for st in tqdm.tqdm(list_of_strings, disable=not verbose):
14669
+ for cha in st:
14670
+ str_set.add(cha)
14671
+
14672
+ str_lst = sorted(str_set)
14673
+
14674
+ str_dic = dict(zip(str_lst, range(len(str_lst))))
14675
+ rev_str_dic = {v: k for k, v in str_dic.items()}
14676
+
14677
+ return str_dic, rev_str_dic
14678
+
14679
+ ###################################################################################
14680
+
14681
+ def chords_common_tones_chain(chords,
14682
+ use_full_chords=False
14683
+ ):
14684
+
14685
+ if use_full_chords:
14686
+ CHORDS = ALL_CHORDS_FULL
14687
+
14688
+ else:
14689
+ CHORDS = ALL_CHORDS_SORTED
14690
+
14691
+ tones_chords = [CHORDS[c] for c in chords if 0 <= c < len(CHORDS)]
14692
+
14693
+ n = len(tones_chords)
14694
+
14695
+ if not tones_chords:
14696
+ return []
14697
+
14698
+ if n < 2:
14699
+ return tones_chords
14700
+
14701
+ result = []
14702
+
14703
+ for i in range(n):
14704
+ if i == 0:
14705
+ common = set(tones_chords[0]) & set(tones_chords[1])
14706
+
14707
+ elif i == n - 1:
14708
+ common = set(tones_chords[n - 2]) & set(tones_chords[n - 1])
14709
+
14710
+ else:
14711
+ common = set(tones_chords[i - 1]) & set(tones_chords[i]) & set(tones_chords[i + 1])
14712
+
14713
+ result.append(min(common) if common else -1)
14714
+
14715
+ return result
14716
+
14717
+ ###################################################################################
14718
+
14719
+ def tones_chord_to_int(tones_chord,
14720
+ reverse_bits=True
14721
+ ):
14722
+
14723
+ cbits = tones_chord_to_bits(tones_chord,
14724
+ reverse=reverse_bits
14725
+ )
14726
+
14727
+ cint = bits_to_int(cbits)
14728
+
14729
+ return cint
14730
+
14731
+ ###################################################################################
14732
+
14733
+ def int_to_tones_chord(integer,
14734
+ reverse_bits=True
14735
+ ):
14736
+
14737
+ integer = integer % 4096
14738
+
14739
+ cbits = int_to_bits(integer)
14740
+
14741
+ if reverse_bits:
14742
+ cbits.reverse()
14743
+
14744
+ tones_chord = bits_to_tones_chord(cbits)
14745
+
14746
+ return tones_chord
14747
+
14748
+ ###################################################################################
14749
+
14750
+ def fix_bad_chords_in_escore_notes(escore_notes,
14751
+ use_full_chords=False,
14752
+ return_bad_chords_count=False
14753
+ ):
14754
+
14755
+ if use_full_chords:
14756
+ CHORDS = ALL_CHORDS_FULL
14757
+
14758
+ else:
14759
+ CHORDS = ALL_CHORDS_SORTED
14760
+
14761
+ bcount = 0
14762
+
14763
+ if escore_notes:
14764
+
14765
+ chords = chordify_score([1000, escore_notes])
14766
+
14767
+ fixed_chords = []
14768
+
14769
+ for c in chords:
14770
+ c.sort(key=lambda x: x[3])
14771
+
14772
+ if len(c) > 1:
14773
+
14774
+ groups = groupby(c, key=lambda x: x[3])
14775
+
14776
+ for cha, gr in groups:
14777
+
14778
+ if cha != 9:
14779
+
14780
+ gr = list(gr)
14781
+
14782
+ tones_chord = sorted(set([p[4] % 12 for p in gr]))
14783
+
14784
+ if tones_chord not in CHORDS:
14785
+ tones_chord = check_and_fix_tones_chord(tones_chord,
14786
+ use_full_chords=use_full_chords
14787
+ )
14788
+
14789
+ bcount += 1
14790
+
14791
+ ngr = []
14792
+
14793
+ for n in gr:
14794
+ if n[4] % 12 in tones_chord:
14795
+ ngr.append(n)
14796
+
14797
+ fixed_chords.extend(ngr)
14798
+
14799
+ else:
14800
+ fixed_chords.extend(gr)
14801
+
14802
+
14803
+ else:
14804
+ fixed_chords.extend(c)
14805
+
14806
+ fixed_chords.sort(key=lambda x: (x[1], -x[4]))
14807
+
14808
+ if return_bad_chords_count:
14809
+ return fixed_chords, bcount
14810
+
14811
+ else:
14812
+ return fixed_chords
14813
+
14814
+ else:
14815
+ if return_bad_chords_count:
14816
+ return escore_notes, bcount
14817
+
14818
+ else:
14819
+ return escore_notes
14820
+
14821
+ ###################################################################################
14822
+
14823
+ def remove_events_from_escore_notes(escore_notes,
14824
+ ele_idx=2,
14825
+ ele_vals=[1],
14826
+ chan_idx=3,
14827
+ skip_drums=True
14828
+ ):
14829
+
14830
+ new_escore_notes = []
14831
+
14832
+ for e in escore_notes:
14833
+ if skip_drums:
14834
+ if e[ele_idx] not in ele_vals or e[chan_idx] == 9:
14835
+ new_escore_notes.append(e)
14836
+
14837
+ else:
14838
+ if e[ele_idx] not in ele_vals:
14839
+ new_escore_notes.append(e)
14840
+
14841
+ return new_escore_notes
14842
+
14843
+ ###################################################################################
14844
+
14845
+ def flatten_spikes(arr):
14846
+
14847
+ if len(arr) < 3:
14848
+ return arr[:]
14849
+
14850
+ result = arr[:]
14851
+
14852
+ for i in range(1, len(arr) - 1):
14853
+ prev, curr, next_ = arr[i - 1], arr[i], arr[i + 1]
14854
+
14855
+ if (prev <= next_ and (curr > prev and curr > next_)) or \
14856
+ (prev >= next_ and (curr < prev and curr < next_)):
14857
+ result[i] = max(min(prev, next_), min(max(prev, next_), curr))
14858
+
14859
+ return result
14860
+
14861
+ ###################################################################################
14862
+
14863
+ def flatten_spikes_advanced(arr, window=1):
14864
+
14865
+ if len(arr) < 3:
14866
+ return arr[:]
14867
+
14868
+ result = arr[:]
14869
+ n = len(arr)
14870
+
14871
+ def is_spike(i):
14872
+ left = arr[i - window:i]
14873
+ right = arr[i + 1:i + 1 + window]
14874
+
14875
+ if not left or not right:
14876
+ return False
14877
+
14878
+ avg_left = sum(left) / len(left)
14879
+ avg_right = sum(right) / len(right)
14880
+
14881
+ if arr[i] > avg_left and arr[i] > avg_right:
14882
+ return True
14883
+
14884
+ if arr[i] < avg_left and arr[i] < avg_right:
14885
+ return True
14886
+
14887
+ return False
14888
+
14889
+ for i in range(window, n - window):
14890
+ if is_spike(i):
14891
+ neighbors = arr[i - window:i] + arr[i + 1:i + 1 + window]
14892
+ result[i] = int(sorted(neighbors)[len(neighbors) // 2])
14893
+
14894
+ return result
14895
+
14896
+ ###################################################################################
14897
+
14898
+ def add_smooth_melody_to_enhanced_score_notes(escore_notes,
14899
+ melody_channel=3,
14900
+ melody_patch=40,
14901
+ melody_start_chord=0,
14902
+ min_notes_gap=0,
14903
+ exclude_durs=[1],
14904
+ adv_flattening=True,
14905
+ extend_durs=True,
14906
+ max_mel_vels=127,
14907
+ max_acc_vels=80,
14908
+ return_melody=False
14909
+ ):
14910
+
14911
+ escore_notes1 = remove_duplicate_pitches_from_escore_notes(escore_notes)
14912
+
14913
+ escore_notes2 = fix_escore_notes_durations(escore_notes1,
14914
+ min_notes_gap=min_notes_gap
14915
+ )
14916
+
14917
+ escore_notes3 = fix_bad_chords_in_escore_notes(escore_notes2)
14918
+
14919
+ escore_notes4 = remove_events_from_escore_notes(escore_notes3,
14920
+ ele_vals=exclude_durs
14921
+ )
14922
+
14923
+ escore_notes5 = add_expressive_melody_to_enhanced_score_notes(escore_notes4,
14924
+ melody_channel=melody_channel,
14925
+ melody_patch=melody_patch,
14926
+ melody_start_chord=melody_start_chord,
14927
+ return_melody=True,
14928
+ )
14929
+
14930
+ mel_score = remove_events_from_escore_notes(escore_notes5,
14931
+ ele_vals=exclude_durs
14932
+ )
14933
+
14934
+ pitches = [p[4] for p in mel_score]
14935
+
14936
+ if adv_flattening:
14937
+ res = flatten_spikes_advanced(pitches)
14938
+
14939
+ else:
14940
+ res = flatten_spikes(pitches)
14941
+
14942
+ mel_score3 = copy.deepcopy(mel_score)
14943
+
14944
+ for i, e in enumerate(mel_score3):
14945
+ e[4] = res[i]
14946
+
14947
+ mel_score3 = fix_monophonic_score_durations(merge_melody_notes(mel_score3),
14948
+ extend_durs=extend_durs
14949
+ )
14950
+
14951
+ adjust_score_velocities(mel_score3, max_mel_vels)
14952
+ adjust_score_velocities(escore_notes4, max_acc_vels)
14953
+
14954
+ if return_melody:
14955
+ return sorted(mel_score3, key=lambda x: (x[1], -x[4]))
14956
+
14957
+ else:
14958
+ return sorted(mel_score3 + escore_notes4, key=lambda x: (x[1], -x[4]))
14959
+
14960
+ ###################################################################################
14961
+
14962
+ def sorted_chords_to_full_chords(chords):
14963
+
14964
+ cchords = []
14965
+
14966
+ for c in chords:
14967
+ tones_chord = ALL_CHORDS_SORTED[c]
14968
+
14969
+ if tones_chord not in ALL_CHORDS_FULL:
14970
+ tones_chord = check_and_fix_tones_chord(tones_chord)
14971
+
14972
+ cchords.append(ALL_CHORDS_FULL.index(tones_chord))
14973
+
14974
+ return cchords
14975
+
14976
+ ###################################################################################
14977
+
14978
+ def full_chords_to_sorted_chords(chords):
14979
+
14980
+ cchords = []
14981
+
14982
+ for c in chords:
14983
+ tones_chord = ALL_CHORDS_FULL[c]
14984
+
14985
+ if tones_chord not in ALL_CHORDS_SORTED:
14986
+ tones_chord = check_and_fix_tones_chord(tones_chord, use_full_chords=False)
14987
+
14988
+ cchords.append(ALL_CHORDS_SORTED.index(tones_chord))
14989
+
14990
+ return cchords
14991
+
14992
+ ###################################################################################
14993
+
14994
+ def chords_to_escore_notes(chords,
14995
+ use_full_chords=False,
14996
+ chords_dtime=500,
14997
+ add_melody=True,
14998
+ add_texture=True,
14999
+ ):
15000
+
15001
+ if use_full_chords:
15002
+ CHORDS = ALL_CHORDS_FULL
15003
+
15004
+ else:
15005
+ CHORDS = ALL_CHORDS_SORTED
15006
+
15007
+ score = []
15008
+
15009
+ dtime = 0
15010
+
15011
+ dur = chords_dtime
15012
+
15013
+ for c in chords:
15014
+
15015
+ if add_melody:
15016
+ score.append(['note', dtime, dur, 3, CHORDS[c][0]+72, 115+CHORDS[c][0], 40])
15017
+
15018
+ for cc in CHORDS[c]:
15019
+ score.append(['note', dtime, dur, 0, cc+48, 30+cc+48, 0])
15020
+
15021
+ if random.randint(0, 1) and add_texture:
15022
+ score.append(['note', dtime, dur, 0, cc+60, 20+cc+60, 0])
15023
+
15024
+ dtime += chords_dtime
15025
+
15026
+ return score
15027
+
15028
+ ###################################################################################
15029
+
15030
  print('Module loaded!')
15031
  print('=' * 70)
15032
  print('Enjoy! :)')