asigalov61 commited on
Commit
38e51a9
·
verified ·
1 Parent(s): ea512e9

Upload TMIDIX.py

Browse files
Files changed (1) hide show
  1. TMIDIX.py +536 -25
TMIDIX.py CHANGED
@@ -5,9 +5,8 @@ r'''############################################################################
5
  #
6
  #
7
  # Tegridy MIDI X Module (TMIDI X / tee-midi eks)
8
- # Version 1.0
9
  #
10
- # NOTE: TMIDI X Module starts after the partial MIDI.py module @ line 1438
11
  #
12
  # Based upon MIDI.py module v.6.7. by Peter Billam / pjb.com.au
13
  #
@@ -26,7 +25,7 @@ r'''############################################################################
26
  # you may not use this file except in compliance with the License.
27
  # You may obtain a copy of the License at
28
  #
29
- # http://www.apache.org/licenses/LICENSE-2.0
30
  #
31
  # Unless required by applicable law or agreed to in writing, software
32
  # distributed under the License is distributed on an "AS IS" BASIS,
@@ -47,7 +46,20 @@ r'''############################################################################
47
  # Copyright 2020 Peter Billam
48
  #
49
  ###################################################################################
50
- ###################################################################################'''
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
  import sys, struct, copy
53
 
@@ -1440,7 +1452,6 @@ def _encode(events_lol, unknown_callback=None, never_add_eot=False,
1440
  ###################################################################################
1441
  #
1442
  # Tegridy MIDI X Module (TMIDI X / tee-midi eks)
1443
- # Version 1.0
1444
  #
1445
  # Based upon and includes the amazing MIDI.py module v.6.7. by Peter Billam
1446
  # pjb.com.au
@@ -1497,6 +1508,8 @@ from pathlib import Path
1497
 
1498
  import shutil
1499
 
 
 
1500
  ###################################################################################
1501
  #
1502
  # Original TMIDI Tegridy helper functions
@@ -4715,7 +4728,8 @@ def augment_enhanced_score_notes(enhanced_score_notes,
4715
  ceil_timings=False,
4716
  round_timings=False,
4717
  legacy_timings=True,
4718
- sort_drums_last=False
 
4719
  ):
4720
 
4721
  esn = copy.deepcopy(enhanced_score_notes)
@@ -4758,6 +4772,16 @@ def augment_enhanced_score_notes(enhanced_score_notes,
4758
  e[4] = max(1, min(127, e[4] + pitch_shift))
4759
 
4760
  pe = enhanced_score_notes[i]
 
 
 
 
 
 
 
 
 
 
4761
 
4762
  if full_sorting:
4763
 
@@ -6698,12 +6722,23 @@ def find_next_bar(escore_notes, bar_time, start_note_idx, cur_bar):
6698
  def align_escore_notes_to_bars(escore_notes,
6699
  bar_time=4000,
6700
  trim_durations=False,
6701
- split_durations=False
 
6702
  ):
6703
 
6704
  #=============================================================================
 
 
 
 
 
 
 
 
 
 
6705
 
6706
- aligned_escore_notes = copy.deepcopy(escore_notes)
6707
 
6708
  abs_time = 0
6709
  nidx = 0
@@ -6715,13 +6750,13 @@ def align_escore_notes_to_bars(escore_notes,
6715
 
6716
  while next_bar:
6717
 
6718
- next_bar = find_next_bar(escore_notes, bar_time, nidx, bcount)
6719
 
6720
  if next_bar:
6721
-
6722
- gescore_notes = escore_notes[nidx:next_bar[1]]
6723
  else:
6724
- gescore_notes = escore_notes[nidx:]
6725
 
6726
  original_timings = [delta] + [(b[1]-a[1]) for a, b in zip(gescore_notes[:-1], gescore_notes[1:])]
6727
  adj_timings = adjust_numbers_to_sum(original_timings, bar_time)
@@ -6736,7 +6771,8 @@ def align_escore_notes_to_bars(escore_notes,
6736
  nidx += 1
6737
 
6738
  if next_bar:
6739
- delta = escore_notes[next_bar[1]][1]-escore_notes[next_bar[1]-1][1]
 
6740
  bcount += 1
6741
 
6742
  #=============================================================================
@@ -11304,26 +11340,57 @@ def system_memory_utilization(return_dict=False):
11304
 
11305
  def create_files_list(datasets_paths=['./'],
11306
  files_exts=['.mid', '.midi', '.kar', '.MID', '.MIDI', '.KAR'],
 
 
 
 
11307
  randomize_files_list=True,
 
11308
  verbose=True
11309
  ):
 
11310
  if verbose:
11311
  print('=' * 70)
11312
  print('Searching for files...')
11313
  print('This may take a while on a large dataset in particular...')
11314
  print('=' * 70)
11315
 
11316
- filez_set = defaultdict(None)
11317
-
11318
  files_exts = tuple(files_exts)
11319
 
 
 
 
11320
  for dataset_addr in tqdm.tqdm(datasets_paths, disable=not verbose):
11321
  for dirpath, dirnames, filenames in os.walk(dataset_addr):
11322
- for file in filenames:
11323
- if file not in filez_set and file.endswith(files_exts):
11324
- filez_set[os.path.join(dirpath, file)] = None
11325
-
11326
- filez = list(filez_set.keys())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11327
 
11328
  if verbose:
11329
  print('Done!')
@@ -11343,6 +11410,7 @@ def create_files_list(datasets_paths=['./'],
11343
 
11344
  if verbose:
11345
  print('Found', len(filez), 'files.')
 
11346
  print('=' * 70)
11347
 
11348
  else:
@@ -11350,8 +11418,20 @@ def create_files_list(datasets_paths=['./'],
11350
  print('Could not find any files...')
11351
  print('Please check dataset dirs and files extensions...')
11352
  print('=' * 70)
 
 
 
 
 
 
 
 
 
 
 
11353
 
11354
- return filez
 
11355
 
11356
  ###################################################################################
11357
 
@@ -12172,8 +12252,16 @@ def escore_notes_pitches_chords_signature(escore_notes,
12172
  sort_by_counts=False,
12173
  use_full_chords=False
12174
  ):
 
 
 
 
 
 
 
 
12175
 
12176
- escore_notes = [e for e in escore_notes if e[6] <= max_patch % 129]
12177
 
12178
  if escore_notes:
12179
 
@@ -12182,7 +12270,7 @@ def escore_notes_pitches_chords_signature(escore_notes,
12182
  sig = []
12183
  dsig = []
12184
 
12185
- drums_offset = 321 + 128
12186
 
12187
  bad_chords_counter = 0
12188
 
@@ -12199,10 +12287,10 @@ def escore_notes_pitches_chords_signature(escore_notes,
12199
  tones_chord = sorted(set([p % 12 for p in pitches]))
12200
 
12201
  try:
12202
- sig_token = ALL_CHORDS_SORTED.index(tones_chord) + 128
12203
  except:
12204
  checked_tones_chord = check_and_fix_tones_chord(tones_chord, use_full_chords=use_full_chords)
12205
- sig_token = ALL_CHORDS_SORTED.index(checked_tones_chord) + 128
12206
  bad_chords_counter += 1
12207
 
12208
  elif len(pitches) == 1:
@@ -12359,6 +12447,429 @@ def copy_file(src_file: str, trg_dir: str, add_subdir: bool = False, verbose: bo
12359
 
12360
  return None
12361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12362
  ###################################################################################
12363
  # This is the end of the TMIDI X Python module
12364
  ###################################################################################
 
5
  #
6
  #
7
  # Tegridy MIDI X Module (TMIDI X / tee-midi eks)
 
8
  #
9
+ # NOTE: TMIDI X Module starts after the partial MIDI.py module @ line 1450
10
  #
11
  # Based upon MIDI.py module v.6.7. by Peter Billam / pjb.com.au
12
  #
 
25
  # you may not use this file except in compliance with the License.
26
  # You may obtain a copy of the License at
27
  #
28
+ # http://www.apache.org/licenses/LICENSE-2.0
29
  #
30
  # Unless required by applicable law or agreed to in writing, software
31
  # distributed under the License is distributed on an "AS IS" BASIS,
 
46
  # Copyright 2020 Peter Billam
47
  #
48
  ###################################################################################
49
+ ###################################################################################
50
+ '''
51
+
52
+ ###################################################################################
53
+
54
+ __version__ = "25.4.11"
55
+
56
+ print('=' * 70)
57
+ print('TMIDIX Python module')
58
+ print('Version:', __version__)
59
+ print('=' * 70)
60
+ print('Loading module...')
61
+
62
+ ###################################################################################
63
 
64
  import sys, struct, copy
65
 
 
1452
  ###################################################################################
1453
  #
1454
  # Tegridy MIDI X Module (TMIDI X / tee-midi eks)
 
1455
  #
1456
  # Based upon and includes the amazing MIDI.py module v.6.7. by Peter Billam
1457
  # pjb.com.au
 
1508
 
1509
  import shutil
1510
 
1511
+ import hashlib
1512
+
1513
  ###################################################################################
1514
  #
1515
  # Original TMIDI Tegridy helper functions
 
4728
  ceil_timings=False,
4729
  round_timings=False,
4730
  legacy_timings=True,
4731
+ sort_drums_last=False,
4732
+ even_timings=False
4733
  ):
4734
 
4735
  esn = copy.deepcopy(enhanced_score_notes)
 
4772
  e[4] = max(1, min(127, e[4] + pitch_shift))
4773
 
4774
  pe = enhanced_score_notes[i]
4775
+
4776
+
4777
+ if even_timings:
4778
+
4779
+ for e in esn:
4780
+ if e[1] % 2 != 0:
4781
+ e[1] += 1
4782
+
4783
+ if e[2] % 2 != 0:
4784
+ e[2] += 1
4785
 
4786
  if full_sorting:
4787
 
 
6722
  def align_escore_notes_to_bars(escore_notes,
6723
  bar_time=4000,
6724
  trim_durations=False,
6725
+ split_durations=False,
6726
+ even_timings=False
6727
  ):
6728
 
6729
  #=============================================================================
6730
+
6731
+ escore = copy.deepcopy(escore_notes)
6732
+
6733
+ if even_timings:
6734
+ for e in escore:
6735
+ if e[1] % 2 != 0:
6736
+ e[1] += 1
6737
+
6738
+ if e[2] % 2 != 0:
6739
+ e[2] += 1
6740
 
6741
+ aligned_escore_notes = copy.deepcopy(escore)
6742
 
6743
  abs_time = 0
6744
  nidx = 0
 
6750
 
6751
  while next_bar:
6752
 
6753
+ next_bar = find_next_bar(escore, bar_time, nidx, bcount)
6754
 
6755
  if next_bar:
6756
+ gescore_notes = escore[nidx:next_bar[1]]
6757
+
6758
  else:
6759
+ gescore_notes = escore[nidx:]
6760
 
6761
  original_timings = [delta] + [(b[1]-a[1]) for a, b in zip(gescore_notes[:-1], gescore_notes[1:])]
6762
  adj_timings = adjust_numbers_to_sum(original_timings, bar_time)
 
6771
  nidx += 1
6772
 
6773
  if next_bar:
6774
+ delta = escore[next_bar[1]][1]-escore[next_bar[1]-1][1]
6775
+
6776
  bcount += 1
6777
 
6778
  #=============================================================================
 
11340
 
11341
  def create_files_list(datasets_paths=['./'],
11342
  files_exts=['.mid', '.midi', '.kar', '.MID', '.MIDI', '.KAR'],
11343
+ use_md5_hashes=False,
11344
+ max_num_files_per_dir=-1,
11345
+ randomize_dir_files=False,
11346
+ max_total_files=-1,
11347
  randomize_files_list=True,
11348
+ return_dupes=False,
11349
  verbose=True
11350
  ):
11351
+
11352
  if verbose:
11353
  print('=' * 70)
11354
  print('Searching for files...')
11355
  print('This may take a while on a large dataset in particular...')
11356
  print('=' * 70)
11357
 
 
 
11358
  files_exts = tuple(files_exts)
11359
 
11360
+ filez_set = defaultdict(None)
11361
+ dupes_list = []
11362
+
11363
  for dataset_addr in tqdm.tqdm(datasets_paths, disable=not verbose):
11364
  for dirpath, dirnames, filenames in os.walk(dataset_addr):
11365
+
11366
+ if randomize_dir_files:
11367
+ random.shuffle(filenames)
11368
+
11369
+ if max_num_files_per_dir > 0:
11370
+ max_num_files = max_num_files_per_dir
11371
+
11372
+ else:
11373
+ max_num_files = len(filenames)
11374
+
11375
+ for file in filenames[:max_num_files]:
11376
+ if file.endswith(files_exts):
11377
+ if use_md5_hashes:
11378
+ md5_hash = hashlib.md5(open(os.path.join(dirpath, file), 'rb').read()).hexdigest()
11379
+
11380
+ if md5_hash not in filez_set:
11381
+ filez_set[md5_hash] = os.path.join(dirpath, file)
11382
+
11383
+ else:
11384
+ dupes_list.append(os.path.join(dirpath, file))
11385
+
11386
+ else:
11387
+ if file not in filez_set:
11388
+ filez_set[file] = os.path.join(dirpath, file)
11389
+
11390
+ else:
11391
+ dupes_list.append(os.path.join(dirpath, file))
11392
+
11393
+ filez = list(filez_set.values())
11394
 
11395
  if verbose:
11396
  print('Done!')
 
11410
 
11411
  if verbose:
11412
  print('Found', len(filez), 'files.')
11413
+ print('Skipped', len(dupes_list), 'duplicate files.')
11414
  print('=' * 70)
11415
 
11416
  else:
 
11418
  print('Could not find any files...')
11419
  print('Please check dataset dirs and files extensions...')
11420
  print('=' * 70)
11421
+
11422
+ if max_total_files > 0:
11423
+ if return_dupes:
11424
+ return filez[:max_total_files], dupes_list
11425
+
11426
+ else:
11427
+ return filez[:max_total_files]
11428
+
11429
+ else:
11430
+ if return_dupes:
11431
+ return filez, dupes_list
11432
 
11433
+ else:
11434
+ return filez
11435
 
11436
  ###################################################################################
11437
 
 
12252
  sort_by_counts=False,
12253
  use_full_chords=False
12254
  ):
12255
+
12256
+ if use_full_chords:
12257
+ CHORDS = ALL_CHORDS_FULL
12258
+
12259
+ else:
12260
+ CHORDS = ALL_CHORDS_SORTED
12261
+
12262
+ max_patch = max(0, min(128, max_patch))
12263
 
12264
+ escore_notes = [e for e in escore_notes if e[6] <= max_patch]
12265
 
12266
  if escore_notes:
12267
 
 
12270
  sig = []
12271
  dsig = []
12272
 
12273
+ drums_offset = len(CHORDS) + 128
12274
 
12275
  bad_chords_counter = 0
12276
 
 
12287
  tones_chord = sorted(set([p % 12 for p in pitches]))
12288
 
12289
  try:
12290
+ sig_token = CHORDS.index(tones_chord) + 128
12291
  except:
12292
  checked_tones_chord = check_and_fix_tones_chord(tones_chord, use_full_chords=use_full_chords)
12293
+ sig_token = CHORDS.index(checked_tones_chord) + 128
12294
  bad_chords_counter += 1
12295
 
12296
  elif len(pitches) == 1:
 
12447
 
12448
  return None
12449
 
12450
+ ###################################################################################
12451
+
12452
+ def escore_notes_even_timings(escore_notes, in_place=True):
12453
+
12454
+ if in_place:
12455
+ for e in escore_notes:
12456
+ if e[1] % 2 != 0:
12457
+ e[1] += 1
12458
+
12459
+ if e[2] % 2 != 0:
12460
+ e[2] += 1
12461
+
12462
+ return []
12463
+
12464
+ else:
12465
+ escore = copy.deepcopy(escore_notes)
12466
+
12467
+ for e in escore:
12468
+ if e[1] % 2 != 0:
12469
+ e[1] += 1
12470
+
12471
+ if e[2] % 2 != 0:
12472
+ e[2] += 1
12473
+
12474
+ return escore
12475
+
12476
+ ###################################################################################
12477
+
12478
+ def both_chords(chord1, chord2, merge_threshold=2):
12479
+
12480
+ if len(chord1) > 1 and len(chord2) > 0 and chord2[0][1]-chord1[0][1] <= merge_threshold:
12481
+ return True
12482
+
12483
+ elif len(chord1) > 0 and len(chord2) > 1 and chord2[0][1]-chord1[0][1] <= merge_threshold:
12484
+ return True
12485
+
12486
+ else:
12487
+ return False
12488
+
12489
+ def merge_chords(chord1, chord2, sort_drums_last=False):
12490
+
12491
+ mchord = chord1
12492
+
12493
+ seen = []
12494
+
12495
+ for e in chord2:
12496
+ if tuple([e[4], e[6]]) not in seen:
12497
+ mchord.append(e)
12498
+ seen.append(tuple([e[4], e[6]]))
12499
+
12500
+ for e in mchord[1:]:
12501
+ e[1] = mchord[0][1]
12502
+
12503
+ if sort_drums_last:
12504
+ mchord.sort(key=lambda x: (x[4], x[6]) if x[6] != 128 else (x[6], -x[4]))
12505
+
12506
+ else:
12507
+ mchord.sort(key=lambda x: (x[4], x[6]))
12508
+
12509
+ return mchord
12510
+
12511
+ def merge_escore_notes(escore_notes, merge_threshold=2, sort_drums_last=False):
12512
+
12513
+ cscore = chordify_score([1000, escore_notes])
12514
+
12515
+ merged_chords = []
12516
+ merged_chord = cscore[0]
12517
+
12518
+ for i in range(1, len(cscore)):
12519
+
12520
+ cchord = cscore[i]
12521
+
12522
+ if both_chords(merged_chord, cchord, merge_threshold=merge_threshold):
12523
+ merged_chord = merge_chords(merged_chord, cchord, sort_drums_last=sort_drums_last)
12524
+
12525
+ else:
12526
+ merged_chords.append(merged_chord)
12527
+ merged_chord = cchord
12528
+
12529
+ return flatten(merged_chords)
12530
+
12531
+ ###################################################################################
12532
+
12533
+ def solo_piano_escore_notes_tokenized(escore_notes,
12534
+ compress_start_times=True,
12535
+ encode_velocities=False,
12536
+ verbose=False
12537
+ ):
12538
+
12539
+ if verbose:
12540
+ print('=' * 70)
12541
+ print('Encoding MIDI...')
12542
+
12543
+ sp_escore_notes = solo_piano_escore_notes(escore_notes)
12544
+ zscore = recalculate_score_timings(sp_escore_notes)
12545
+ dscore = delta_score_notes(zscore, timings_clip_value=127)
12546
+
12547
+ score = []
12548
+
12549
+ notes_counter = 0
12550
+ chords_counter = 1
12551
+
12552
+ for i, e in enumerate(dscore):
12553
+
12554
+ dtime = e[1]
12555
+ dur = e[2]
12556
+ ptc = e[4]
12557
+ vel = e[5]
12558
+
12559
+ if compress_start_times:
12560
+
12561
+ if i == 0:
12562
+ score.extend([0, dur+128, ptc+256])
12563
+
12564
+ if encode_velocities:
12565
+ score.append(vel+384)
12566
+
12567
+ else:
12568
+ if dtime == 0:
12569
+ score.extend([dur+128, ptc+256])
12570
+
12571
+ else:
12572
+ score.extend([dtime, dur+128, ptc+256])
12573
+
12574
+ if encode_velocities:
12575
+ score.append(vel+384)
12576
+
12577
+ if dtime != 0:
12578
+ chords_counter += 1
12579
+
12580
+ else:
12581
+ score.extend([dtime, dur+128, ptc+256])
12582
+
12583
+ if encode_velocities:
12584
+ score.append(vel+384)
12585
+
12586
+ if dtime != 0:
12587
+ chords_counter += 1
12588
+
12589
+ notes_counter += 1
12590
+
12591
+ if verbose:
12592
+ print('Done!')
12593
+ print('=' * 70)
12594
+
12595
+ print('Source MIDI composition has', len(zscore), 'notes')
12596
+ print('Source MIDI composition has', len([d[1] for d in dscore if d[1] !=0 ])+1, 'chords')
12597
+ print('-' * 70)
12598
+ print('Encoded sequence has', notes_counter, 'pitches')
12599
+ print('Encoded sequence has', chords_counter, 'chords')
12600
+ print('-' * 70)
12601
+ print('Final encoded sequence has', len(score), 'tokens')
12602
+ print('=' * 70)
12603
+
12604
+ return score
12605
+
12606
+ ###################################################################################
12607
+
12608
+ def equalize_closest_elements_dynamic(seq,
12609
+ min_val=128,
12610
+ max_val=256,
12611
+ splitting_factor=1.5,
12612
+ tightness_threshold=0.15
12613
+ ):
12614
+
12615
+ candidates = [(i, x) for i, x in enumerate(seq) if min_val <= x <= max_val]
12616
+
12617
+ if len(candidates) < 2:
12618
+ return seq.copy()
12619
+
12620
+ sorted_candidates = sorted(candidates, key=lambda pair: pair[1])
12621
+ candidate_values = [val for _, val in sorted_candidates]
12622
+
12623
+ differences = [candidate_values[i+1] - candidate_values[i] for i in range(len(candidate_values)-1)]
12624
+
12625
+ def median(lst):
12626
+
12627
+ n = len(lst)
12628
+ sorted_lst = sorted(lst)
12629
+ mid = n // 2
12630
+
12631
+ if n % 2 == 0:
12632
+ return (sorted_lst[mid - 1] + sorted_lst[mid]) / 2.0
12633
+
12634
+ else:
12635
+ return sorted_lst[mid]
12636
+
12637
+ med_diff = median(differences)
12638
+
12639
+ split_indices = [i for i, diff in enumerate(differences) if diff > splitting_factor * med_diff]
12640
+
12641
+ clusters = []
12642
+
12643
+ if split_indices:
12644
+ start = 0
12645
+ for split_index in split_indices:
12646
+ clusters.append(sorted_candidates[start:split_index+1])
12647
+ start = split_index + 1
12648
+ clusters.append(sorted_candidates[start:])
12649
+
12650
+ else:
12651
+ clusters = [sorted_candidates]
12652
+
12653
+
12654
+ valid_clusters = [cluster for cluster in clusters if len(cluster) >= 2]
12655
+ if not valid_clusters:
12656
+ return seq.copy()
12657
+
12658
+ def cluster_spread(cluster):
12659
+ values = [val for (_, val) in cluster]
12660
+ return max(values) - min(values)
12661
+
12662
+ valid_clusters.sort(key=lambda cluster: (len(cluster), -cluster_spread(cluster)), reverse=True)
12663
+ selected_cluster = valid_clusters[0]
12664
+
12665
+ allowed_range_width = max_val - min_val
12666
+ spread = cluster_spread(selected_cluster)
12667
+ ratio = spread / allowed_range_width
12668
+
12669
+ if ratio > tightness_threshold:
12670
+ return seq.copy()
12671
+
12672
+ cluster_values = [val for (_, val) in selected_cluster]
12673
+ equal_value = sum(cluster_values) // len(cluster_values)
12674
+
12675
+
12676
+ result = list(seq)
12677
+ for idx, _ in selected_cluster:
12678
+ result[idx] = equal_value
12679
+
12680
+ return result
12681
+
12682
+ ###################################################################################
12683
+
12684
+ def chunk_list(lst, chunk_size):
12685
+ return [lst[i:i + chunk_size] for i in range(0, len(lst), chunk_size)]
12686
+
12687
+ ###################################################################################
12688
+
12689
+ def compress_tokens_sequence(seq,
12690
+ min_val=128,
12691
+ max_val=256,
12692
+ group_size=2,
12693
+ splitting_factor=1.5,
12694
+ tightness_threshold=0.15
12695
+ ):
12696
+
12697
+ comp_seq = equalize_closest_elements_dynamic(seq,
12698
+ min_val,
12699
+ max_val,
12700
+ splitting_factor=splitting_factor,
12701
+ tightness_threshold=tightness_threshold
12702
+ )
12703
+
12704
+ seq_split = sorted(chunk_list(comp_seq, group_size), key=lambda x: (-x[0], -x[1]))
12705
+
12706
+ seq_grouped = [[[k]] + [vv[1:] for vv in v] for k, v in groupby(seq_split, key=lambda x: x[0])]
12707
+
12708
+ return flatten(flatten(sorted(seq_grouped, key=lambda x: -x[1][0])))
12709
+
12710
+ ###################################################################################
12711
+
12712
+ def merge_adjacent_pairs(values_counts):
12713
+
12714
+ merged = []
12715
+ i = 0
12716
+
12717
+ while i < len(values_counts):
12718
+
12719
+ if i < len(values_counts) - 1:
12720
+ value1, count1 = values_counts[i]
12721
+ value2, count2 = values_counts[i + 1]
12722
+
12723
+ if value2 - value1 == 1:
12724
+ if count2 > count1:
12725
+ merged_value = value2
12726
+
12727
+ else:
12728
+ merged_value = value1
12729
+
12730
+ merged_count = count1 + count2
12731
+ merged.append((merged_value, merged_count))
12732
+
12733
+ i += 2
12734
+
12735
+ continue
12736
+
12737
+ merged.append(values_counts[i])
12738
+
12739
+ i += 1
12740
+
12741
+ return merged
12742
+
12743
+ ###################################################################################
12744
+
12745
+ def merge_escore_notes_start_times(escore_notes, num_merges=1):
12746
+
12747
+ new_dscore = delta_score_notes(escore_notes)
12748
+
12749
+ times = [e[1] for e in new_dscore if e[1] != 0]
12750
+ times_counts = sorted(Counter(times).most_common())
12751
+
12752
+ prev_counts = []
12753
+ new_times_counts = times_counts
12754
+
12755
+ mcount = 0
12756
+
12757
+ while prev_counts != new_times_counts:
12758
+ prev_counts = new_times_counts
12759
+ new_times_counts = merge_adjacent_pairs(new_times_counts)
12760
+
12761
+ mcount += 1
12762
+
12763
+ if mcount == num_merges:
12764
+ break
12765
+
12766
+ gtimes = [r[0] for r in new_times_counts]
12767
+
12768
+ for e in new_dscore:
12769
+ if e[1] > 0:
12770
+ e[1] = find_closest_value(gtimes, e[1])[0]
12771
+ e[2] -= num_merges
12772
+
12773
+ return delta_score_to_abs_score(new_dscore)
12774
+
12775
+ ###################################################################################
12776
+
12777
+ def multi_instrumental_escore_notes_tokenized(escore_notes, compress_seq=False):
12778
+
12779
+ melody_chords = []
12780
+
12781
+ pe = escore_notes[0]
12782
+
12783
+ for i, e in enumerate(escore_notes):
12784
+
12785
+ dtime = max(0, min(255, e[1]-pe[1]))
12786
+
12787
+ dur = max(0, min(255, e[2]))
12788
+
12789
+ cha = max(0, min(15, e[3]))
12790
+
12791
+ if cha == 9:
12792
+ pat = 128
12793
+
12794
+ else:
12795
+ pat = max(0, min(127, e[6]))
12796
+
12797
+ ptc = max(0, min(127, e[4]))
12798
+
12799
+ vel = max(8, min(127, e[5]))
12800
+ velocity = round(vel / 15)-1
12801
+
12802
+ dur_vel = (8 * dur) + velocity
12803
+ pat_ptc = (129 * pat) + ptc
12804
+
12805
+ if compress_seq:
12806
+ if dtime != 0 or i == 0:
12807
+ melody_chords.extend([dtime, dur_vel+256, pat_ptc+2304])
12808
+
12809
+ else:
12810
+ melody_chords.extend([dur_vel+256, pat_ptc+2304])
12811
+
12812
+ else:
12813
+ melody_chords.extend([dtime, dur_vel+256, pat_ptc+2304])
12814
+
12815
+ pe = e
12816
+
12817
+ return melody_chords
12818
+
12819
+ ###################################################################################
12820
+
12821
+ def merge_counts(data, return_lists=True):
12822
+
12823
+ merged = defaultdict(int)
12824
+
12825
+ for value, count in data:
12826
+ merged[value] += count
12827
+
12828
+ if return_lists:
12829
+ return [[k, v] for k, v in merged.items()]
12830
+
12831
+ else:
12832
+ return list(merged.items())
12833
+
12834
+ ###################################################################################
12835
+
12836
+ def convert_escore_notes_pitches_chords_signature(signature, convert_to_full_chords=True):
12837
+
12838
+ if convert_to_full_chords:
12839
+ SRC_CHORDS = ALL_CHORDS_SORTED
12840
+ TRG_CHORDS = ALL_CHORDS_FULL
12841
+
12842
+ else:
12843
+ SRC_CHORDS = ALL_CHORDS_FULL
12844
+ TRG_CHORDS = ALL_CHORDS_SORTED
12845
+
12846
+ cdiff = len(TRG_CHORDS) - len(SRC_CHORDS)
12847
+
12848
+ pitches_counts = [c for c in signature if -1 < c[0] < 128]
12849
+ chords_counts = [c for c in signature if 127 < c[0] < len(SRC_CHORDS)+128]
12850
+ drums_counts = [[c[0]-cdiff, c[1]] for c in signature if len(SRC_CHORDS)+127 < c[0] < len(SRC_CHORDS)+256]
12851
+ bad_chords_count = [c for c in signature if c[0] == -1]
12852
+
12853
+ new_chords_counts = []
12854
+
12855
+ for c in chords_counts:
12856
+ tones_chord = SRC_CHORDS[c[0]-128]
12857
+
12858
+ if tones_chord not in TRG_CHORDS:
12859
+ tones_chord = check_and_fix_tones_chord(tones_chord, use_full_chords=convert_to_full_chords)
12860
+ bad_chords_count[0][1] += 1
12861
+
12862
+ new_chords_counts.append([TRG_CHORDS.index(tones_chord)+128, c[1]])
12863
+
12864
+ return pitches_counts + merge_counts(new_chords_counts) + drums_counts + bad_chords_count
12865
+
12866
+ ###################################################################################
12867
+
12868
+ print('Module loaded!')
12869
+ print('=' * 70)
12870
+ print('Enjoy! :)')
12871
+ print('=' * 70)
12872
+
12873
  ###################################################################################
12874
  # This is the end of the TMIDI X Python module
12875
  ###################################################################################