Upload TMIDIX.py
Browse files
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
|
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 |
-
#
|
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(
|
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(
|
6719 |
|
6720 |
if next_bar:
|
6721 |
-
|
6722 |
-
|
6723 |
else:
|
6724 |
-
gescore_notes =
|
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 =
|
|
|
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 |
-
|
11323 |
-
|
11324 |
-
|
11325 |
-
|
11326 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
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
|
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 =
|
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 =
|
12203 |
except:
|
12204 |
checked_tones_chord = check_and_fix_tones_chord(tones_chord, use_full_chords=use_full_chords)
|
12205 |
-
sig_token =
|
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 |
###################################################################################
|