asigalov61 commited on
Commit
faf16d7
1 Parent(s): ef7a679

Upload 2 files

Browse files
Files changed (2) hide show
  1. TMIDIX.py +2107 -73
  2. TPLOTS.py +1245 -0
TMIDIX.py CHANGED
@@ -1484,6 +1484,7 @@ from abc import ABC, abstractmethod
1484
  from difflib import SequenceMatcher as SM
1485
 
1486
  import statistics
 
1487
 
1488
  import matplotlib.pyplot as plt
1489
 
@@ -1762,7 +1763,10 @@ def plot_ms_SONG(ms_song,
1762
  note_height = 0.75,
1763
  show_grid_lines=False,
1764
  return_plt = False,
1765
- timings_multiplier=1
 
 
 
1766
  ):
1767
 
1768
  '''Tegridy ms SONG plotter/vizualizer'''
@@ -1816,10 +1820,22 @@ def plot_ms_SONG(ms_song,
1816
 
1817
  plt.title(plot_title)
1818
 
 
 
 
 
 
 
 
 
 
 
 
1819
  if return_plt:
1820
  return fig
1821
 
1822
  plt.show()
 
1823
 
1824
  ###################################################################################
1825
 
@@ -1932,7 +1948,7 @@ def Tegridy_Any_Pickle_File_Reader(input_file_name='TMIDI_Pickle_File', ext='.pi
1932
 
1933
  '''Tegridy Pickle File Loader
1934
 
1935
- Input: Full path and file name without extention
1936
  File extension if different from default .pickle
1937
 
1938
  Output: Standard Python 3 unpickled data object
@@ -1944,7 +1960,13 @@ def Tegridy_Any_Pickle_File_Reader(input_file_name='TMIDI_Pickle_File', ext='.pi
1944
  print('Tegridy Pickle File Loader')
1945
  print('Loading the pickle file. Please wait...')
1946
 
1947
- with open(input_file_name + ext, 'rb') as pickle_file:
 
 
 
 
 
 
1948
  content = pickle.load(pickle_file)
1949
 
1950
  if verbose:
@@ -3519,12 +3541,19 @@ def Tegridy_Split_List(list_to_split, split_value=0):
3519
 
3520
  # Binary chords functions
3521
 
3522
- def tones_chord_to_bits(chord):
 
3523
  bits = [0] * 12
 
3524
  for num in chord:
3525
  bits[num] = 1
3526
 
3527
- return bits
 
 
 
 
 
3528
 
3529
  def bits_to_tones_chord(bits):
3530
  return [i for i, bit in enumerate(bits) if bit == 1]
@@ -4687,23 +4716,53 @@ def create_similarity_matrix(list_of_values, matrix_length=0):
4687
 
4688
  ###################################################################################
4689
 
 
 
 
 
 
 
4690
  def augment_enhanced_score_notes(enhanced_score_notes,
4691
  timings_divider=16,
4692
  full_sorting=True,
4693
  timings_shift=0,
4694
- pitch_shift=0
 
4695
  ):
4696
 
4697
  esn = copy.deepcopy(enhanced_score_notes)
4698
 
4699
- for e in esn:
4700
- e[1] = int(e[1] / timings_divider) + timings_shift
4701
- e[2] = int(e[2] / timings_divider) + timings_shift
4702
- e[4] = e[4] + pitch_shift
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4703
 
4704
  if full_sorting:
4705
 
4706
- # Sorting by patch, pitch, then by start-time
4707
  esn.sort(key=lambda x: x[6])
4708
  esn.sort(key=lambda x: x[4], reverse=True)
4709
  esn.sort(key=lambda x: x[1])
@@ -4894,25 +4953,26 @@ def patch_list_from_enhanced_score_notes(enhanced_score_notes,
4894
  patches = [-1] * 16
4895
 
4896
  for idx, e in enumerate(enhanced_score_notes):
4897
- if e[3] != 9:
4898
- if patches[e[3]] == -1:
4899
- patches[e[3]] = e[6]
4900
- else:
4901
- if patches[e[3]] != e[6]:
4902
- if e[6] in patches:
4903
- e[3] = patches.index(e[6])
4904
- else:
4905
- if -1 in patches:
4906
- patches[patches.index(-1)] = e[6]
4907
  else:
4908
- patches[-1] = e[6]
 
 
 
4909
 
4910
- if verbose:
4911
- print('=' * 70)
4912
- print('WARNING! Composition has more than 15 patches!')
4913
- print('Conflict note number:', idx)
4914
- print('Conflict channel number:', e[3])
4915
- print('Conflict patch number:', e[6])
4916
 
4917
  patches = [p if p != -1 else default_patch for p in patches]
4918
 
@@ -4945,19 +5005,20 @@ def patch_enhanced_score_notes(enhanced_score_notes,
4945
  overflow_idx = -1
4946
 
4947
  for idx, e in enumerate(enhanced_score_notes):
4948
- if e[3] != 9:
4949
- if patches[e[3]] == -1:
4950
- patches[e[3]] = e[6]
4951
- else:
4952
- if patches[e[3]] != e[6]:
4953
- if e[6] in patches:
4954
- e[3] = patches.index(e[6])
4955
- else:
4956
- if -1 in patches:
4957
- patches[patches.index(-1)] = e[6]
4958
  else:
4959
- overflow_idx = idx
4960
- break
 
 
 
4961
 
4962
  enhanced_score_notes_with_patch_changes.append(e)
4963
 
@@ -4967,15 +5028,16 @@ def patch_enhanced_score_notes(enhanced_score_notes,
4967
 
4968
  if overflow_idx != -1:
4969
  for idx, e in enumerate(enhanced_score_notes[overflow_idx:]):
4970
- if e[3] != 9:
4971
- if e[6] not in patches:
4972
- if e[6] not in overflow_patches:
4973
- overflow_patches.append(e[6])
4974
- enhanced_score_notes_with_patch_changes.append(['patch_change', e[1], e[3], e[6]])
4975
- else:
4976
- e[3] = patches.index(e[6])
 
4977
 
4978
- enhanced_score_notes_with_patch_changes.append(e)
4979
 
4980
  #===========================================================================
4981
 
@@ -5258,7 +5320,8 @@ def add_melody_to_enhanced_score_notes(enhanced_score_notes,
5258
  melody_patch=40,
5259
  melody_max_velocity=110,
5260
  acc_max_velocity=90,
5261
- pass_drums=True
 
5262
  ):
5263
 
5264
  if pass_drums:
@@ -5336,7 +5399,11 @@ def add_melody_to_enhanced_score_notes(enhanced_score_notes,
5336
 
5337
  adjust_score_velocities(smoothed_melody, melody_max_velocity)
5338
 
5339
- final_score = sorted(smoothed_melody + acc_score, key=lambda x: (x[1], -x[4]))
 
 
 
 
5340
 
5341
  return final_score
5342
 
@@ -5349,7 +5416,10 @@ def find_paths(list_of_lists, path=[]):
5349
 
5350
  ###################################################################################
5351
 
5352
- def recalculate_score_timings(score, start_time=0):
 
 
 
5353
 
5354
  rscore = copy.deepcopy(score)
5355
 
@@ -5359,10 +5429,10 @@ def recalculate_score_timings(score, start_time=0):
5359
 
5360
  for e in rscore:
5361
 
5362
- dtime = e[1] - pe[1]
5363
  pe = copy.deepcopy(e)
5364
  abs_time += dtime
5365
- e[1] = abs_time
5366
 
5367
  return rscore
5368
 
@@ -6359,38 +6429,2002 @@ def transpose_pitches(pitches, transpose_value=0):
6359
 
6360
  ###################################################################################
6361
 
6362
- def reverse_enhanced_score_notes(enhanced_score_notes):
 
 
 
 
 
6363
 
6364
- score = recalculate_score_timings(enhanced_score_notes)
6365
 
6366
- cscore = chordify_score([1000, score])
6367
 
6368
- abs_dtimes = []
6369
 
6370
- for i, t in enumerate(cscore[:-1]):
6371
- abs_dtimes.append(cscore[i+1][0][1])
6372
- abs_dtimes.append(cscore[-1][0][1]+cscore[-1][0][2])
 
 
 
 
 
 
 
6373
 
6374
- new_dtimes = []
6375
- pt = abs_dtimes[-1]
6376
 
6377
- for t in abs_dtimes[::-1]:
6378
- new_dtimes.append(abs(pt-t))
6379
- pt = t
6380
 
6381
- new_mel = copy.deepcopy(cscore[::-1])
6382
 
6383
- time = 0
6384
 
6385
- for i, t in enumerate(new_mel):
6386
- time += new_dtimes[i]
6387
- for tt in t:
6388
- tt[1] = time
6389
 
6390
- return recalculate_score_timings(flatten(new_mel))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6391
 
6392
  ###################################################################################
6393
 
6394
- # This is the end of the TMIDI X Python module
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6395
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6396
  ###################################################################################
 
1484
  from difflib import SequenceMatcher as SM
1485
 
1486
  import statistics
1487
+ import math
1488
 
1489
  import matplotlib.pyplot as plt
1490
 
 
1763
  note_height = 0.75,
1764
  show_grid_lines=False,
1765
  return_plt = False,
1766
+ timings_multiplier=1,
1767
+ save_plt='',
1768
+ save_only_plt_image=True,
1769
+ save_transparent=False
1770
  ):
1771
 
1772
  '''Tegridy ms SONG plotter/vizualizer'''
 
1820
 
1821
  plt.title(plot_title)
1822
 
1823
+ if save_plt != '':
1824
+ if save_only_plt_image:
1825
+ plt.axis('off')
1826
+ plt.title('')
1827
+ plt.savefig(save_plt, transparent=save_transparent, bbox_inches='tight', pad_inches=0, facecolor='black')
1828
+ plt.close()
1829
+
1830
+ else:
1831
+ plt.savefig(save_plt)
1832
+ plt.close()
1833
+
1834
  if return_plt:
1835
  return fig
1836
 
1837
  plt.show()
1838
+ plt.close()
1839
 
1840
  ###################################################################################
1841
 
 
1948
 
1949
  '''Tegridy Pickle File Loader
1950
 
1951
+ Input: Full path and file name with or without extention
1952
  File extension if different from default .pickle
1953
 
1954
  Output: Standard Python 3 unpickled data object
 
1960
  print('Tegridy Pickle File Loader')
1961
  print('Loading the pickle file. Please wait...')
1962
 
1963
+ if os.path.basename(input_file_name).endswith(ext):
1964
+ fname = input_file_name
1965
+
1966
+ else:
1967
+ fname = input_file_name + ext
1968
+
1969
+ with open(fname, 'rb') as pickle_file:
1970
  content = pickle.load(pickle_file)
1971
 
1972
  if verbose:
 
3541
 
3542
  # Binary chords functions
3543
 
3544
+ def tones_chord_to_bits(chord, reverse=True):
3545
+
3546
  bits = [0] * 12
3547
+
3548
  for num in chord:
3549
  bits[num] = 1
3550
 
3551
+ if reverse:
3552
+ bits.reverse()
3553
+ return bits
3554
+
3555
+ else:
3556
+ return bits
3557
 
3558
  def bits_to_tones_chord(bits):
3559
  return [i for i, bit in enumerate(bits) if bit == 1]
 
4716
 
4717
  ###################################################################################
4718
 
4719
+ def ceil_with_precision(value, decimal_places):
4720
+ factor = 10 ** decimal_places
4721
+ return math.ceil(value * factor) / factor
4722
+
4723
+ ###################################################################################
4724
+
4725
  def augment_enhanced_score_notes(enhanced_score_notes,
4726
  timings_divider=16,
4727
  full_sorting=True,
4728
  timings_shift=0,
4729
+ pitch_shift=0,
4730
+ legacy_timings=False
4731
  ):
4732
 
4733
  esn = copy.deepcopy(enhanced_score_notes)
4734
 
4735
+ pe = enhanced_score_notes[0]
4736
+
4737
+ abs_time = max(0, int(enhanced_score_notes[0][1] / timings_divider))
4738
+
4739
+ for i, e in enumerate(esn):
4740
+
4741
+ dtime = (e[1] / timings_divider) - (pe[1] / timings_divider)
4742
+
4743
+ if 0.5 < dtime < 1:
4744
+ dtime = 1
4745
+
4746
+ else:
4747
+ dtime = int(dtime)
4748
+
4749
+ if legacy_timings:
4750
+ abs_time = int(e[1] / timings_divider) + timings_shift
4751
+
4752
+ else:
4753
+ abs_time += dtime
4754
+
4755
+ e[1] = max(0, abs_time + timings_shift)
4756
+
4757
+ e[2] = max(1, int(e[2] / timings_divider)) + timings_shift
4758
+
4759
+ e[4] = max(1, min(127, e[4] + pitch_shift))
4760
+
4761
+ pe = enhanced_score_notes[i]
4762
 
4763
  if full_sorting:
4764
 
4765
+ # Sorting by patch, reverse pitch and start-time
4766
  esn.sort(key=lambda x: x[6])
4767
  esn.sort(key=lambda x: x[4], reverse=True)
4768
  esn.sort(key=lambda x: x[1])
 
4953
  patches = [-1] * 16
4954
 
4955
  for idx, e in enumerate(enhanced_score_notes):
4956
+ if e[0] == 'note':
4957
+ if e[3] != 9:
4958
+ if patches[e[3]] == -1:
4959
+ patches[e[3]] = e[6]
4960
+ else:
4961
+ if patches[e[3]] != e[6]:
4962
+ if e[6] in patches:
4963
+ e[3] = patches.index(e[6])
 
 
4964
  else:
4965
+ if -1 in patches:
4966
+ patches[patches.index(-1)] = e[6]
4967
+ else:
4968
+ patches[-1] = e[6]
4969
 
4970
+ if verbose:
4971
+ print('=' * 70)
4972
+ print('WARNING! Composition has more than 15 patches!')
4973
+ print('Conflict note number:', idx)
4974
+ print('Conflict channel number:', e[3])
4975
+ print('Conflict patch number:', e[6])
4976
 
4977
  patches = [p if p != -1 else default_patch for p in patches]
4978
 
 
5005
  overflow_idx = -1
5006
 
5007
  for idx, e in enumerate(enhanced_score_notes):
5008
+ if e[0] == 'note':
5009
+ if e[3] != 9:
5010
+ if patches[e[3]] == -1:
5011
+ patches[e[3]] = e[6]
5012
+ else:
5013
+ if patches[e[3]] != e[6]:
5014
+ if e[6] in patches:
5015
+ e[3] = patches.index(e[6])
 
 
5016
  else:
5017
+ if -1 in patches:
5018
+ patches[patches.index(-1)] = e[6]
5019
+ else:
5020
+ overflow_idx = idx
5021
+ break
5022
 
5023
  enhanced_score_notes_with_patch_changes.append(e)
5024
 
 
5028
 
5029
  if overflow_idx != -1:
5030
  for idx, e in enumerate(enhanced_score_notes[overflow_idx:]):
5031
+ if e[0] == 'note':
5032
+ if e[3] != 9:
5033
+ if e[6] not in patches:
5034
+ if e[6] not in overflow_patches:
5035
+ overflow_patches.append(e[6])
5036
+ enhanced_score_notes_with_patch_changes.append(['patch_change', e[1], e[3], e[6]])
5037
+ else:
5038
+ e[3] = patches.index(e[6])
5039
 
5040
+ enhanced_score_notes_with_patch_changes.append(e)
5041
 
5042
  #===========================================================================
5043
 
 
5320
  melody_patch=40,
5321
  melody_max_velocity=110,
5322
  acc_max_velocity=90,
5323
+ pass_drums=True,
5324
+ return_melody=False
5325
  ):
5326
 
5327
  if pass_drums:
 
5399
 
5400
  adjust_score_velocities(smoothed_melody, melody_max_velocity)
5401
 
5402
+ if return_melody:
5403
+ final_score = sorted(smoothed_melody, key=lambda x: (x[1], -x[4]))
5404
+
5405
+ else:
5406
+ final_score = sorted(smoothed_melody + acc_score, key=lambda x: (x[1], -x[4]))
5407
 
5408
  return final_score
5409
 
 
5416
 
5417
  ###################################################################################
5418
 
5419
+ def recalculate_score_timings(score,
5420
+ start_time=0,
5421
+ timings_index=1
5422
+ ):
5423
 
5424
  rscore = copy.deepcopy(score)
5425
 
 
5429
 
5430
  for e in rscore:
5431
 
5432
+ dtime = e[timings_index] - pe[timings_index]
5433
  pe = copy.deepcopy(e)
5434
  abs_time += dtime
5435
+ e[timings_index] = abs_time
5436
 
5437
  return rscore
5438
 
 
6429
 
6430
  ###################################################################################
6431
 
6432
+ def reverse_enhanced_score_notes(escore_notes):
6433
+
6434
+ score = recalculate_score_timings(escore_notes)
6435
+
6436
+ ematrix = escore_notes_to_escore_matrix(score, reverse_matrix=True)
6437
+ e_score = escore_matrix_to_original_escore_notes(ematrix)
6438
 
6439
+ reversed_score = recalculate_score_timings(e_score)
6440
 
6441
+ return reversed_score
6442
 
6443
+ ###################################################################################
6444
 
6445
+ def count_patterns(lst, sublist):
6446
+ count = 0
6447
+ idx = 0
6448
+ for i in range(len(lst) - len(sublist) + 1):
6449
+ if lst[idx:idx + len(sublist)] == sublist:
6450
+ count += 1
6451
+ idx += len(sublist)
6452
+ else:
6453
+ idx += 1
6454
+ return count
6455
 
6456
+ ###################################################################################
 
6457
 
6458
+ def find_lrno_patterns(seq):
 
 
6459
 
6460
+ all_seqs = Counter()
6461
 
6462
+ max_pat_len = math.ceil(len(seq) / 2)
6463
 
6464
+ num_iter = 0
 
 
 
6465
 
6466
+ for i in range(len(seq)):
6467
+ for j in range(i+1, len(seq)+1):
6468
+ if j-i <= max_pat_len:
6469
+ all_seqs[tuple(seq[i:j])] += 1
6470
+ num_iter += 1
6471
+
6472
+ max_count = 0
6473
+ max_len = 0
6474
+
6475
+ for val, count in all_seqs.items():
6476
+
6477
+ if max_len < len(val):
6478
+ max_count = max(2, count)
6479
+
6480
+ if count > 1:
6481
+ max_len = max(max_len, len(val))
6482
+ pval = val
6483
+
6484
+ max_pats = []
6485
+
6486
+ for val, count in all_seqs.items():
6487
+ if count == max_count and len(val) == max_len:
6488
+ max_pats.append(val)
6489
+
6490
+ found_patterns = []
6491
+
6492
+ for pat in max_pats:
6493
+ count = count_patterns(seq, list(pat))
6494
+ if count > 1:
6495
+ found_patterns.append([count, len(pat), pat])
6496
+
6497
+ return found_patterns
6498
 
6499
  ###################################################################################
6500
 
6501
+ def delta_pitches(escore_notes, pitches_index=4):
6502
+
6503
+ pitches = [p[pitches_index] for p in escore_notes]
6504
+
6505
+ return [a-b for a, b in zip(pitches[:-1], pitches[1:])]
6506
+
6507
+ ###################################################################################
6508
+
6509
+ def split_list(lst, val):
6510
+ return [lst[i:j] for i, j in zip([0] + [k + 1 for k, x in enumerate(lst) if x == val], [k for k, x in enumerate(lst) if x == val] + [len(lst)]) if j > i]
6511
+
6512
+ ###################################################################################
6513
+
6514
+ def even_timings(escore_notes,
6515
+ times_idx=1,
6516
+ durs_idx=2
6517
+ ):
6518
+
6519
+ esn = copy.deepcopy(escore_notes)
6520
+
6521
+ for e in esn:
6522
+
6523
+ if e[times_idx] != 0:
6524
+ if e[times_idx] % 2 != 0:
6525
+ e[times_idx] += 1
6526
+
6527
+ if e[durs_idx] % 2 != 0:
6528
+ e[durs_idx] += 1
6529
+
6530
+ return esn
6531
+
6532
+ ###################################################################################
6533
+
6534
+ def delta_score_to_abs_score(delta_score_notes,
6535
+ times_idx=1
6536
+ ):
6537
+
6538
+ abs_score = copy.deepcopy(delta_score_notes)
6539
+
6540
+ abs_time = 0
6541
+
6542
+ for i, e in enumerate(delta_score_notes):
6543
+
6544
+ dtime = e[times_idx]
6545
+
6546
+ abs_time += dtime
6547
+
6548
+ abs_score[i][times_idx] = abs_time
6549
+
6550
+ return abs_score
6551
+
6552
+ ###################################################################################
6553
+
6554
+
6555
+ def adjust_numbers_to_sum(numbers, target_sum):
6556
+
6557
+ current_sum = sum(numbers)
6558
+ difference = target_sum - current_sum
6559
+
6560
+ non_zero_elements = [(i, num) for i, num in enumerate(numbers) if num != 0]
6561
+
6562
+ total_non_zero = sum(num for _, num in non_zero_elements)
6563
+
6564
+ increments = []
6565
+ for i, num in non_zero_elements:
6566
+ proportion = num / total_non_zero
6567
+ increment = proportion * difference
6568
+ increments.append(increment)
6569
+
6570
+ for idx, (i, num) in enumerate(non_zero_elements):
6571
+ numbers[i] += int(round(increments[idx]))
6572
+
6573
+ current_sum = sum(numbers)
6574
+ difference = target_sum - current_sum
6575
+ non_zero_indices = [i for i, num in enumerate(numbers) if num != 0]
6576
+
6577
+ for i in range(abs(difference)):
6578
+ numbers[non_zero_indices[i % len(non_zero_indices)]] += 1 if difference > 0 else -1
6579
+
6580
+ return numbers
6581
+
6582
+ ###################################################################################
6583
+
6584
+ def find_next_bar(escore_notes, bar_time, start_note_idx, cur_bar):
6585
+ for e in escore_notes[start_note_idx:]:
6586
+ if e[1] // bar_time > cur_bar:
6587
+ return e, escore_notes.index(e)
6588
+
6589
+ ###################################################################################
6590
+
6591
+ def align_escore_notes_to_bars(escore_notes,
6592
+ bar_time=4000,
6593
+ trim_durations=False,
6594
+ split_durations=False
6595
+ ):
6596
+
6597
+ #=============================================================================
6598
+
6599
+ aligned_escore_notes = copy.deepcopy(escore_notes)
6600
+
6601
+ abs_time = 0
6602
+ nidx = 0
6603
+ delta = 0
6604
+ bcount = 0
6605
+ next_bar = [0]
6606
+
6607
+ #=============================================================================
6608
+
6609
+ while next_bar:
6610
+
6611
+ next_bar = find_next_bar(escore_notes, bar_time, nidx, bcount)
6612
+
6613
+ if next_bar:
6614
+
6615
+ gescore_notes = escore_notes[nidx:next_bar[1]]
6616
+ else:
6617
+ gescore_notes = escore_notes[nidx:]
6618
+
6619
+ original_timings = [delta] + [(b[1]-a[1]) for a, b in zip(gescore_notes[:-1], gescore_notes[1:])]
6620
+ adj_timings = adjust_numbers_to_sum(original_timings, bar_time)
6621
+
6622
+ for t in adj_timings:
6623
+
6624
+ abs_time += t
6625
+
6626
+ aligned_escore_notes[nidx][1] = abs_time
6627
+ aligned_escore_notes[nidx][2] -= int(bar_time // 200)
6628
+
6629
+ nidx += 1
6630
+
6631
+ if next_bar:
6632
+ delta = escore_notes[next_bar[1]][1]-escore_notes[next_bar[1]-1][1]
6633
+ bcount += 1
6634
+
6635
+ #=============================================================================
6636
+
6637
+ aligned_adjusted_escore_notes = []
6638
+ bcount = 0
6639
+
6640
+ for a in aligned_escore_notes:
6641
+ bcount = a[1] // bar_time
6642
+ nbtime = bar_time * (bcount+1)
6643
+
6644
+ if a[1]+a[2] > nbtime and a[3] != 9:
6645
+ if trim_durations or split_durations:
6646
+ ddiff = ((a[1]+a[2])-nbtime)
6647
+ aa = copy.deepcopy(a)
6648
+ aa[2] = a[2] - ddiff
6649
+ aligned_adjusted_escore_notes.append(aa)
6650
+
6651
+ if split_durations:
6652
+ aaa = copy.deepcopy(a)
6653
+ aaa[1] = a[1]+aa[2]
6654
+ aaa[2] = ddiff
6655
+
6656
+ aligned_adjusted_escore_notes.append(aaa)
6657
+
6658
+ else:
6659
+ aligned_adjusted_escore_notes.append(a)
6660
+
6661
+ else:
6662
+ aligned_adjusted_escore_notes.append(a)
6663
+
6664
+ #=============================================================================
6665
+
6666
+ return aligned_adjusted_escore_notes
6667
+
6668
+ ###################################################################################
6669
+
6670
+ def normalize_chord_durations(chord,
6671
+ dur_idx=2,
6672
+ norm_factor=100
6673
+ ):
6674
+
6675
+ nchord = copy.deepcopy(chord)
6676
+
6677
+ for c in nchord:
6678
+ c[dur_idx] = int(round(max(1 / norm_factor, c[dur_idx] // norm_factor) * norm_factor))
6679
+
6680
+ return nchord
6681
+
6682
+ ###################################################################################
6683
+
6684
+ def normalize_chordified_score_durations(chordified_score,
6685
+ dur_idx=2,
6686
+ norm_factor=100
6687
+ ):
6688
+
6689
+ ncscore = copy.deepcopy(chordified_score)
6690
+
6691
+ for cc in ncscore:
6692
+ for c in cc:
6693
+ c[dur_idx] = int(round(max(1 / norm_factor, c[dur_idx] // norm_factor) * norm_factor))
6694
+
6695
+ return ncscore
6696
+
6697
+ ###################################################################################
6698
+
6699
+ def horizontal_ordered_list_search(list_of_lists,
6700
+ query_list,
6701
+ start_idx=0,
6702
+ end_idx=-1
6703
+ ):
6704
+
6705
+ lol = list_of_lists
6706
+
6707
+ results = []
6708
+
6709
+ if start_idx > 0:
6710
+ lol = list_of_lists[start_idx:]
6711
+
6712
+ if start_idx == -1:
6713
+ idx = -1
6714
+ for i, l in enumerate(list_of_lists):
6715
+ try:
6716
+ idx = l.index(query_list[0])
6717
+ lol = list_of_lists[i:]
6718
+ break
6719
+ except:
6720
+ continue
6721
+
6722
+ if idx == -1:
6723
+ results.append(-1)
6724
+ return results
6725
+ else:
6726
+ results.append(i)
6727
+
6728
+ if end_idx != -1:
6729
+ lol = list_of_lists[start_idx:start_idx+max(end_idx, len(query_list))]
6730
+
6731
+ for i, q in enumerate(query_list):
6732
+ try:
6733
+ idx = lol[i].index(q)
6734
+ results.append(idx)
6735
+ except:
6736
+ results.append(-1)
6737
+ return results
6738
+
6739
+ return results
6740
+
6741
+ ###################################################################################
6742
+
6743
+ def escore_notes_to_escore_matrix(escore_notes,
6744
+ alt_velocities=False,
6745
+ flip_matrix=False,
6746
+ reverse_matrix=False
6747
+ ):
6748
+
6749
+ last_time = escore_notes[-1][1]
6750
+ last_notes = [e for e in escore_notes if e[1] == last_time]
6751
+ max_last_dur = max([e[2] for e in last_notes])
6752
+
6753
+ time_range = last_time+max_last_dur
6754
+
6755
+ channels_list = sorted(set([e[3] for e in escore_notes]))
6756
+
6757
+ escore_matrixes = []
6758
+
6759
+ for cha in channels_list:
6760
+
6761
+ escore_matrix = [[[-1, -1]] * 128 for _ in range(time_range)]
6762
+
6763
+ pe = escore_notes[0]
6764
+
6765
+ for i, note in enumerate(escore_notes):
6766
+
6767
+ etype, time, duration, channel, pitch, velocity, patch = note
6768
+
6769
+ time = max(0, time)
6770
+ duration = max(1, duration)
6771
+ channel = max(0, min(15, channel))
6772
+ pitch = max(0, min(127, pitch))
6773
+ velocity = max(0, min(127, velocity))
6774
+ patch = max(0, min(128, patch))
6775
+
6776
+ if alt_velocities:
6777
+ velocity -= (i % 2)
6778
+
6779
+ if channel == cha:
6780
+
6781
+ for t in range(time, min(time + duration, time_range)):
6782
+
6783
+ escore_matrix[t][pitch] = [velocity, patch]
6784
+
6785
+ pe = note
6786
+
6787
+ if flip_matrix:
6788
+
6789
+ temp_matrix = []
6790
+
6791
+ for m in escore_matrix:
6792
+ temp_matrix.append(m[::-1])
6793
+
6794
+ escore_matrix = temp_matrix
6795
+
6796
+ if reverse_matrix:
6797
+ escore_matrix = escore_matrix[::-1]
6798
+
6799
+ escore_matrixes.append(escore_matrix)
6800
+
6801
+ return [channels_list, escore_matrixes]
6802
+
6803
+ ###################################################################################
6804
+
6805
+ def escore_matrix_to_merged_escore_notes(full_escore_matrix,
6806
+ max_note_duration=4000
6807
+ ):
6808
+
6809
+ merged_escore_notes = []
6810
+
6811
+ mat_channels_list = full_escore_matrix[0]
6812
+
6813
+ for m, cha in enumerate(mat_channels_list):
6814
+
6815
+ escore_matrix = full_escore_matrix[1][m]
6816
+
6817
+ result = []
6818
+
6819
+ for j in range(len(escore_matrix[0])):
6820
+
6821
+ count = 1
6822
+
6823
+ for i in range(1, len(escore_matrix)):
6824
+
6825
+ if escore_matrix[i][j] != [-1, -1] and escore_matrix[i][j][1] == escore_matrix[i-1][j][1] and count < max_note_duration:
6826
+ count += 1
6827
+
6828
+ else:
6829
+ if count > 1:
6830
+ result.append([i-count, count, j, escore_matrix[i-1][j]])
6831
+
6832
+ count = 1
6833
+
6834
+ if count > 1:
6835
+ result.append([len(escore_matrix)-count, count, j, escore_matrix[-1][j]])
6836
+
6837
+ result.sort(key=lambda x: (x[0], -x[2]))
6838
+
6839
+ for r in result:
6840
+ merged_escore_notes.append(['note', r[0], r[1], cha, r[2], r[3][0], r[3][1]])
6841
+
6842
+ return sorted(merged_escore_notes, key=lambda x: (x[1], -x[4], x[6]))
6843
+
6844
+ ###################################################################################
6845
+
6846
+ def escore_matrix_to_original_escore_notes(full_escore_matrix):
6847
+
6848
+ merged_escore_notes = []
6849
+
6850
+ mat_channels_list = full_escore_matrix[0]
6851
+
6852
+ for m, cha in enumerate(mat_channels_list):
6853
+
6854
+ escore_matrix = full_escore_matrix[1][m]
6855
+
6856
+ result = []
6857
+
6858
+ for j in range(len(escore_matrix[0])):
6859
+
6860
+ count = 1
6861
+
6862
+ for i in range(1, len(escore_matrix)):
6863
+
6864
+ if escore_matrix[i][j] != [-1, -1] and escore_matrix[i][j] == escore_matrix[i-1][j]:
6865
+ count += 1
6866
+
6867
+ else:
6868
+ if count > 1:
6869
+ result.append([i-count, count, j, escore_matrix[i-1][j]])
6870
+
6871
+ count = 1
6872
+
6873
+ if count > 1:
6874
+ result.append([len(escore_matrix)-count, count, j, escore_matrix[-1][j]])
6875
+
6876
+ result.sort(key=lambda x: (x[0], -x[2]))
6877
+
6878
+ for r in result:
6879
+ merged_escore_notes.append(['note', r[0], r[1], cha, r[2], r[3][0], r[3][1]])
6880
+
6881
+ return sorted(merged_escore_notes, key=lambda x: (x[1], -x[4], x[6]))
6882
+
6883
+ ###################################################################################
6884
+
6885
+ def escore_notes_to_binary_matrix(escore_notes,
6886
+ channel=0,
6887
+ patch=0,
6888
+ flip_matrix=False,
6889
+ reverse_matrix=False
6890
+ ):
6891
+
6892
+ escore = [e for e in escore_notes if e[3] == channel and e[6] == patch]
6893
+
6894
+ if escore:
6895
+ last_time = escore[-1][1]
6896
+ last_notes = [e for e in escore if e[1] == last_time]
6897
+ max_last_dur = max([e[2] for e in last_notes])
6898
+
6899
+ time_range = last_time+max_last_dur
6900
+
6901
+ escore_matrix = []
6902
+
6903
+ escore_matrix = [[0] * 128 for _ in range(time_range)]
6904
+
6905
+ for note in escore:
6906
+
6907
+ etype, time, duration, chan, pitch, velocity, pat = note
6908
+
6909
+ time = max(0, time)
6910
+ duration = max(1, duration)
6911
+ chan = max(0, min(15, chan))
6912
+ pitch = max(0, min(127, pitch))
6913
+ velocity = max(0, min(127, velocity))
6914
+ pat = max(0, min(128, pat))
6915
+
6916
+ if channel == chan and patch == pat:
6917
+
6918
+ for t in range(time, min(time + duration, time_range)):
6919
+
6920
+ escore_matrix[t][pitch] = 1
6921
 
6922
+ if flip_matrix:
6923
+
6924
+ temp_matrix = []
6925
+
6926
+ for m in escore_matrix:
6927
+ temp_matrix.append(m[::-1])
6928
+
6929
+ escore_matrix = temp_matrix
6930
+
6931
+ if reverse_matrix:
6932
+ escore_matrix = escore_matrix[::-1]
6933
+
6934
+ return escore_matrix
6935
+
6936
+ else:
6937
+ return None
6938
+
6939
+ ###################################################################################
6940
+
6941
+ def binary_matrix_to_original_escore_notes(binary_matrix,
6942
+ channel=0,
6943
+ patch=0,
6944
+ velocity=-1
6945
+ ):
6946
+
6947
+ result = []
6948
+
6949
+ for j in range(len(binary_matrix[0])):
6950
+
6951
+ count = 1
6952
+
6953
+ for i in range(1, len(binary_matrix)):
6954
+
6955
+ if binary_matrix[i][j] != 0 and binary_matrix[i][j] == binary_matrix[i-1][j]:
6956
+ count += 1
6957
+
6958
+ else:
6959
+ if count > 1:
6960
+ result.append([i-count, count, j, binary_matrix[i-1][j]])
6961
+
6962
+ else:
6963
+ if binary_matrix[i-1][j] != 0:
6964
+ result.append([i-count, count, j, binary_matrix[i-1][j]])
6965
+
6966
+ count = 1
6967
+
6968
+ if count > 1:
6969
+ result.append([len(binary_matrix)-count, count, j, binary_matrix[-1][j]])
6970
+
6971
+ else:
6972
+ if binary_matrix[i-1][j] != 0:
6973
+ result.append([i-count, count, j, binary_matrix[i-1][j]])
6974
+
6975
+ result.sort(key=lambda x: (x[0], -x[2]))
6976
+
6977
+ original_escore_notes = []
6978
+
6979
+ vel = velocity
6980
+
6981
+ for r in result:
6982
+
6983
+ if velocity == -1:
6984
+ vel = max(40, r[2])
6985
+
6986
+ original_escore_notes.append(['note', r[0], r[1], channel, r[2], vel, patch])
6987
+
6988
+ return sorted(original_escore_notes, key=lambda x: (x[1], -x[4], x[6]))
6989
+
6990
+ ###################################################################################
6991
+
6992
+ def escore_notes_averages(escore_notes,
6993
+ times_index=1,
6994
+ durs_index=2,
6995
+ chans_index=3,
6996
+ ptcs_index=4,
6997
+ vels_index=5,
6998
+ average_drums=False,
6999
+ score_is_delta=False,
7000
+ return_ptcs_and_vels=False
7001
+ ):
7002
+
7003
+ if score_is_delta:
7004
+ if average_drums:
7005
+ times = [e[times_index] for e in escore_notes if e[times_index] != 0]
7006
+ else:
7007
+ times = [e[times_index] for e in escore_notes if e[times_index] != 0 and e[chans_index] != 9]
7008
+
7009
+ else:
7010
+ descore_notes = delta_score_notes(escore_notes)
7011
+ if average_drums:
7012
+ times = [e[times_index] for e in descore_notes if e[times_index] != 0]
7013
+ else:
7014
+ times = [e[times_index] for e in descore_notes if e[times_index] != 0 and e[chans_index] != 9]
7015
+
7016
+ if average_drums:
7017
+ durs = [e[durs_index] for e in escore_notes]
7018
+ else:
7019
+ durs = [e[durs_index] for e in escore_notes if e[chans_index] != 9]
7020
+
7021
+ if return_ptcs_and_vels:
7022
+ if average_drums:
7023
+ ptcs = [e[ptcs_index] for e in escore_notes]
7024
+ vels = [e[vels_index] for e in escore_notes]
7025
+ else:
7026
+ ptcs = [e[ptcs_index] for e in escore_notes if e[chans_index] != 9]
7027
+ vels = [e[vels_index] for e in escore_notes if e[chans_index] != 9]
7028
+
7029
+ return [sum(times) / len(times), sum(durs) / len(durs), sum(ptcs) / len(ptcs), sum(vels) / len(vels)]
7030
+
7031
+ else:
7032
+ return [sum(times) / len(times), sum(durs) / len(durs)]
7033
+
7034
+ ###################################################################################
7035
+
7036
+ def adjust_escore_notes_timings(escore_notes,
7037
+ adj_k=1,
7038
+ times_index=1,
7039
+ durs_index=2,
7040
+ score_is_delta=False,
7041
+ return_delta_scpre=False
7042
+ ):
7043
+
7044
+ if score_is_delta:
7045
+ adj_escore_notes = copy.deepcopy(escore_notes)
7046
+ else:
7047
+ adj_escore_notes = delta_score_notes(escore_notes)
7048
+
7049
+ for e in adj_escore_notes:
7050
+
7051
+ if e[times_index] != 0:
7052
+ e[times_index] = max(1, round(e[times_index] * adj_k))
7053
+
7054
+ e[durs_index] = max(1, round(e[durs_index] * adj_k))
7055
+
7056
+ if return_delta_scpre:
7057
+ return adj_escore_notes
7058
+
7059
+ else:
7060
+ return delta_score_to_abs_score(adj_escore_notes)
7061
+
7062
+ ###################################################################################
7063
+
7064
+ def escore_notes_delta_times(escore_notes,
7065
+ times_index=1
7066
+ ):
7067
+
7068
+ descore_notes = delta_score_notes(escore_notes)
7069
+
7070
+ return [e[times_index] for e in descore_notes]
7071
+
7072
+ ###################################################################################
7073
+
7074
+ def escore_notes_durations(escore_notes,
7075
+ durs_index=1
7076
+ ):
7077
+
7078
+ descore_notes = delta_score_notes(escore_notes)
7079
+
7080
+ return [e[durs_index] for e in descore_notes]
7081
+
7082
+ ###################################################################################
7083
+
7084
+ def ordered_lists_match_ratio(src_list, trg_list):
7085
+
7086
+ zlist = list(zip(src_list, trg_list))
7087
+
7088
+ return sum([a == b for a, b in zlist]) / len(list(zlist))
7089
+
7090
+ ###################################################################################
7091
+
7092
+ def lists_intersections(src_list, trg_list):
7093
+ return list(set(src_list) & set(trg_list))
7094
+
7095
+ ###################################################################################
7096
+
7097
+ def transpose_escore_notes(escore_notes,
7098
+ transpose_value=0,
7099
+ channel_index=3,
7100
+ pitches_index=4
7101
+ ):
7102
+
7103
+ tr_escore_notes = copy.deepcopy(escore_notes)
7104
+
7105
+ for e in tr_escore_notes:
7106
+ if e[channel_index] != 9:
7107
+ e[pitches_index] = max(1, min(127, e[pitches_index] + transpose_value))
7108
+
7109
+ return tr_escore_notes
7110
+
7111
+ ###################################################################################
7112
+
7113
+ def transpose_escore_notes_to_pitch(escore_notes,
7114
+ target_pitch_value=60,
7115
+ channel_index=3,
7116
+ pitches_index=4
7117
+ ):
7118
+
7119
+ tr_escore_notes = copy.deepcopy(escore_notes)
7120
+
7121
+ transpose_delta = int(round(target_pitch_value)) - int(round(escore_notes_averages(escore_notes, return_ptcs_and_vels=True)[2]))
7122
+
7123
+ for e in tr_escore_notes:
7124
+ if e[channel_index] != 9:
7125
+ e[pitches_index] = max(1, min(127, e[pitches_index] + transpose_delta))
7126
+
7127
+ return tr_escore_notes
7128
+
7129
+ ###################################################################################
7130
+
7131
+ CHORDS_TYPES = ['WHITE', 'BLACK', 'UNKNOWN', 'MIXED WHITE', 'MIXED BLACK', 'MIXED GRAY']
7132
+
7133
+ ###################################################################################
7134
+
7135
+ def tones_chord_type(tones_chord,
7136
+ return_chord_type_index=True,
7137
+ use_filtered_chords=True
7138
+ ):
7139
+
7140
+ WN = WHITE_NOTES
7141
+ BN = BLACK_NOTES
7142
+ MX = WHITE_NOTES + BLACK_NOTES
7143
+
7144
+ if use_filtered_chords:
7145
+ CHORDS = ALL_CHORDS_FILTERED
7146
+
7147
+ else:
7148
+ CHORDS = ALL_CHORDS_SORTED
7149
+
7150
+ tones_chord = sorted(tones_chord)
7151
+
7152
+ ctype = 'UNKNOWN'
7153
+
7154
+ if tones_chord in CHORDS:
7155
+
7156
+ if sorted(set(tones_chord) & set(WN)) == tones_chord:
7157
+ ctype = 'WHITE'
7158
+
7159
+ elif sorted(set(tones_chord) & set(BN)) == tones_chord:
7160
+ ctype = 'BLACK'
7161
+
7162
+ if len(tones_chord) > 1 and sorted(set(tones_chord) & set(MX)) == tones_chord:
7163
+
7164
+ if len(sorted(set(tones_chord) & set(WN))) == len(sorted(set(tones_chord) & set(BN))):
7165
+ ctype = 'MIXED GRAY'
7166
+
7167
+ elif len(sorted(set(tones_chord) & set(WN))) > len(sorted(set(tones_chord) & set(BN))):
7168
+ ctype = 'MIXED WHITE'
7169
+
7170
+ elif len(sorted(set(tones_chord) & set(WN))) < len(sorted(set(tones_chord) & set(BN))):
7171
+ ctype = 'MIXED BLACK'
7172
+
7173
+ if return_chord_type_index:
7174
+ return CHORDS_TYPES.index(ctype)
7175
+
7176
+ else:
7177
+ return ctype
7178
+
7179
+ ###################################################################################
7180
+
7181
+ def tone_type(tone,
7182
+ return_tone_type_index=True
7183
+ ):
7184
+
7185
+ tone = tone % 12
7186
+
7187
+ if tone in BLACK_NOTES:
7188
+ if return_tone_type_index:
7189
+ return CHORDS_TYPES.index('BLACK')
7190
+ else:
7191
+ return "BLACK"
7192
+
7193
+ else:
7194
+ if return_tone_type_index:
7195
+ return CHORDS_TYPES.index('WHITE')
7196
+ else:
7197
+ return "WHITE"
7198
+
7199
+ ###################################################################################
7200
+
7201
+ def lists_sym_differences(src_list, trg_list):
7202
+ return list(set(src_list) ^ set(trg_list))
7203
+
7204
+ ###################################################################################
7205
+
7206
+ def lists_differences(long_list, short_list):
7207
+ return list(set(long_list) - set(short_list))
7208
+
7209
+ ###################################################################################
7210
+
7211
+ def find_best_tones_chord(src_tones_chords,
7212
+ trg_tones_chords,
7213
+ find_longest=True
7214
+ ):
7215
+
7216
+ not_seen_trg_chords = []
7217
+
7218
+ max_len = 0
7219
+
7220
+ for tc in trg_tones_chords:
7221
+ if sorted(tc) in src_tones_chords:
7222
+ not_seen_trg_chords.append(sorted(tc))
7223
+ max_len = max(max_len, len(tc))
7224
+
7225
+ if not not_seen_trg_chords:
7226
+ max_len = len(max(trg_tones_chords, key=len))
7227
+ not_seen_trg_chords = trg_tones_chords
7228
+
7229
+ if find_longest:
7230
+ return random.choice([c for c in not_seen_trg_chords if len(c) == max_len])
7231
+
7232
+ else:
7233
+ return random.choice(not_seen_trg_chords)
7234
+
7235
+ ###################################################################################
7236
+
7237
+ def find_matching_tones_chords(tones_chord,
7238
+ matching_chord_length=-1,
7239
+ match_chord_type=True,
7240
+ use_filtered_chords=True
7241
+ ):
7242
+
7243
+ if use_filtered_chords:
7244
+ CHORDS = ALL_CHORDS_FILTERED
7245
+ else:
7246
+ CHORDS = ALL_CHORDS_SORTED
7247
+
7248
+ tones_chord = sorted(tones_chord)
7249
+
7250
+ tclen = len(tones_chord)
7251
+
7252
+ tctype = tones_chord_type(tones_chord, use_filtered_chords=use_filtered_chords)
7253
+
7254
+ matches = []
7255
+
7256
+ for tc in CHORDS:
7257
+
7258
+ if matching_chord_length == -1:
7259
+ if len(tc) > tclen:
7260
+ if sorted(lists_intersections(tc, tones_chord)) == tones_chord:
7261
+ if match_chord_type:
7262
+ if tones_chord_type(tc, use_filtered_chords=use_filtered_chords) == tctype:
7263
+ tcdiffs = lists_differences(tc, tones_chord)
7264
+ if all(tone_type(d) == tctype % 3 for d in tcdiffs):
7265
+ matches.append(tc)
7266
+ else:
7267
+ matches.append(tc)
7268
+
7269
+ else:
7270
+
7271
+ if len(tc) == max(tclen, matching_chord_length):
7272
+ if sorted(lists_intersections(tc, tones_chord)) == tones_chord:
7273
+ if match_chord_type:
7274
+ if tones_chord_type(tc, use_filtered_chords=use_filtered_chords) == tctype:
7275
+ tcdiffs = lists_differences(tc, tones_chord)
7276
+ if all(tone_type(d) == tctype % 3 for d in tcdiffs):
7277
+ matches.append(tc)
7278
+ else:
7279
+ matches.append(tc)
7280
+
7281
+ return sorted(matches, key=len)
7282
+
7283
+ ###################################################################################
7284
+
7285
+ def adjust_list_of_values_to_target_average(list_of_values,
7286
+ trg_avg,
7287
+ min_value,
7288
+ max_value
7289
+ ):
7290
+
7291
+ filtered_values = [value for value in list_of_values if min_value <= value <= max_value]
7292
+
7293
+ if not filtered_values:
7294
+ return list_of_values
7295
+
7296
+ current_avg = sum(filtered_values) / len(filtered_values)
7297
+ scale_factor = trg_avg / current_avg
7298
+
7299
+ adjusted_values = [value * scale_factor for value in filtered_values]
7300
+
7301
+ total_difference = trg_avg * len(filtered_values) - sum(adjusted_values)
7302
+ adjustment_per_value = total_difference / len(filtered_values)
7303
+
7304
+ final_values = [value + adjustment_per_value for value in adjusted_values]
7305
+
7306
+ while abs(sum(final_values) / len(final_values) - trg_avg) > 1e-6:
7307
+ total_difference = trg_avg * len(final_values) - sum(final_values)
7308
+ adjustment_per_value = total_difference / len(final_values)
7309
+ final_values = [value + adjustment_per_value for value in final_values]
7310
+
7311
+ final_values = [round(value) for value in final_values]
7312
+
7313
+ adjusted_values = copy.deepcopy(list_of_values)
7314
+
7315
+ j = 0
7316
+
7317
+ for i in range(len(adjusted_values)):
7318
+ if min_value <= adjusted_values[i] <= max_value:
7319
+ adjusted_values[i] = final_values[j]
7320
+ j += 1
7321
+
7322
+ return adjusted_values
7323
+
7324
+ ###################################################################################
7325
+
7326
+ def adjust_escore_notes_to_average(escore_notes,
7327
+ trg_avg,
7328
+ min_value=1,
7329
+ max_value=4000,
7330
+ times_index=1,
7331
+ durs_index=2,
7332
+ score_is_delta=False,
7333
+ return_delta_scpre=False
7334
+ ):
7335
+ if score_is_delta:
7336
+ delta_escore_notes = copy.deepcopy(escore_notes)
7337
+
7338
+ else:
7339
+ delta_escore_notes = delta_score_notes(escore_notes)
7340
+
7341
+ times = [[e[times_index], e[durs_index]] for e in delta_escore_notes]
7342
+
7343
+ filtered_values = [value for value in times if min_value <= value[0] <= max_value]
7344
+
7345
+ if not filtered_values:
7346
+ return escore_notes
7347
+
7348
+ current_avg = sum([v[0] for v in filtered_values]) / len([v[0] for v in filtered_values])
7349
+ scale_factor = trg_avg / current_avg
7350
+
7351
+ adjusted_values = [[value[0] * scale_factor, value[1] * scale_factor] for value in filtered_values]
7352
+
7353
+ total_difference = trg_avg * len([v[0] for v in filtered_values]) - sum([v[0] for v in adjusted_values])
7354
+ adjustment_per_value = total_difference / len(filtered_values)
7355
+
7356
+ final_values = [[value[0] + adjustment_per_value, value[1] + adjustment_per_value] for value in adjusted_values]
7357
+
7358
+ while abs(sum([v[0] for v in final_values]) / len(final_values) - trg_avg) > 1e-6:
7359
+ total_difference = trg_avg * len(final_values) - sum([v[0] for v in final_values])
7360
+ adjustment_per_value = total_difference / len(final_values)
7361
+ final_values = [[value[0] + adjustment_per_value, value[1] + adjustment_per_value] for value in final_values]
7362
+
7363
+ final_values = [[round(value[0]), round(value[1])] for value in final_values]
7364
+
7365
+ adjusted_delta_score = copy.deepcopy(delta_escore_notes)
7366
+
7367
+ j = 0
7368
+
7369
+ for i in range(len(adjusted_delta_score)):
7370
+ if min_value <= adjusted_delta_score[i][1] <= max_value:
7371
+ adjusted_delta_score[i][times_index] = final_values[j][0]
7372
+ adjusted_delta_score[i][durs_index] = final_values[j][1]
7373
+ j += 1
7374
+
7375
+ adjusted_escore_notes = delta_score_to_abs_score(adjusted_delta_score)
7376
+
7377
+ if return_delta_scpre:
7378
+ return adjusted_delta_score
7379
+
7380
+ else:
7381
+ return adjusted_escore_notes
7382
+
7383
+ ###################################################################################
7384
+
7385
+ def harmonize_enhanced_melody_score_notes_to_ms_SONG(escore_notes,
7386
+ melody_velocity=-1,
7387
+ melody_channel=3,
7388
+ melody_patch=40,
7389
+ melody_base_octave=4,
7390
+ harmonized_tones_chords_velocity=-1,
7391
+ harmonized_tones_chords_channel=0,
7392
+ harmonized_tones_chords_patch=0
7393
+ ):
7394
+
7395
+ harmonized_tones_chords = harmonize_enhanced_melody_score_notes(escore_notes)
7396
+
7397
+ harm_escore_notes = []
7398
+
7399
+ time = 0
7400
+
7401
+ for i, note in enumerate(escore_notes):
7402
+
7403
+ time = note[1]
7404
+ dur = note[2]
7405
+ ptc = note[4]
7406
+
7407
+ if melody_velocity == -1:
7408
+ vel = int(110 + ((ptc % 12) * 1.5))
7409
+ else:
7410
+ vel = melody_velocity
7411
+
7412
+ harm_escore_notes.append(['note', time, dur, melody_channel, ptc, vel, melody_patch])
7413
+
7414
+ for t in harmonized_tones_chords[i]:
7415
+
7416
+ ptc = (melody_base_octave * 12) + t
7417
+
7418
+ if harmonized_tones_chords_velocity == -1:
7419
+ vel = int(80 + ((ptc % 12) * 1.5))
7420
+ else:
7421
+ vel = harmonized_tones_chords_velocity
7422
+
7423
+ harm_escore_notes.append(['note', time, dur, harmonized_tones_chords_channel, ptc, vel, harmonized_tones_chords_patch])
7424
+
7425
+ return sorted(harm_escore_notes, key=lambda x: (x[1], -x[4], x[6]))
7426
+
7427
+ ###################################################################################
7428
+
7429
+ def check_and_fix_pitches_chord(pitches_chord,
7430
+ use_filtered_chords=True
7431
+ ):
7432
+
7433
+ pitches_chord = sorted(pitches_chord, reverse=True)
7434
+
7435
+ if use_filtered_chords:
7436
+ CHORDS = ALL_CHORDS_FILTERED
7437
+ else:
7438
+ CHORDS = ALL_CHORDS_SORTED
7439
+
7440
+ tones_chord = sorted(set([p % 12 for p in pitches_chord]))
7441
+
7442
+ if tones_chord not in CHORDS:
7443
+
7444
+ if len(tones_chord) == 2:
7445
+
7446
+ tones_counts = Counter([p % 12 for p in pitches_chord]).most_common()
7447
+
7448
+ if tones_counts[0][1] > 1:
7449
+ tones_chord = [tones_counts[0][0]]
7450
+ elif tones_counts[1][1] > 1:
7451
+ tones_chord = [tones_counts[1][0]]
7452
+ else:
7453
+ tones_chord = [pitches_chord[0] % 12]
7454
+
7455
+ if len(tones_chord) > 2:
7456
+
7457
+ tones_chord_combs = [list(comb) for i in range(len(tones_chord)-2, 0, -1) for comb in combinations(tones_chord, i+1)]
7458
+
7459
+ for co in tones_chord_combs:
7460
+ if co in CHORDS:
7461
+ tones_chord = co
7462
+ break
7463
+
7464
+ new_pitches_chord = []
7465
+
7466
+ for p in pitches_chord:
7467
+
7468
+ if p % 12 in tones_chord:
7469
+ new_pitches_chord.append(p)
7470
+
7471
+ return sorted(new_pitches_chord, reverse=True)
7472
+
7473
+ ###################################################################################
7474
+
7475
+ ALL_CHORDS_TRANS = [[0], [0, 4], [0, 4, 7], [0, 4, 8], [0, 5], [0, 6], [0, 7], [0, 8], [1], [1, 5],
7476
+ [1, 5, 9], [1, 6], [1, 7], [1, 8], [1, 9], [2], [2, 6], [2, 6, 10], [2, 7],
7477
+ [2, 8], [2, 9], [2, 10], [3], [3, 7], [3, 7, 11], [3, 8], [3, 9], [3, 10],
7478
+ [3, 11], [4], [4, 7], [4, 7, 11], [4, 8], [4, 9], [4, 10], [4, 11], [5],
7479
+ [5, 9], [5, 10], [5, 11], [6], [6, 10], [6, 11], [7], [7, 11], [8], [9], [10],
7480
+ [11]]
7481
+
7482
+ ###################################################################################
7483
+
7484
+ def minkowski_distance(x, y, p=3, pad_value=float('inf')):
7485
+
7486
+ if len(x) != len(y):
7487
+ return -1
7488
+
7489
+ distance = 0
7490
+
7491
+ for i in range(len(x)):
7492
+
7493
+ if x[i] == pad_value or y[i] == pad_value:
7494
+ continue
7495
+
7496
+ distance += abs(x[i] - y[i]) ** p
7497
+
7498
+ return distance ** (1 / p)
7499
+
7500
+ ###################################################################################
7501
+
7502
+ def dot_product(x, y, pad_value=None):
7503
+ return sum(xi * yi for xi, yi in zip(x, y) if xi != pad_value and yi != pad_value)
7504
+
7505
+ def norm(vector, pad_value=None):
7506
+ return sum(xi ** 2 for xi in vector if xi != pad_value) ** 0.5
7507
+
7508
+ def cosine_similarity(x, y, pad_value=None):
7509
+ if len(x) != len(y):
7510
+ return -1
7511
+
7512
+ dot_prod = dot_product(x, y, pad_value)
7513
+ norm_x = norm(x, pad_value)
7514
+ norm_y = norm(y, pad_value)
7515
+
7516
+ if norm_x == 0 or norm_y == 0:
7517
+ return 0.0
7518
+
7519
+ return dot_prod / (norm_x * norm_y)
7520
+
7521
+ ###################################################################################
7522
+
7523
+ def hamming_distance(arr1, arr2, pad_value):
7524
+ return sum(el1 != el2 for el1, el2 in zip(arr1, arr2) if el1 != pad_value and el2 != pad_value)
7525
+
7526
+ ###################################################################################
7527
+
7528
+ def jaccard_similarity(arr1, arr2, pad_value):
7529
+ intersection = sum(el1 and el2 for el1, el2 in zip(arr1, arr2) if el1 != pad_value and el2 != pad_value)
7530
+ union = sum((el1 or el2) for el1, el2 in zip(arr1, arr2) if el1 != pad_value or el2 != pad_value)
7531
+ return intersection / union if union != 0 else 0
7532
+
7533
+ ###################################################################################
7534
+
7535
+ def pearson_correlation(arr1, arr2, pad_value):
7536
+ filtered_pairs = [(el1, el2) for el1, el2 in zip(arr1, arr2) if el1 != pad_value and el2 != pad_value]
7537
+ if not filtered_pairs:
7538
+ return 0
7539
+ n = len(filtered_pairs)
7540
+ sum1 = sum(el1 for el1, el2 in filtered_pairs)
7541
+ sum2 = sum(el2 for el1, el2 in filtered_pairs)
7542
+ sum1_sq = sum(el1 ** 2 for el1, el2 in filtered_pairs)
7543
+ sum2_sq = sum(el2 ** 2 for el1, el2 in filtered_pairs)
7544
+ p_sum = sum(el1 * el2 for el1, el2 in filtered_pairs)
7545
+ num = p_sum - (sum1 * sum2 / n)
7546
+ den = ((sum1_sq - sum1 ** 2 / n) * (sum2_sq - sum2 ** 2 / n)) ** 0.5
7547
+ if den == 0:
7548
+ return 0
7549
+ return num / den
7550
+
7551
+ ###################################################################################
7552
+
7553
+ def calculate_combined_distances(array_of_arrays,
7554
+ combine_hamming_distance=True,
7555
+ combine_jaccard_similarity=True,
7556
+ combine_pearson_correlation=True,
7557
+ pad_value=None
7558
+ ):
7559
+
7560
+ binary_arrays = array_of_arrays
7561
+ binary_array_len = len(binary_arrays)
7562
+
7563
+ hamming_distances = [[0] * binary_array_len for _ in range(binary_array_len)]
7564
+ jaccard_similarities = [[0] * binary_array_len for _ in range(binary_array_len)]
7565
+ pearson_correlations = [[0] * binary_array_len for _ in range(binary_array_len)]
7566
+
7567
+ for i in range(binary_array_len):
7568
+ for j in range(i + 1, binary_array_len):
7569
+ hamming_distances[i][j] = hamming_distance(binary_arrays[i], binary_arrays[j], pad_value)
7570
+ hamming_distances[j][i] = hamming_distances[i][j]
7571
+
7572
+ jaccard_similarities[i][j] = jaccard_similarity(binary_arrays[i], binary_arrays[j], pad_value)
7573
+ jaccard_similarities[j][i] = jaccard_similarities[i][j]
7574
+
7575
+ pearson_correlations[i][j] = pearson_correlation(binary_arrays[i], binary_arrays[j], pad_value)
7576
+ pearson_correlations[j][i] = pearson_correlations[i][j]
7577
+
7578
+ max_hamming = max(max(row) for row in hamming_distances)
7579
+ min_hamming = min(min(row) for row in hamming_distances)
7580
+ normalized_hamming = [[(val - min_hamming) / (max_hamming - min_hamming) for val in row] for row in hamming_distances]
7581
+
7582
+ max_jaccard = max(max(row) for row in jaccard_similarities)
7583
+ min_jaccard = min(min(row) for row in jaccard_similarities)
7584
+ normalized_jaccard = [[(val - min_jaccard) / (max_jaccard - min_jaccard) for val in row] for row in jaccard_similarities]
7585
+
7586
+ max_pearson = max(max(row) for row in pearson_correlations)
7587
+ min_pearson = min(min(row) for row in pearson_correlations)
7588
+ normalized_pearson = [[(val - min_pearson) / (max_pearson - min_pearson) for val in row] for row in pearson_correlations]
7589
+
7590
+ selected_metrics = 0
7591
+
7592
+ if combine_hamming_distance:
7593
+ selected_metrics += normalized_hamming[i][j]
7594
+
7595
+ if combine_jaccard_similarity:
7596
+ selected_metrics += (1 - normalized_jaccard[i][j])
7597
+
7598
+ if combine_pearson_correlation:
7599
+ selected_metrics += (1 - normalized_pearson[i][j])
7600
+
7601
+ combined_metric = [[selected_metrics for i in range(binary_array_len)] for j in range(binary_array_len)]
7602
+
7603
+ return combined_metric
7604
+
7605
+ ###################################################################################
7606
+
7607
+ def tones_chords_to_bits(tones_chords):
7608
+
7609
+ bits_tones_chords = []
7610
+
7611
+ for c in tones_chords:
7612
+
7613
+ c.sort()
7614
+
7615
+ bits = tones_chord_to_bits(c)
7616
+
7617
+ bits_tones_chords.append(bits)
7618
+
7619
+ return bits_tones_chords
7620
+
7621
+ ###################################################################################
7622
+
7623
+ def tones_chords_to_ints(tones_chords):
7624
+
7625
+ ints_tones_chords = []
7626
+
7627
+ for c in tones_chords:
7628
+
7629
+ c.sort()
7630
+
7631
+ bits = tones_chord_to_bits(c)
7632
+
7633
+ number = bits_to_int(bits)
7634
+
7635
+ ints_tones_chords.append(number)
7636
+
7637
+ return ints_tones_chords
7638
+
7639
+ ###################################################################################
7640
+
7641
+ def tones_chords_to_types(tones_chords,
7642
+ return_chord_type_index=False
7643
+ ):
7644
+
7645
+ types_tones_chords = []
7646
+
7647
+ for c in tones_chords:
7648
+
7649
+ c.sort()
7650
+
7651
+ ctype = tones_chord_type(c, return_chord_type_index=return_chord_type_index)
7652
+
7653
+ types_tones_chords.append(ctype)
7654
+
7655
+ return types_tones_chords
7656
+
7657
+ ###################################################################################
7658
+
7659
+ def morph_tones_chord(tones_chord,
7660
+ trg_tone,
7661
+ use_filtered_chords=True
7662
+ ):
7663
+
7664
+ src_tones_chord = sorted(sorted(set(tones_chord)) + [trg_tone])
7665
+
7666
+ combs = [list(comb) for i in range(len(src_tones_chord), 0, -1) for comb in combinations(src_tones_chord, i) if trg_tone in list(comb)]
7667
+
7668
+ matches = []
7669
+
7670
+ if use_filtered_chords:
7671
+ CHORDS = ALL_CHORDS_FILTERED
7672
+
7673
+ else:
7674
+ CHORDS = ALL_CHORDS_SORTED
7675
+
7676
+ for c in combs:
7677
+ if sorted(set(c)) in CHORDS:
7678
+ matches.append(sorted(set(c)))
7679
+
7680
+ max_len = len(max(matches, key=len))
7681
+
7682
+ return random.choice([m for m in matches if len(m) == max_len])
7683
+
7684
+ ###################################################################################
7685
+
7686
+ def compress_binary_matrix(binary_matrix,
7687
+ only_compress_zeros=False,
7688
+ return_compression_ratio=False
7689
+ ):
7690
+
7691
+ compressed_bmatrix = []
7692
+
7693
+ zm = [0] * len(binary_matrix[0])
7694
+ pm = [0] * len(binary_matrix[0])
7695
+
7696
+ mcount = 0
7697
+
7698
+ for m in binary_matrix:
7699
+
7700
+ if only_compress_zeros:
7701
+ if m != zm:
7702
+ compressed_bmatrix.append(m)
7703
+ mcount += 1
7704
+
7705
+ else:
7706
+ if m != pm:
7707
+ compressed_bmatrix.append(m)
7708
+ mcount += 1
7709
+
7710
+ pm = m
7711
+
7712
+ if return_compression_ratio:
7713
+ return [compressed_bmatrix, mcount / len(binary_matrix)]
7714
+
7715
+ else:
7716
+ return compressed_bmatrix
7717
+
7718
+ ###################################################################################
7719
+
7720
+ def solo_piano_escore_notes(escore_notes,
7721
+ channels_index=3,
7722
+ pitches_index=4,
7723
+ patches_index=6,
7724
+ keep_drums=False,
7725
+ ):
7726
+
7727
+ cscore = chordify_score([1000, escore_notes])
7728
+
7729
+ sp_escore_notes = []
7730
+
7731
+ for c in cscore:
7732
+
7733
+ seen = []
7734
+ chord = []
7735
+
7736
+ for cc in c:
7737
+ if cc[pitches_index] not in seen:
7738
+
7739
+ if cc[channels_index] != 9:
7740
+ cc[channels_index] = 0
7741
+ cc[patches_index] = 0
7742
+
7743
+ chord.append(cc)
7744
+ seen.append(cc[pitches_index])
7745
+
7746
+ else:
7747
+ if keep_drums:
7748
+ chord.append(cc)
7749
+ seen.append(cc[pitches_index])
7750
+
7751
+ sp_escore_notes.append(chord)
7752
+
7753
+ return flatten(sp_escore_notes)
7754
+
7755
+ ###################################################################################
7756
+
7757
+ def strip_drums_from_escore_notes(escore_notes,
7758
+ channels_index=3
7759
+ ):
7760
+
7761
+ return [e for e in escore_notes if e[channels_index] != 9]
7762
+
7763
+ ###################################################################################
7764
+
7765
+ def fixed_escore_notes_timings(escore_notes,
7766
+ fixed_durations=False,
7767
+ fixed_timings_multiplier=1,
7768
+ custom_fixed_time=-1,
7769
+ custom_fixed_dur=-1
7770
+ ):
7771
+
7772
+ fixed_timings_escore_notes = delta_score_notes(escore_notes, even_timings=True)
7773
+
7774
+ mode_time = round(Counter([e[1] for e in fixed_timings_escore_notes if e[1] != 0]).most_common()[0][0] * fixed_timings_multiplier)
7775
+
7776
+ if mode_time % 2 != 0:
7777
+ mode_time += 1
7778
+
7779
+ mode_dur = round(Counter([e[2] for e in fixed_timings_escore_notes if e[2] != 0]).most_common()[0][0] * fixed_timings_multiplier)
7780
+
7781
+ if mode_dur % 2 != 0:
7782
+ mode_dur += 1
7783
+
7784
+ for e in fixed_timings_escore_notes:
7785
+ if e[1] != 0:
7786
+
7787
+ if custom_fixed_time > 0:
7788
+ e[1] = custom_fixed_time
7789
+
7790
+ else:
7791
+ e[1] = mode_time
7792
+
7793
+ if fixed_durations:
7794
+
7795
+ if custom_fixed_dur > 0:
7796
+ e[2] = custom_fixed_dur
7797
+
7798
+ else:
7799
+ e[2] = mode_dur
7800
+
7801
+ return delta_score_to_abs_score(fixed_timings_escore_notes)
7802
+
7803
+ ###################################################################################
7804
+
7805
+ def cubic_kernel(x):
7806
+ abs_x = abs(x)
7807
+ if abs_x <= 1:
7808
+ return 1.5 * abs_x**3 - 2.5 * abs_x**2 + 1
7809
+ elif abs_x <= 2:
7810
+ return -0.5 * abs_x**3 + 2.5 * abs_x**2 - 4 * abs_x + 2
7811
+ else:
7812
+ return 0
7813
+
7814
+ ###################################################################################
7815
+
7816
+ def resize_matrix(matrix, new_height, new_width):
7817
+ old_height = len(matrix)
7818
+ old_width = len(matrix[0])
7819
+ resized_matrix = [[0] * new_width for _ in range(new_height)]
7820
+
7821
+ for i in range(new_height):
7822
+ for j in range(new_width):
7823
+ old_i = i * old_height / new_height
7824
+ old_j = j * old_width / new_width
7825
+
7826
+ value = 0
7827
+ total_weight = 0
7828
+ for m in range(-1, 3):
7829
+ for n in range(-1, 3):
7830
+ i_m = min(max(int(old_i) + m, 0), old_height - 1)
7831
+ j_n = min(max(int(old_j) + n, 0), old_width - 1)
7832
+
7833
+ if matrix[i_m][j_n] == 0:
7834
+ continue
7835
+
7836
+ weight = cubic_kernel(old_i - i_m) * cubic_kernel(old_j - j_n)
7837
+ value += matrix[i_m][j_n] * weight
7838
+ total_weight += weight
7839
+
7840
+ if total_weight > 0:
7841
+ value /= total_weight
7842
+
7843
+ resized_matrix[i][j] = int(value > 0.5)
7844
+
7845
+ return resized_matrix
7846
+
7847
+ ###################################################################################
7848
+
7849
+ def square_binary_matrix(binary_matrix,
7850
+ matrix_size=128,
7851
+ use_fast_squaring=False,
7852
+ return_plot_points=False
7853
+ ):
7854
+
7855
+ if use_fast_squaring:
7856
+
7857
+ step = round(len(binary_matrix) / matrix_size)
7858
+
7859
+ samples = []
7860
+
7861
+ for i in range(0, len(binary_matrix), step):
7862
+ samples.append(tuple([tuple(d) for d in binary_matrix[i:i+step]]))
7863
+
7864
+ resized_matrix = []
7865
+
7866
+ zmatrix = [[0] * matrix_size]
7867
+
7868
+ for s in samples:
7869
+
7870
+ samples_counts = Counter(s).most_common()
7871
+
7872
+ best_sample = tuple([0] * matrix_size)
7873
+ pm = tuple(zmatrix[0])
7874
+
7875
+ for sc in samples_counts:
7876
+ if sc[0] != tuple(zmatrix[0]) and sc[0] != pm:
7877
+ best_sample = sc[0]
7878
+ pm = sc[0]
7879
+ break
7880
+
7881
+ pm = sc[0]
7882
+
7883
+ resized_matrix.append(list(best_sample))
7884
+
7885
+ resized_matrix = resized_matrix[:matrix_size]
7886
+ resized_matrix += zmatrix * (matrix_size - len(resized_matrix))
7887
+
7888
+ else:
7889
+ resized_matrix = resize_matrix(binary_matrix, matrix_size, matrix_size)
7890
+
7891
+ points = [(i, j) for i in range(matrix_size) for j in range(matrix_size) if resized_matrix[i][j] == 1]
7892
+
7893
+ if return_plot_points:
7894
+ return [resized_matrix, points]
7895
+
7896
+ else:
7897
+ return resized_matrix
7898
+
7899
+ ###################################################################################
7900
+
7901
+ def mean(matrix):
7902
+ return sum(sum(row) for row in matrix) / (len(matrix) * len(matrix[0]))
7903
+
7904
+ ###################################################################################
7905
+
7906
+ def variance(matrix, mean_value):
7907
+ return sum(sum((element - mean_value) ** 2 for element in row) for row in matrix) / (len(matrix) * len(matrix[0]))
7908
+
7909
+ ###################################################################################
7910
+
7911
+ def covariance(matrix1, matrix2, mean1, mean2):
7912
+ return sum(sum((matrix1[i][j] - mean1) * (matrix2[i][j] - mean2) for j in range(len(matrix1[0]))) for i in range(len(matrix1))) / (len(matrix1) * len(matrix1[0]))
7913
+
7914
+ ###################################################################################
7915
+
7916
+ def ssim_index(matrix1, matrix2, bit_depth=1):
7917
+
7918
+ if len(matrix1) != len(matrix2) and len(matrix1[0]) != len(matrix2[0]):
7919
+ return -1
7920
+
7921
+ K1, K2 = 0.01, 0.03
7922
+ L = bit_depth
7923
+ C1 = (K1 * L) ** 2
7924
+ C2 = (K2 * L) ** 2
7925
+
7926
+ mu1 = mean(matrix1)
7927
+ mu2 = mean(matrix2)
7928
+
7929
+ sigma1_sq = variance(matrix1, mu1)
7930
+ sigma2_sq = variance(matrix2, mu2)
7931
+
7932
+ sigma12 = covariance(matrix1, matrix2, mu1, mu2)
7933
+
7934
+ ssim = ((2 * mu1 * mu2 + C1) * (2 * sigma12 + C2)) / ((mu1 ** 2 + mu2 ** 2 + C1) * (sigma1_sq + sigma2_sq + C2))
7935
+
7936
+ return ssim
7937
+
7938
+ ###################################################################################
7939
+
7940
+ def find_most_similar_matrix(array_of_matrices,
7941
+ trg_matrix,
7942
+ matrices_bit_depth=1,
7943
+ return_most_similar_index=False
7944
+ ):
7945
+
7946
+ max_ssim = -float('inf')
7947
+ most_similar_index = -1
7948
+
7949
+ for i, matrix in enumerate(array_of_matrices):
7950
+
7951
+ ssim = ssim_index(matrix, trg_matrix, bit_depth=matrices_bit_depth)
7952
+
7953
+ if ssim > max_ssim:
7954
+ max_ssim = ssim
7955
+ most_similar_index = i
7956
+
7957
+ if return_most_similar_index:
7958
+ return most_similar_index
7959
+
7960
+ else:
7961
+ return array_of_matrices[most_similar_index]
7962
+
7963
+ ###################################################################################
7964
+
7965
+ def chord_to_pchord(chord):
7966
+
7967
+ pchord = []
7968
+
7969
+ for cc in chord:
7970
+ if cc[3] != 9:
7971
+ pchord.append(cc[4])
7972
+
7973
+ return pchord
7974
+
7975
+ ###################################################################################
7976
+
7977
+ def summarize_escore_notes(escore_notes,
7978
+ summary_length_in_chords=128,
7979
+ preserve_timings=True,
7980
+ preserve_durations=False,
7981
+ time_threshold=12,
7982
+ min_sum_chord_len=2,
7983
+ use_tones_chords=True
7984
+ ):
7985
+
7986
+ cscore = chordify_score([d[1:] for d in delta_score_notes(escore_notes)])
7987
+
7988
+ summary_length_in_chords = min(len(cscore), summary_length_in_chords)
7989
+
7990
+ ltthresh = time_threshold // 2
7991
+ uttresh = time_threshold * 2
7992
+
7993
+ mc_time = Counter([c[0][0] for c in cscore if c[0][2] != 9 and ltthresh < c[0][0] < uttresh]).most_common()[0][0]
7994
+
7995
+ pchords = []
7996
+
7997
+ for c in cscore:
7998
+ if use_tones_chords:
7999
+ pchords.append([c[0][0]] + pitches_to_tones_chord(chord_to_pchord(c)))
8000
+
8001
+ else:
8002
+ pchords.append([c[0][0]] + chord_to_pchord(c))
8003
+
8004
+ step = round(len(pchords) / summary_length_in_chords)
8005
+
8006
+ samples = []
8007
+
8008
+ for i in range(0, len(pchords), step):
8009
+ samples.append(tuple([tuple(d) for d in pchords[i:i+step]]))
8010
+
8011
+ summarized_escore_notes = []
8012
+
8013
+ for i, s in enumerate(samples):
8014
+
8015
+ best_chord = list([v[0] for v in Counter(s).most_common() if v[0][0] == mc_time and len(v[0]) > min_sum_chord_len])
8016
+
8017
+ if not best_chord:
8018
+ best_chord = list([v[0] for v in Counter(s).most_common() if len(v[0]) > min_sum_chord_len])
8019
+
8020
+ if not best_chord:
8021
+ best_chord = list([Counter(s).most_common()[0][0]])
8022
+
8023
+ chord = copy.deepcopy(cscore[[ss for ss in s].index(best_chord[0])+(i*step)])
8024
+
8025
+ if preserve_timings:
8026
+
8027
+ if not preserve_durations:
8028
+
8029
+ if i > 0:
8030
+
8031
+ pchord = summarized_escore_notes[-1]
8032
+
8033
+ for pc in pchord:
8034
+ pc[1] = min(pc[1], chord[0][0])
8035
+
8036
+ else:
8037
+
8038
+ chord[0][0] = 1
8039
+
8040
+ for c in chord:
8041
+ c[1] = 1
8042
+
8043
+ summarized_escore_notes.append(chord)
8044
+
8045
+ summarized_escore_notes = summarized_escore_notes[:summary_length_in_chords]
8046
+
8047
+ return [['note'] + d for d in delta_score_to_abs_score(flatten(summarized_escore_notes), times_idx=0)]
8048
+
8049
+ ###################################################################################
8050
+
8051
+ def compress_patches_in_escore_notes(escore_notes,
8052
+ num_patches=4,
8053
+ group_patches=False
8054
+ ):
8055
+
8056
+ if num_patches > 4:
8057
+ n_patches = 4
8058
+ elif num_patches < 1:
8059
+ n_patches = 1
8060
+ else:
8061
+ n_patches = num_patches
8062
+
8063
+ if group_patches:
8064
+ patches_set = sorted(set([e[6] for e in c]))
8065
+ trg_patch_list = []
8066
+ seen = []
8067
+ for p in patches_set:
8068
+ if p // 8 not in seen:
8069
+ trg_patch_list.append(p)
8070
+ seen.append(p // 8)
8071
+
8072
+ trg_patch_list = sorted(trg_patch_list)
8073
+
8074
+ else:
8075
+ trg_patch_list = sorted(set([e[6] for e in c]))
8076
+
8077
+ if 128 in trg_patch_list and n_patches > 1:
8078
+ trg_patch_list = trg_patch_list[:n_patches-1] + [128]
8079
+ else:
8080
+ trg_patch_list = trg_patch_list[:n_patches]
8081
+
8082
+ new_escore_notes = []
8083
+
8084
+ for e in escore_notes:
8085
+ if e[6] in trg_patch_list:
8086
+ new_escore_notes.append(e)
8087
+
8088
+ return new_escore_notes
8089
+
8090
+ ###################################################################################
8091
+
8092
+ def compress_patches_in_escore_notes_chords(escore_notes,
8093
+ max_num_patches_per_chord=4,
8094
+ group_patches=True,
8095
+ root_grouped_patches=False
8096
+ ):
8097
+
8098
+ if max_num_patches_per_chord > 4:
8099
+ n_patches = 4
8100
+ elif max_num_patches_per_chord < 1:
8101
+ n_patches = 1
8102
+ else:
8103
+ n_patches = max_num_patches_per_chord
8104
+
8105
+ cscore = chordify_score([1000, sorted(escore_notes, key=lambda x: (x[1], x[6]))])
8106
+
8107
+ new_escore_notes = []
8108
+
8109
+ for c in cscore:
8110
+
8111
+ if group_patches:
8112
+ patches_set = sorted(set([e[6] for e in c]))
8113
+ trg_patch_list = []
8114
+ seen = []
8115
+ for p in patches_set:
8116
+ if p // 8 not in seen:
8117
+ trg_patch_list.append(p)
8118
+ seen.append(p // 8)
8119
+
8120
+ trg_patch_list = sorted(trg_patch_list)
8121
+
8122
+ else:
8123
+ trg_patch_list = sorted(set([e[6] for e in c]))
8124
+
8125
+ if 128 in trg_patch_list and n_patches > 1:
8126
+ trg_patch_list = trg_patch_list[:n_patches-1] + [128]
8127
+ else:
8128
+ trg_patch_list = trg_patch_list[:n_patches]
8129
+
8130
+ for ccc in c:
8131
+
8132
+ cc = copy.deepcopy(ccc)
8133
+
8134
+ if group_patches:
8135
+ if cc[6] // 8 in [t // 8 for t in trg_patch_list]:
8136
+ if root_grouped_patches:
8137
+ cc[6] = (cc[6] // 8) * 8
8138
+ new_escore_notes.append(cc)
8139
+
8140
+ else:
8141
+ if cc[6] in trg_patch_list:
8142
+ new_escore_notes.append(cc)
8143
+
8144
+ return new_escore_notes
8145
+
8146
+ ###################################################################################
8147
+
8148
+ def escore_notes_to_image_matrix(escore_notes,
8149
+ num_img_channels=3,
8150
+ filter_out_zero_rows=False,
8151
+ filter_out_duplicate_rows=False,
8152
+ flip_matrix=False,
8153
+ reverse_matrix=False
8154
+ ):
8155
+
8156
+ escore_notes = sorted(escore_notes, key=lambda x: (x[1], x[6]))
8157
+
8158
+ if num_img_channels > 1:
8159
+ n_mat_channels = 3
8160
+ else:
8161
+ n_mat_channels = 1
8162
+
8163
+ if escore_notes:
8164
+ last_time = escore_notes[-1][1]
8165
+ last_notes = [e for e in escore_notes if e[1] == last_time]
8166
+ max_last_dur = max([e[2] for e in last_notes])
8167
+
8168
+ time_range = last_time+max_last_dur
8169
+
8170
+ escore_matrix = []
8171
+
8172
+ escore_matrix = [[0] * 128 for _ in range(time_range)]
8173
+
8174
+ for note in escore_notes:
8175
+
8176
+ etype, time, duration, chan, pitch, velocity, pat = note
8177
+
8178
+ time = max(0, time)
8179
+ duration = max(2, duration)
8180
+ chan = max(0, min(15, chan))
8181
+ pitch = max(0, min(127, pitch))
8182
+ velocity = max(0, min(127, velocity))
8183
+ patch = max(0, min(128, pat))
8184
+
8185
+ if chan != 9:
8186
+ pat = patch + 128
8187
+ else:
8188
+ pat = 127
8189
+
8190
+ seen_pats = []
8191
+
8192
+ for t in range(time, min(time + duration, time_range)):
8193
+
8194
+ mat_value = escore_matrix[t][pitch]
8195
+
8196
+ mat_value_0 = (mat_value // (256 * 256)) % 256
8197
+ mat_value_1 = (mat_value // 256) % 256
8198
+
8199
+ cur_num_chans = 0
8200
+
8201
+ if 0 < mat_value < 256 and pat not in seen_pats:
8202
+ cur_num_chans = 1
8203
+ elif 256 < mat_value < (256 * 256) and pat not in seen_pats:
8204
+ cur_num_chans = 2
8205
+
8206
+ if cur_num_chans < n_mat_channels:
8207
+
8208
+ if n_mat_channels == 1:
8209
+
8210
+ escore_matrix[t][pitch] = pat
8211
+ seen_pats.append(pat)
8212
+
8213
+ elif n_mat_channels == 3:
8214
+
8215
+ if cur_num_chans == 0:
8216
+ escore_matrix[t][pitch] = pat
8217
+ seen_pats.append(pat)
8218
+ elif cur_num_chans == 1:
8219
+ escore_matrix[t][pitch] = (256 * 256 * mat_value_0) + (256 * pat)
8220
+ seen_pats.append(pat)
8221
+ elif cur_num_chans == 2:
8222
+ escore_matrix[t][pitch] = (256 * 256 * mat_value_0) + (256 * mat_value_1) + pat
8223
+ seen_pats.append(pat)
8224
+
8225
+ if filter_out_zero_rows:
8226
+ escore_matrix = [e for e in escore_matrix if sum(e) != 0]
8227
+
8228
+ if filter_out_duplicate_rows:
8229
+
8230
+ dd_escore_matrix = []
8231
+
8232
+ pr = [-1] * 128
8233
+ for e in escore_matrix:
8234
+ if e != pr:
8235
+ dd_escore_matrix.append(e)
8236
+ pr = e
8237
+
8238
+ escore_matrix = dd_escore_matrix
8239
+
8240
+ if flip_matrix:
8241
+
8242
+ temp_matrix = []
8243
+
8244
+ for m in escore_matrix:
8245
+ temp_matrix.append(m[::-1])
8246
+
8247
+ escore_matrix = temp_matrix
8248
+
8249
+ if reverse_matrix:
8250
+ escore_matrix = escore_matrix[::-1]
8251
+
8252
+ return escore_matrix
8253
+
8254
+ else:
8255
+ return None
8256
+
8257
+ ###################################################################################
8258
+
8259
+ def find_value_power(value, number):
8260
+ return math.floor(math.log(value, number))
8261
+
8262
+ ###################################################################################
8263
+
8264
+ def image_matrix_to_original_escore_notes(image_matrix,
8265
+ velocity=-1
8266
+ ):
8267
+
8268
+ result = []
8269
+
8270
+ for j in range(len(image_matrix[0])):
8271
+
8272
+ count = 1
8273
+
8274
+ for i in range(1, len(image_matrix)):
8275
+
8276
+ if image_matrix[i][j] != 0 and image_matrix[i][j] == image_matrix[i-1][j]:
8277
+ count += 1
8278
+
8279
+ else:
8280
+ if count > 1:
8281
+ result.append([i-count, count, j, image_matrix[i-1][j]])
8282
+
8283
+ else:
8284
+ if image_matrix[i-1][j] != 0:
8285
+ result.append([i-count, count, j, image_matrix[i-1][j]])
8286
+
8287
+ count = 1
8288
+
8289
+ if count > 1:
8290
+ result.append([len(image_matrix)-count, count, j, image_matrix[-1][j]])
8291
+
8292
+ else:
8293
+ if image_matrix[i-1][j] != 0:
8294
+ result.append([i-count, count, j, image_matrix[i-1][j]])
8295
+
8296
+ result.sort(key=lambda x: (x[0], -x[2]))
8297
+
8298
+ original_escore_notes = []
8299
+
8300
+ vel = velocity
8301
+
8302
+ for r in result:
8303
+
8304
+ if velocity == -1:
8305
+ vel = max(40, r[2])
8306
+
8307
+ ptc0 = 0
8308
+ ptc1 = 0
8309
+ ptc2 = 0
8310
+
8311
+ if find_value_power(r[3], 256) == 0:
8312
+ ptc0 = r[3] % 256
8313
+
8314
+ elif find_value_power(r[3], 256) == 1:
8315
+ ptc0 = r[3] // 256
8316
+ ptc1 = (r[3] // 256) % 256
8317
+
8318
+ elif find_value_power(r[3], 256) == 2:
8319
+ ptc0 = (r[3] // 256) // 256
8320
+ ptc1 = (r[3] // 256) % 256
8321
+ ptc2 = r[3] % 256
8322
+
8323
+ ptcs = [ptc0, ptc1, ptc2]
8324
+ patches = [p for p in ptcs if p != 0]
8325
+
8326
+ for i, p in enumerate(patches):
8327
+
8328
+ if p < 128:
8329
+ patch = 128
8330
+ channel = 9
8331
+
8332
+ else:
8333
+ patch = p % 128
8334
+ chan = p // 8
8335
+
8336
+ if chan == 9:
8337
+ chan += 1
8338
+
8339
+ channel = min(15, chan)
8340
+
8341
+ original_escore_notes.append(['note', r[0], r[1], channel, r[2], vel, patch])
8342
+
8343
+ output_score = sorted(original_escore_notes, key=lambda x: (x[1], -x[4], x[6]))
8344
+
8345
+ adjust_score_velocities(output_score, 127)
8346
+
8347
+ return output_score
8348
+
8349
+ ###################################################################################
8350
+
8351
+ def escore_notes_delta_times(escore_notes,
8352
+ timings_index=1,
8353
+ channels_index=3,
8354
+ omit_zeros=False,
8355
+ omit_drums=False
8356
+ ):
8357
+
8358
+ if omit_drums:
8359
+
8360
+ score = [e for e in escore_notes if e[channels_index] != 9]
8361
+ dtimes = [score[0][timings_index]] + [b[timings_index]-a[timings_index] for a, b in zip(score[:-1], score[1:])]
8362
+
8363
+ else:
8364
+ dtimes = [escore_notes[0][timings_index]] + [b[timings_index]-a[timings_index] for a, b in zip(escore_notes[:-1], escore_notes[1:])]
8365
+
8366
+ if omit_zeros:
8367
+ dtimes = [d for d in dtimes if d != 0]
8368
+
8369
+ return dtimes
8370
+
8371
+ ###################################################################################
8372
+
8373
+ def monophonic_check(escore_notes, times_index=1):
8374
+ return len(escore_notes) == len(set([e[times_index] for e in escore_notes]))
8375
+
8376
+ ###################################################################################
8377
+
8378
+ def count_escore_notes_patches(escore_notes, patches_index=6):
8379
+ return [list(c) for c in Counter([e[patches_index] for e in escore_notes]).most_common()]
8380
+
8381
+ ###################################################################################
8382
+
8383
+ def escore_notes_medley(list_of_escore_notes,
8384
+ list_of_labels=None,
8385
+ pause_time_value=255
8386
+ ):
8387
+
8388
+ if list_of_labels is not None:
8389
+ labels = [str(l) for l in list_of_labels] + ['No label'] * (len(list_of_escore_notes)-len(list_of_labels))
8390
+
8391
+ medley = []
8392
+
8393
+ time = 0
8394
+
8395
+ for i, m in enumerate(list_of_escore_notes):
8396
+
8397
+ if list_of_labels is not None:
8398
+ medley.append(['text_event', time, labels[i]])
8399
+
8400
+ pe = m[0]
8401
+
8402
+ for mm in m:
8403
+
8404
+ time += mm[1] - pe[1]
8405
+
8406
+ mmm = copy.deepcopy(mm)
8407
+ mmm[1] = time
8408
+
8409
+ medley.append(mmm)
8410
+
8411
+ pe = mm
8412
+
8413
+ time += pause_time_value
8414
+
8415
+ return medley
8416
+
8417
+ ###################################################################################
8418
+
8419
+ def proportions_counter(list_of_values):
8420
+
8421
+ counts = Counter(list_of_values).most_common()
8422
+ clen = sum([c[1] for c in counts])
8423
+
8424
+ return [[c[0], c[1], c[1] / clen] for c in counts]
8425
+
8426
+ ###################################################################################
8427
+ #
8428
+ # This is the end of the TMIDI X Python module
8429
+ #
8430
  ###################################################################################
TPLOTS.py ADDED
@@ -0,0 +1,1245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #! /usr/bin/python3
2
+
3
+ r'''############################################################################
4
+ ################################################################################
5
+ #
6
+ #
7
+ # Tegridy Plots Python Module (TPLOTS)
8
+ # Version 1.0
9
+ #
10
+ # Project Los Angeles
11
+ #
12
+ # Tegridy Code 2024
13
+ #
14
+ # https://github.com/asigalov61/tegridy-tools
15
+ #
16
+ #
17
+ ################################################################################
18
+ #
19
+ # Copyright 2024 Project Los Angeles / Tegridy Code
20
+ #
21
+ # Licensed under the Apache License, Version 2.0 (the "License");
22
+ # you may not use this file except in compliance with the License.
23
+ # You may obtain a copy of the License at
24
+ #
25
+ # http://www.apache.org/licenses/LICENSE-2.0
26
+ #
27
+ # Unless required by applicable law or agreed to in writing, software
28
+ # distributed under the License is distributed on an "AS IS" BASIS,
29
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30
+ # See the License for the specific language governing permissions and
31
+ # limitations under the License.
32
+ #
33
+ ################################################################################
34
+ ################################################################################
35
+ #
36
+ # Critical dependencies
37
+ #
38
+ # !pip install numpy
39
+ # !pip install scipy
40
+ # !pip install matplotlib
41
+ # !pip install networkx
42
+ # !pip3 install scikit-learn
43
+ #
44
+ ################################################################################
45
+ #
46
+ # Future critical dependencies
47
+ #
48
+ # !pip install umap-learn
49
+ # !pip install alphashape
50
+ #
51
+ ################################################################################
52
+ '''
53
+
54
+ ################################################################################
55
+ # Modules imports
56
+ ################################################################################
57
+
58
+ import os
59
+ from collections import Counter
60
+ from itertools import groupby
61
+
62
+ import numpy as np
63
+
64
+ import networkx as nx
65
+
66
+ from sklearn.manifold import TSNE
67
+ from sklearn import metrics
68
+ from sklearn.preprocessing import MinMaxScaler
69
+ from sklearn.decomposition import PCA
70
+
71
+ from scipy.ndimage import zoom
72
+ from scipy.spatial import distance_matrix
73
+ from scipy.sparse.csgraph import minimum_spanning_tree
74
+ from scipy.stats import zscore
75
+
76
+ import matplotlib.pyplot as plt
77
+ from PIL import Image
78
+
79
+ ################################################################################
80
+ # Constants
81
+ ################################################################################
82
+
83
+ ALL_CHORDS_FILTERED = [[0], [0, 3], [0, 3, 5], [0, 3, 5, 8], [0, 3, 5, 9], [0, 3, 5, 10], [0, 3, 7],
84
+ [0, 3, 7, 10], [0, 3, 8], [0, 3, 9], [0, 3, 10], [0, 4], [0, 4, 6],
85
+ [0, 4, 6, 9], [0, 4, 6, 10], [0, 4, 7], [0, 4, 7, 10], [0, 4, 8], [0, 4, 9],
86
+ [0, 4, 10], [0, 5], [0, 5, 8], [0, 5, 9], [0, 5, 10], [0, 6], [0, 6, 9],
87
+ [0, 6, 10], [0, 7], [0, 7, 10], [0, 8], [0, 9], [0, 10], [1], [1, 4],
88
+ [1, 4, 6], [1, 4, 6, 9], [1, 4, 6, 10], [1, 4, 6, 11], [1, 4, 7],
89
+ [1, 4, 7, 10], [1, 4, 7, 11], [1, 4, 8], [1, 4, 8, 11], [1, 4, 9], [1, 4, 10],
90
+ [1, 4, 11], [1, 5], [1, 5, 8], [1, 5, 8, 11], [1, 5, 9], [1, 5, 10],
91
+ [1, 5, 11], [1, 6], [1, 6, 9], [1, 6, 10], [1, 6, 11], [1, 7], [1, 7, 10],
92
+ [1, 7, 11], [1, 8], [1, 8, 11], [1, 9], [1, 10], [1, 11], [2], [2, 5],
93
+ [2, 5, 8], [2, 5, 8, 11], [2, 5, 9], [2, 5, 10], [2, 5, 11], [2, 6], [2, 6, 9],
94
+ [2, 6, 10], [2, 6, 11], [2, 7], [2, 7, 10], [2, 7, 11], [2, 8], [2, 8, 11],
95
+ [2, 9], [2, 10], [2, 11], [3], [3, 5], [3, 5, 8], [3, 5, 8, 11], [3, 5, 9],
96
+ [3, 5, 10], [3, 5, 11], [3, 7], [3, 7, 10], [3, 7, 11], [3, 8], [3, 8, 11],
97
+ [3, 9], [3, 10], [3, 11], [4], [4, 6], [4, 6, 9], [4, 6, 10], [4, 6, 11],
98
+ [4, 7], [4, 7, 10], [4, 7, 11], [4, 8], [4, 8, 11], [4, 9], [4, 10], [4, 11],
99
+ [5], [5, 8], [5, 8, 11], [5, 9], [5, 10], [5, 11], [6], [6, 9], [6, 10],
100
+ [6, 11], [7], [7, 10], [7, 11], [8], [8, 11], [9], [10], [11]]
101
+
102
+ ################################################################################
103
+
104
+ CHORDS_TYPES = ['WHITE', 'BLACK', 'UNKNOWN', 'MIXED WHITE', 'MIXED BLACK', 'MIXED GRAY']
105
+
106
+ ################################################################################
107
+
108
+ WHITE_NOTES = [0, 2, 4, 5, 7, 9, 11]
109
+
110
+ ################################################################################
111
+
112
+ BLACK_NOTES = [1, 3, 6, 8, 10]
113
+
114
+ ################################################################################
115
+ # Helper functions
116
+ ################################################################################
117
+
118
+ def tones_chord_type(tones_chord,
119
+ return_chord_type_index=True,
120
+ ):
121
+
122
+ """
123
+ Returns tones chord type
124
+ """
125
+
126
+ WN = WHITE_NOTES
127
+ BN = BLACK_NOTES
128
+ MX = WHITE_NOTES + BLACK_NOTES
129
+
130
+
131
+ CHORDS = ALL_CHORDS_FILTERED
132
+
133
+ tones_chord = sorted(tones_chord)
134
+
135
+ ctype = 'UNKNOWN'
136
+
137
+ if tones_chord in CHORDS:
138
+
139
+ if sorted(set(tones_chord) & set(WN)) == tones_chord:
140
+ ctype = 'WHITE'
141
+
142
+ elif sorted(set(tones_chord) & set(BN)) == tones_chord:
143
+ ctype = 'BLACK'
144
+
145
+ if len(tones_chord) > 1 and sorted(set(tones_chord) & set(MX)) == tones_chord:
146
+
147
+ if len(sorted(set(tones_chord) & set(WN))) == len(sorted(set(tones_chord) & set(BN))):
148
+ ctype = 'MIXED GRAY'
149
+
150
+ elif len(sorted(set(tones_chord) & set(WN))) > len(sorted(set(tones_chord) & set(BN))):
151
+ ctype = 'MIXED WHITE'
152
+
153
+ elif len(sorted(set(tones_chord) & set(WN))) < len(sorted(set(tones_chord) & set(BN))):
154
+ ctype = 'MIXED BLACK'
155
+
156
+ if return_chord_type_index:
157
+ return CHORDS_TYPES.index(ctype)
158
+
159
+ else:
160
+ return ctype
161
+
162
+ ###################################################################################
163
+
164
+ def tone_type(tone,
165
+ return_tone_type_index=True
166
+ ):
167
+
168
+ """
169
+ Returns tone type
170
+ """
171
+
172
+ tone = tone % 12
173
+
174
+ if tone in BLACK_NOTES:
175
+ if return_tone_type_index:
176
+ return CHORDS_TYPES.index('BLACK')
177
+ else:
178
+ return "BLACK"
179
+
180
+ else:
181
+ if return_tone_type_index:
182
+ return CHORDS_TYPES.index('WHITE')
183
+ else:
184
+ return "WHITE"
185
+
186
+ ###################################################################################
187
+
188
+ def find_closest_points(points, return_points=True):
189
+
190
+ """
191
+ Find closest 2D points
192
+ """
193
+
194
+ coords = np.array(points)
195
+
196
+ num_points = coords.shape[0]
197
+ closest_matches = np.zeros(num_points, dtype=int)
198
+ distances = np.zeros((num_points, num_points))
199
+
200
+ for i in range(num_points):
201
+ for j in range(num_points):
202
+ if i != j:
203
+ distances[i, j] = np.linalg.norm(coords[i] - coords[j])
204
+ else:
205
+ distances[i, j] = np.inf
206
+
207
+ closest_matches = np.argmin(distances, axis=1)
208
+
209
+ if return_points:
210
+ points_matches = coords[closest_matches].tolist()
211
+ return points_matches
212
+
213
+ else:
214
+ return closest_matches.tolist()
215
+
216
+ ################################################################################
217
+
218
+ def reduce_dimensionality_tsne(list_of_valies,
219
+ n_comp=2,
220
+ n_iter=5000,
221
+ verbose=True
222
+ ):
223
+
224
+ """
225
+ Reduces the dimensionality of the values using t-SNE.
226
+ """
227
+
228
+ vals = np.array(list_of_valies)
229
+
230
+ tsne = TSNE(n_components=n_comp,
231
+ n_iter=n_iter,
232
+ verbose=verbose)
233
+
234
+ reduced_vals = tsne.fit_transform(vals)
235
+
236
+ return reduced_vals.tolist()
237
+
238
+ ################################################################################
239
+
240
+ def compute_mst_edges(similarity_scores_list):
241
+
242
+ """
243
+ Computes the Minimum Spanning Tree (MST) edges based on the similarity scores.
244
+ """
245
+
246
+ num_tokens = len(similarity_scores_list[0])
247
+
248
+ graph = nx.Graph()
249
+
250
+ for i in range(num_tokens):
251
+ for j in range(i + 1, num_tokens):
252
+ weight = 1 - similarity_scores_list[i][j]
253
+ graph.add_edge(i, j, weight=weight)
254
+
255
+ mst = nx.minimum_spanning_tree(graph)
256
+
257
+ mst_edges = list(mst.edges(data=False))
258
+
259
+ return mst_edges
260
+
261
+ ################################################################################
262
+
263
+ def square_binary_matrix(binary_matrix,
264
+ matrix_size=128,
265
+ interpolation_order=5,
266
+ return_square_matrix_points=False
267
+ ):
268
+
269
+ """
270
+ Reduces an arbitrary binary matrix to a square binary matrix
271
+ """
272
+
273
+ zoom_factors = (matrix_size / len(binary_matrix), 1)
274
+
275
+ resized_matrix = zoom(binary_matrix, zoom_factors, order=interpolation_order)
276
+
277
+ resized_matrix = (resized_matrix > 0.5).astype(int)
278
+
279
+ final_matrix = np.zeros((matrix_size, matrix_size), dtype=int)
280
+ final_matrix[:, :resized_matrix.shape[1]] = resized_matrix
281
+
282
+ points = np.column_stack(np.where(final_matrix == 1)).tolist()
283
+
284
+ if return_square_matrix_points:
285
+ return points
286
+
287
+ else:
288
+ return resized_matrix
289
+
290
+ ################################################################################
291
+
292
+ def square_matrix_points_colors(square_matrix_points):
293
+
294
+ """
295
+ Returns colors for square matrix points
296
+ """
297
+
298
+ cmap = generate_colors(12)
299
+
300
+ chords = []
301
+ chords_dict = set()
302
+ counts = []
303
+
304
+ for k, v in groupby(square_matrix_points, key=lambda x: x[0]):
305
+ pgroup = [vv[1] for vv in v]
306
+ chord = sorted(set(pgroup))
307
+ tchord = sorted(set([p % 12 for p in chord]))
308
+ chords_dict.add(tuple(tchord))
309
+ chords.append(tuple(tchord))
310
+ counts.append(len(pgroup))
311
+
312
+ chords_dict = sorted(chords_dict)
313
+
314
+ colors = []
315
+
316
+ for i, c in enumerate(chords):
317
+ colors.extend([cmap[round(sum(c) / len(c))]] * counts[i])
318
+
319
+ return colors
320
+
321
+ ################################################################################
322
+
323
+ def hsv_to_rgb(h, s, v):
324
+
325
+ if s == 0.0:
326
+ return v, v, v
327
+
328
+ i = int(h*6.0)
329
+ f = (h*6.0) - i
330
+ p = v*(1.0 - s)
331
+ q = v*(1.0 - s*f)
332
+ t = v*(1.0 - s*(1.0-f))
333
+ i = i%6
334
+
335
+ return [(v, t, p), (q, v, p), (p, v, t), (p, q, v), (t, p, v), (v, p, q)][i]
336
+
337
+ ################################################################################
338
+
339
+ def generate_colors(n):
340
+ return [hsv_to_rgb(i/n, 1, 1) for i in range(n)]
341
+
342
+ ################################################################################
343
+
344
+ def add_arrays(a, b):
345
+ return [sum(pair) for pair in zip(a, b)]
346
+
347
+ ################################################################################
348
+
349
+ def calculate_similarities(lists_of_values, metric='cosine'):
350
+ return metrics.pairwise_distances(lists_of_values, metric=metric).tolist()
351
+
352
+ ################################################################################
353
+
354
+ def get_tokens_embeddings(x_transformer_model):
355
+ return x_transformer_model.net.token_emb.emb.weight.detach().cpu().tolist()
356
+
357
+ ################################################################################
358
+
359
+ def minkowski_distance_matrix(X, p=3):
360
+
361
+ X = np.array(X)
362
+
363
+ n = X.shape[0]
364
+ dist_matrix = np.zeros((n, n))
365
+
366
+ for i in range(n):
367
+ for j in range(n):
368
+ dist_matrix[i, j] = np.sum(np.abs(X[i] - X[j])**p)**(1/p)
369
+
370
+ return dist_matrix.tolist()
371
+
372
+ ################################################################################
373
+
374
+ def robust_normalize(values):
375
+
376
+ values = np.array(values)
377
+ q1 = np.percentile(values, 25)
378
+ q3 = np.percentile(values, 75)
379
+ iqr = q3 - q1
380
+
381
+ filtered_values = values[(values >= q1 - 1.5 * iqr) & (values <= q3 + 1.5 * iqr)]
382
+
383
+ min_val = np.min(filtered_values)
384
+ max_val = np.max(filtered_values)
385
+ normalized_values = (values - min_val) / (max_val - min_val)
386
+
387
+ normalized_values = np.clip(normalized_values, 0, 1)
388
+
389
+ return normalized_values.tolist()
390
+
391
+ ################################################################################
392
+
393
+ def min_max_normalize(values):
394
+
395
+ scaler = MinMaxScaler()
396
+
397
+ return scaler.fit_transform(values).tolist()
398
+
399
+ ################################################################################
400
+
401
+ def remove_points_outliers(points, z_score_threshold=3):
402
+
403
+ points = np.array(points)
404
+
405
+ z_scores = np.abs(zscore(points, axis=0))
406
+
407
+ return points[(z_scores < z_score_threshold).all(axis=1)].tolist()
408
+
409
+ ################################################################################
410
+
411
+ def generate_labels(lists_of_values,
412
+ return_indices_labels=False
413
+ ):
414
+
415
+ ordered_indices = list(range(len(lists_of_values)))
416
+ ordered_indices_labels = [str(i) for i in ordered_indices]
417
+ ordered_values_labels = [str(lists_of_values[i]) for i in ordered_indices]
418
+
419
+ if return_indices_labels:
420
+ return ordered_indices_labels
421
+
422
+ else:
423
+ return ordered_values_labels
424
+
425
+ ################################################################################
426
+
427
+ def reduce_dimensionality_pca(list_of_values, n_components=2):
428
+
429
+ """
430
+ Reduces the dimensionality of the values using PCA.
431
+ """
432
+
433
+ pca = PCA(n_components=n_components)
434
+ pca_data = pca.fit_transform(list_of_values)
435
+
436
+ return pca_data.tolist()
437
+
438
+ def reduce_dimensionality_simple(list_of_values,
439
+ return_means=True,
440
+ return_std_devs=True,
441
+ return_medians=False,
442
+ return_vars=False
443
+ ):
444
+
445
+ '''
446
+ Reduces dimensionality of the values in a simple way
447
+ '''
448
+
449
+ array = np.array(list_of_values)
450
+ results = []
451
+
452
+ if return_means:
453
+ means = np.mean(array, axis=1)
454
+ results.append(means)
455
+
456
+ if return_std_devs:
457
+ std_devs = np.std(array, axis=1)
458
+ results.append(std_devs)
459
+
460
+ if return_medians:
461
+ medians = np.median(array, axis=1)
462
+ results.append(medians)
463
+
464
+ if return_vars:
465
+ vars = np.var(array, axis=1)
466
+ results.append(vars)
467
+
468
+ merged_results = np.column_stack(results)
469
+
470
+ return merged_results.tolist()
471
+
472
+ ################################################################################
473
+
474
+ def reduce_dimensionality_2d_distance(list_of_values, p=5):
475
+
476
+ '''
477
+ Reduces the dimensionality of the values using 2d distance
478
+ '''
479
+
480
+ values = np.array(list_of_values)
481
+
482
+ dist_matrix = distance_matrix(values, values, p=p)
483
+
484
+ mst = minimum_spanning_tree(dist_matrix).toarray()
485
+
486
+ points = []
487
+
488
+ for i in range(len(values)):
489
+ for j in range(len(values)):
490
+ if mst[i, j] > 0:
491
+ points.append([i, j])
492
+
493
+ return points
494
+
495
+ ################################################################################
496
+
497
+ def normalize_to_range(values, n):
498
+
499
+ min_val = min(values)
500
+ max_val = max(values)
501
+
502
+ range_val = max_val - min_val
503
+
504
+ normalized_values = [((value - min_val) / range_val * 2 * n) - n for value in values]
505
+
506
+ return normalized_values
507
+
508
+ ################################################################################
509
+
510
+ def reduce_dimensionality_simple_pca(list_of_values, n_components=2):
511
+
512
+ '''
513
+ Reduces the dimensionality of the values using simple PCA
514
+ '''
515
+
516
+ reduced_values = []
517
+
518
+ for l in list_of_values:
519
+
520
+ norm_values = [round(v * len(l)) for v in normalize_to_range(l, (n_components+1) // 2)]
521
+
522
+ pca_values = Counter(norm_values).most_common()
523
+ pca_values = [vv[0] / len(l) for vv in pca_values]
524
+ pca_values = pca_values[:n_components]
525
+ pca_values = pca_values + [0] * (n_components - len(pca_values))
526
+
527
+ reduced_values.append(pca_values)
528
+
529
+ return reduced_values
530
+
531
+ ################################################################################
532
+
533
+ def filter_and_replace_values(list_of_values,
534
+ threshold,
535
+ replace_value,
536
+ replace_above_threshold=False
537
+ ):
538
+
539
+ array = np.array(list_of_values)
540
+
541
+ modified_array = np.copy(array)
542
+
543
+ if replace_above_threshold:
544
+ modified_array[modified_array > threshold] = replace_value
545
+
546
+ else:
547
+ modified_array[modified_array < threshold] = replace_value
548
+
549
+ return modified_array.tolist()
550
+
551
+ ################################################################################
552
+
553
+ def find_shortest_constellation_path(points,
554
+ start_point_idx,
555
+ end_point_idx,
556
+ p=5,
557
+ return_path_length=False,
558
+ return_path_points=False,
559
+ ):
560
+
561
+ """
562
+ Finds the shortest path between two points of the points constellation
563
+ """
564
+
565
+ points = np.array(points)
566
+
567
+ dist_matrix = distance_matrix(points, points, p=p)
568
+
569
+ mst = minimum_spanning_tree(dist_matrix).toarray()
570
+
571
+ G = nx.Graph()
572
+
573
+ for i in range(len(points)):
574
+ for j in range(len(points)):
575
+ if mst[i, j] > 0:
576
+ G.add_edge(i, j, weight=mst[i, j])
577
+
578
+ path = nx.shortest_path(G,
579
+ source=start_point_idx,
580
+ target=end_point_idx,
581
+ weight='weight'
582
+ )
583
+
584
+ path_length = nx.shortest_path_length(G,
585
+ source=start_point_idx,
586
+ target=end_point_idx,
587
+ weight='weight')
588
+
589
+ path_points = points[np.array(path)].tolist()
590
+
591
+
592
+ if return_path_points:
593
+ return path_points
594
+
595
+ if return_path_length:
596
+ return path_length
597
+
598
+ return path
599
+
600
+ ################################################################################
601
+ # Core functions
602
+ ################################################################################
603
+
604
+ def plot_ms_SONG(ms_song,
605
+ preview_length_in_notes=0,
606
+ block_lines_times_list = None,
607
+ plot_title='ms Song',
608
+ max_num_colors=129,
609
+ drums_color_num=128,
610
+ plot_size=(11,4),
611
+ note_height = 0.75,
612
+ show_grid_lines=False,
613
+ return_plt = False,
614
+ timings_multiplier=1,
615
+ save_plt='',
616
+ save_only_plt_image=True,
617
+ save_transparent=False
618
+ ):
619
+
620
+ '''ms SONG plot'''
621
+
622
+ notes = [s for s in ms_song if s[0] == 'note']
623
+
624
+ if (len(max(notes, key=len)) != 7) and (len(min(notes, key=len)) != 7):
625
+ print('The song notes do not have patches information')
626
+ print('Ploease add patches to the notes in the song')
627
+
628
+ else:
629
+
630
+ start_times = [(s[1] * timings_multiplier) / 1000 for s in notes]
631
+ durations = [(s[2] * timings_multiplier) / 1000 for s in notes]
632
+ pitches = [s[4] for s in notes]
633
+ patches = [s[6] for s in notes]
634
+
635
+ colors = generate_colors(max_num_colors)
636
+ colors[drums_color_num] = (1, 1, 1)
637
+
638
+ pbl = (notes[preview_length_in_notes][1] * timings_multiplier) / 1000
639
+
640
+ fig, ax = plt.subplots(figsize=plot_size)
641
+
642
+ for start, duration, pitch, patch in zip(start_times, durations, pitches, patches):
643
+ rect = plt.Rectangle((start, pitch), duration, note_height, facecolor=colors[patch])
644
+ ax.add_patch(rect)
645
+
646
+ ax.set_xlim([min(start_times), max(add_arrays(start_times, durations))])
647
+ ax.set_ylim([min(pitches)-1, max(pitches)+1])
648
+
649
+ ax.set_facecolor('black')
650
+ fig.patch.set_facecolor('white')
651
+
652
+ if preview_length_in_notes > 0:
653
+ ax.axvline(x=pbl, c='white')
654
+
655
+ if block_lines_times_list:
656
+ for bl in block_lines_times_list:
657
+ ax.axvline(x=bl, c='white')
658
+
659
+ if show_grid_lines:
660
+ ax.grid(color='white')
661
+
662
+ plt.xlabel('Time (s)', c='black')
663
+ plt.ylabel('MIDI Pitch', c='black')
664
+
665
+ plt.title(plot_title)
666
+
667
+ if save_plt != '':
668
+ if save_only_plt_image:
669
+ plt.axis('off')
670
+ plt.title('')
671
+ plt.savefig(save_plt,
672
+ transparent=save_transparent,
673
+ bbox_inches='tight',
674
+ pad_inches=0,
675
+ facecolor='black'
676
+ )
677
+ plt.close()
678
+
679
+ else:
680
+ plt.savefig(save_plt)
681
+ plt.close()
682
+
683
+ if return_plt:
684
+ return fig
685
+
686
+ plt.show()
687
+ plt.close()
688
+
689
+ ################################################################################
690
+
691
+ def plot_square_matrix_points(list_of_points,
692
+ list_of_points_colors,
693
+ plot_size=(7, 7),
694
+ point_size = 10,
695
+ show_grid_lines=False,
696
+ plot_title = 'Square Matrix Points Plot',
697
+ return_plt=False,
698
+ save_plt='',
699
+ save_only_plt_image=True,
700
+ save_transparent=False
701
+ ):
702
+
703
+ '''Square matrix points plot'''
704
+
705
+ fig, ax = plt.subplots(figsize=plot_size)
706
+
707
+ ax.set_facecolor('black')
708
+
709
+ if show_grid_lines:
710
+ ax.grid(color='white')
711
+
712
+ plt.xlabel('Time Step', c='black')
713
+ plt.ylabel('MIDI Pitch', c='black')
714
+
715
+ plt.title(plot_title)
716
+
717
+ plt.scatter([p[0] for p in list_of_points],
718
+ [p[1] for p in list_of_points],
719
+ c=list_of_points_colors,
720
+ s=point_size
721
+ )
722
+
723
+ if save_plt != '':
724
+ if save_only_plt_image:
725
+ plt.axis('off')
726
+ plt.title('')
727
+ plt.savefig(save_plt,
728
+ transparent=save_transparent,
729
+ bbox_inches='tight',
730
+ pad_inches=0,
731
+ facecolor='black'
732
+ )
733
+ plt.close()
734
+
735
+ else:
736
+ plt.savefig(save_plt)
737
+ plt.close()
738
+
739
+ if return_plt:
740
+ return fig
741
+
742
+ plt.show()
743
+ plt.close()
744
+
745
+ ################################################################################
746
+
747
+ def plot_cosine_similarities(lists_of_values,
748
+ plot_size=(7, 7),
749
+ save_plot=''
750
+ ):
751
+
752
+ """
753
+ Cosine similarities plot
754
+ """
755
+
756
+ cos_sim = metrics.pairwise_distances(lists_of_values, metric='cosine')
757
+
758
+ plt.figure(figsize=plot_size)
759
+
760
+ plt.imshow(cos_sim, cmap="inferno", interpolation="nearest")
761
+
762
+ im_ratio = cos_sim.shape[0] / cos_sim.shape[1]
763
+
764
+ plt.colorbar(fraction=0.046 * im_ratio, pad=0.04)
765
+
766
+ plt.xlabel("Index")
767
+ plt.ylabel("Index")
768
+
769
+ plt.tight_layout()
770
+
771
+ if save_plot != '':
772
+ plt.savefig(save_plot, bbox_inches="tight")
773
+ plt.close()
774
+
775
+ plt.show()
776
+ plt.close()
777
+
778
+ ################################################################################
779
+
780
+ def plot_points_with_mst_lines(points,
781
+ points_labels,
782
+ points_mst_edges,
783
+ plot_size=(20, 20),
784
+ labels_size=24,
785
+ save_plot=''
786
+ ):
787
+
788
+ """
789
+ Plots 2D points with labels and MST lines.
790
+ """
791
+
792
+ plt.figure(figsize=plot_size)
793
+
794
+ for i, label in enumerate(points_labels):
795
+ plt.scatter(points[i][0], points[i][1])
796
+ plt.annotate(label, (points[i][0], points[i][1]), fontsize=labels_size)
797
+
798
+ for edge in points_mst_edges:
799
+ i, j = edge
800
+ plt.plot([points[i][0], points[j][0]], [points[i][1], points[j][1]], 'k-', alpha=0.5)
801
+
802
+ plt.title('Points Map with MST Lines', fontsize=labels_size)
803
+ plt.xlabel('X-axis', fontsize=labels_size)
804
+ plt.ylabel('Y-axis', fontsize=labels_size)
805
+
806
+ if save_plot != '':
807
+ plt.savefig(save_plot, bbox_inches="tight")
808
+ plt.close()
809
+
810
+ plt.show()
811
+
812
+ plt.close()
813
+
814
+ ################################################################################
815
+
816
+ def plot_points_constellation(points,
817
+ points_labels,
818
+ p=5,
819
+ plot_size=(15, 15),
820
+ labels_size=12,
821
+ show_grid=False,
822
+ save_plot=''
823
+ ):
824
+
825
+ """
826
+ Plots 2D points constellation
827
+ """
828
+
829
+ points = np.array(points)
830
+
831
+ dist_matrix = distance_matrix(points, points, p=p)
832
+
833
+ mst = minimum_spanning_tree(dist_matrix).toarray()
834
+
835
+ plt.figure(figsize=plot_size)
836
+
837
+ plt.scatter(points[:, 0], points[:, 1], color='blue')
838
+
839
+ for i, label in enumerate(points_labels):
840
+ plt.annotate(label, (points[i, 0], points[i, 1]),
841
+ textcoords="offset points",
842
+ xytext=(0, 10),
843
+ ha='center',
844
+ fontsize=labels_size
845
+ )
846
+
847
+ for i in range(len(points)):
848
+ for j in range(len(points)):
849
+ if mst[i, j] > 0:
850
+ plt.plot([points[i, 0], points[j, 0]], [points[i, 1], points[j, 1]], 'k--')
851
+
852
+ plt.xlabel('X-axis', fontsize=labels_size)
853
+ plt.ylabel('Y-axis', fontsize=labels_size)
854
+ plt.title('2D Coordinates with Minimum Spanning Tree', fontsize=labels_size)
855
+
856
+ plt.grid(show_grid)
857
+
858
+ if save_plot != '':
859
+ plt.savefig(save_plot, bbox_inches="tight")
860
+ plt.close()
861
+
862
+ plt.show()
863
+
864
+ plt.close()
865
+
866
+ ################################################################################
867
+
868
+ def binary_matrix_to_images(matrix,
869
+ step,
870
+ overlap,
871
+ output_folder='./Dataset/',
872
+ output_img_prefix='image',
873
+ output_img_ext='.png',
874
+ save_to_array=False,
875
+ verbose=True
876
+ ):
877
+
878
+ if not save_to_array:
879
+
880
+ if verbose:
881
+ print('=' * 70)
882
+ print('Checking output folder dir...')
883
+
884
+ os.makedirs(os.path.dirname(output_folder), exist_ok=True)
885
+
886
+ if verbose:
887
+ print('Done!')
888
+
889
+ if verbose:
890
+ print('=' * 70)
891
+ print('Writing images...')
892
+
893
+ matrix = np.array(matrix, dtype=np.uint8)
894
+
895
+ image_array = []
896
+
897
+ for i in range(0, max(1, matrix.shape[0]), overlap):
898
+
899
+ submatrix = matrix[i:i+step, :]
900
+
901
+ if submatrix.shape[0] < 128:
902
+ zeros_array = np.zeros((128-submatrix.shape[0], 128))
903
+ submatrix = np.vstack((submatrix, zeros_array))
904
+
905
+ img = Image.fromarray(submatrix * 255).convert('1')
906
+
907
+ if save_to_array:
908
+ image_array.append(np.array(img))
909
+
910
+ else:
911
+ img.save(output_folder + output_img_prefix + '_' + str(matrix.shape[1]) + '_' + str(i).zfill(7) + output_img_ext)
912
+
913
+ if verbose:
914
+ print('Done!')
915
+ print('=' * 70)
916
+ print('Saved', (matrix.shape[0] // min(step, overlap))+1, 'imges!')
917
+ print('=' * 70)
918
+
919
+ if save_to_array:
920
+ return np.array(image_array).tolist()
921
+
922
+ ################################################################################
923
+
924
+ def images_to_binary_matrix(list_of_images):
925
+
926
+ image_array = np.array(list_of_images)
927
+
928
+ original_matrix = []
929
+
930
+ for img in image_array:
931
+
932
+ submatrix = np.array(img)
933
+ original_matrix.extend(submatrix.tolist())
934
+
935
+ return original_matrix
936
+
937
+ ################################################################################
938
+
939
+ def square_image_matrix(image_matrix,
940
+ matrix_size=128,
941
+ num_pca_components=5,
942
+ filter_out_zero_rows=False,
943
+ return_square_matrix_points=False
944
+ ):
945
+
946
+ """
947
+ Reduces an arbitrary image matrix to a square image matrix
948
+ """
949
+
950
+ matrix = np.array(image_matrix)
951
+
952
+ if filter_out_zero_rows:
953
+ matrix = matrix[~np.all(matrix == 0, axis=1)]
954
+
955
+ target_rows = matrix_size
956
+
957
+ rows_per_group = matrix.shape[0] // target_rows
958
+
959
+ compressed_matrix = np.zeros((target_rows, matrix.shape[1]), dtype=np.int32)
960
+
961
+ for i in range(target_rows):
962
+ start_row = i * rows_per_group
963
+ end_row = (i + 1) * rows_per_group
964
+ group = matrix[start_row:end_row, :]
965
+
966
+ pca = PCA(n_components=num_pca_components)
967
+ pca.fit(group)
968
+
969
+ principal_component = np.mean(pca.components_, axis=0)
970
+ contributions = np.dot(group, principal_component)
971
+ selected_row_index = np.argmax(contributions)
972
+
973
+ compressed_matrix[i, :] = group[selected_row_index, :]
974
+
975
+ if return_square_matrix_points:
976
+ filtered_matrix = compressed_matrix[~np.all(compressed_matrix == 0, axis=1)]
977
+
978
+ row_indexes, col_indexes = np.where(filtered_matrix != 0)
979
+ points = np.column_stack((row_indexes, filtered_matrix[row_indexes, col_indexes])).tolist()
980
+
981
+ return points
982
+
983
+ else:
984
+ return compressed_matrix.tolist()
985
+
986
+ ################################################################################
987
+
988
+ def image_matrix_to_images(image_matrix,
989
+ step,
990
+ overlap,
991
+ num_img_channels=3,
992
+ output_folder='./Dataset/',
993
+ output_img_prefix='image',
994
+ output_img_ext='.png',
995
+ save_to_array=False,
996
+ verbose=True
997
+ ):
998
+
999
+ if num_img_channels > 1:
1000
+ n_mat_channels = 3
1001
+
1002
+ else:
1003
+ n_mat_channels = 1
1004
+
1005
+ if not save_to_array:
1006
+
1007
+ if verbose:
1008
+ print('=' * 70)
1009
+ print('Checking output folder dir...')
1010
+
1011
+ os.makedirs(os.path.dirname(output_folder), exist_ok=True)
1012
+
1013
+ if verbose:
1014
+ print('Done!')
1015
+
1016
+ if verbose:
1017
+ print('=' * 70)
1018
+ print('Writing images...')
1019
+
1020
+ matrix = np.array(image_matrix)
1021
+
1022
+ image_array = []
1023
+
1024
+ for i in range(0, max(1, matrix.shape[0]), overlap):
1025
+
1026
+ submatrix = matrix[i:i+step, :]
1027
+
1028
+ if submatrix.shape[0] < 128:
1029
+ zeros_array = np.zeros((128-submatrix.shape[0], 128))
1030
+ submatrix = np.vstack((submatrix, zeros_array))
1031
+
1032
+ if n_mat_channels == 3:
1033
+
1034
+ r = (submatrix // (256*256)) % 256
1035
+ g = (submatrix // 256) % 256
1036
+ b = submatrix % 256
1037
+
1038
+ rgb_image = np.stack((r, g, b), axis=-1).astype(np.uint8)
1039
+ img = Image.fromarray(rgb_image, 'RGB')
1040
+
1041
+ else:
1042
+ grayscale_image = submatrix.astype(np.uint8)
1043
+ img = Image.fromarray(grayscale_image, 'L')
1044
+
1045
+ if save_to_array:
1046
+ image_array.append(np.array(img))
1047
+
1048
+ else:
1049
+ img.save(output_folder + output_img_prefix + '_' + str(matrix.shape[1]) + '_' + str(i).zfill(7) + output_img_ext)
1050
+
1051
+ if verbose:
1052
+ print('Done!')
1053
+ print('=' * 70)
1054
+ print('Saved', (matrix.shape[0] // min(step, overlap))+1, 'imges!')
1055
+ print('=' * 70)
1056
+
1057
+ if save_to_array:
1058
+ return np.array(image_array).tolist()
1059
+
1060
+ ################################################################################
1061
+
1062
+ def images_to_image_matrix(list_of_images,
1063
+ num_img_channels=3
1064
+ ):
1065
+
1066
+ if num_img_channels > 1:
1067
+ n_mat_channels = 3
1068
+
1069
+ else:
1070
+ n_mat_channels = 1
1071
+
1072
+ image_array = np.array(list_of_images)
1073
+
1074
+ original_matrix = []
1075
+
1076
+ for img in image_array:
1077
+
1078
+ if num_img_channels == 3:
1079
+
1080
+ rgb_array = np.array(img)
1081
+
1082
+ matrix = (rgb_array[..., 0].astype(np.int64) * 256*256 +
1083
+ rgb_array[..., 1].astype(np.int64) * 256 +
1084
+ rgb_array[..., 2].astype(np.int64))
1085
+
1086
+ else:
1087
+ matrix = np.array(img)
1088
+
1089
+ original_matrix.extend(matrix)
1090
+
1091
+ return original_matrix
1092
+
1093
+ ################################################################################
1094
+
1095
+ def square_matrix_to_RGB_matrix(square_matrix):
1096
+
1097
+ smatrix = np.array(square_matrix)
1098
+ sq_matrix = smatrix[:smatrix.shape[1]]
1099
+
1100
+ r = (sq_matrix // (256 ** 2)) % 256
1101
+ g = (sq_matrix // 256) % 256
1102
+ b = sq_matrix % 256
1103
+
1104
+ rgb_array = np.stack((r, g, b), axis=-1)
1105
+
1106
+ return rgb_array.tolist()
1107
+
1108
+ ################################################################################
1109
+
1110
+ def upsample_square_matrix(square_matrix, upsampling_factor=4):
1111
+
1112
+ smatrix = np.array(square_matrix)
1113
+ sq_matrix = smatrix[:smatrix.shape[1]]
1114
+
1115
+ scaling_array = np.ones((upsampling_factor, upsampling_factor))
1116
+ scaled_array = np.kron(sq_matrix, scaling_array)
1117
+ scaled_array = scaled_array.astype('int')
1118
+
1119
+ return scaled_array.tolist()
1120
+
1121
+ ################################################################################
1122
+
1123
+ def downsample_square_matrix(square_matrix, downsampling_factor=4):
1124
+
1125
+ smatrix = np.array(square_matrix)
1126
+ sq_matrix = smatrix[:smatrix.shape[1]]
1127
+
1128
+ dmatrix = sq_matrix[::downsampling_factor, ::downsampling_factor]
1129
+ dmatrix = dmatrix.astype('int')
1130
+
1131
+ return dmatrix.tolist()
1132
+
1133
+ ################################################################################
1134
+ # [WIP] Future dev functions
1135
+ ################################################################################
1136
+
1137
+ '''
1138
+ import umap
1139
+
1140
+ def reduce_dimensionality_umap(list_of_values,
1141
+ n_comp=2,
1142
+ n_neighbors=15,
1143
+ ):
1144
+
1145
+ """
1146
+ Reduces the dimensionality of the values using UMAP.
1147
+ """
1148
+
1149
+ vals = np.array(list_of_values)
1150
+
1151
+ umap_reducer = umap.UMAP(n_components=n_comp,
1152
+ n_neighbors=n_neighbors,
1153
+ n_epochs=5000,
1154
+ verbose=True
1155
+ )
1156
+
1157
+ reduced_vals = umap_reducer.fit_transform(vals)
1158
+
1159
+ return reduced_vals.tolist()
1160
+ '''
1161
+
1162
+ ################################################################################
1163
+
1164
+ '''
1165
+ import alphashape
1166
+ from shapely.geometry import Point
1167
+ from matplotlib.tri import Triangulation, LinearTriInterpolator
1168
+ from scipy.stats import zscore
1169
+
1170
+ #===============================================================================
1171
+
1172
+ coordinates = points
1173
+
1174
+ dist_matrix = minkowski_distance_matrix(coordinates, p=3) # You can change the value of p as needed
1175
+
1176
+ # Centering matrix
1177
+ n = dist_matrix.shape[0]
1178
+ H = np.eye(n) - np.ones((n, n)) / n
1179
+
1180
+ # Apply double centering
1181
+ B = -0.5 * H @ dist_matrix**2 @ H
1182
+
1183
+ # Eigen decomposition
1184
+ eigvals, eigvecs = np.linalg.eigh(B)
1185
+
1186
+ # Sort eigenvalues and eigenvectors
1187
+ idx = np.argsort(eigvals)[::-1]
1188
+ eigvals = eigvals[idx]
1189
+ eigvecs = eigvecs[:, idx]
1190
+
1191
+ # Select the top 2 eigenvectors
1192
+ X_transformed = eigvecs[:, :2] * np.sqrt(eigvals[:2])
1193
+
1194
+ #===============================================================================
1195
+
1196
+ src_points = X_transformed
1197
+ src_values = np.array([[p[1]] for p in points]) #np.random.rand(X_transformed.shape[0])
1198
+
1199
+ #===============================================================================
1200
+
1201
+ # Normalize the points to the range [0, 1]
1202
+ scaler = MinMaxScaler()
1203
+ points_normalized = scaler.fit_transform(src_points)
1204
+
1205
+ values_normalized = custom_normalize(src_values)
1206
+
1207
+ # Remove outliers based on z-score
1208
+ z_scores = np.abs(zscore(points_normalized, axis=0))
1209
+ filtered_points = points_normalized[(z_scores < 3).all(axis=1)]
1210
+ filtered_values = values_normalized[(z_scores < 3).all(axis=1)]
1211
+
1212
+ # Compute the concave hull (alpha shape)
1213
+ alpha = 8 # Adjust alpha as needed
1214
+ hull = alphashape.alphashape(filtered_points, alpha)
1215
+
1216
+ # Create a triangulation
1217
+ tri = Triangulation(filtered_points[:, 0], filtered_points[:, 1])
1218
+
1219
+ # Interpolate the values on the triangulation
1220
+ interpolator = LinearTriInterpolator(tri, filtered_values[:, 0])
1221
+ xi, yi = np.meshgrid(np.linspace(0, 1, 100), np.linspace(0, 1, 100))
1222
+ zi = interpolator(xi, yi)
1223
+
1224
+ # Mask out points outside the concave hull
1225
+ mask = np.array([hull.contains(Point(x, y)) for x, y in zip(xi.flatten(), yi.flatten())])
1226
+ zi = np.ma.array(zi, mask=~mask.reshape(zi.shape))
1227
+
1228
+ # Plot the filled contour based on the interpolated values
1229
+ plt.contourf(xi, yi, zi, levels=50, cmap='viridis')
1230
+
1231
+ # Plot the original points
1232
+ #plt.scatter(filtered_points[:, 0], filtered_points[:, 1], c=filtered_values, edgecolors='k')
1233
+
1234
+ plt.title('Filled Contour Plot with Original Values')
1235
+ plt.xlabel('X-axis')
1236
+ plt.ylabel('Y-axis')
1237
+ plt.colorbar(label='Value')
1238
+ plt.show()
1239
+ '''
1240
+
1241
+ ################################################################################
1242
+ #
1243
+ # This is the end of TPLOTS Python modules
1244
+ #
1245
+ ################################################################################