Spaces:
Running
on
Zero
Running
on
Zero
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,9 +46,23 @@ r'''############################################################################
|
|
| 47 |
# Copyright 2020 Peter Billam
|
| 48 |
#
|
| 49 |
###################################################################################
|
| 50 |
-
###################################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
import sys, struct, copy
|
|
|
|
| 53 |
Version = '6.7'
|
| 54 |
VersionDate = '20201120'
|
| 55 |
|
|
@@ -1439,7 +1452,6 @@ def _encode(events_lol, unknown_callback=None, never_add_eot=False,
|
|
| 1439 |
###################################################################################
|
| 1440 |
#
|
| 1441 |
# Tegridy MIDI X Module (TMIDI X / tee-midi eks)
|
| 1442 |
-
# Version 1.0
|
| 1443 |
#
|
| 1444 |
# Based upon and includes the amazing MIDI.py module v.6.7. by Peter Billam
|
| 1445 |
# pjb.com.au
|
|
@@ -1476,6 +1488,7 @@ from itertools import groupby
|
|
| 1476 |
|
| 1477 |
from collections import Counter
|
| 1478 |
from collections import defaultdict
|
|
|
|
| 1479 |
|
| 1480 |
from operator import itemgetter
|
| 1481 |
|
|
@@ -1492,6 +1505,14 @@ import psutil
|
|
| 1492 |
|
| 1493 |
import json
|
| 1494 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1495 |
###################################################################################
|
| 1496 |
#
|
| 1497 |
# Original TMIDI Tegridy helper functions
|
|
@@ -3844,7 +3865,10 @@ def chordify_score(score,
|
|
| 3844 |
else:
|
| 3845 |
return None
|
| 3846 |
|
| 3847 |
-
def fix_monophonic_score_durations(monophonic_score
|
|
|
|
|
|
|
|
|
|
| 3848 |
|
| 3849 |
fixed_score = []
|
| 3850 |
|
|
@@ -3856,15 +3880,17 @@ def fix_monophonic_score_durations(monophonic_score):
|
|
| 3856 |
nmt = monophonic_score[i+1][1]
|
| 3857 |
|
| 3858 |
if note[1]+note[2] >= nmt:
|
| 3859 |
-
note_dur = nmt-note[1]-
|
| 3860 |
else:
|
| 3861 |
note_dur = note[2]
|
| 3862 |
|
| 3863 |
new_note = [note[0], note[1], note_dur] + note[3:]
|
| 3864 |
-
|
| 3865 |
-
|
| 3866 |
-
|
| 3867 |
-
|
|
|
|
|
|
|
| 3868 |
|
| 3869 |
elif type(monophonic_score[0][0]) == int:
|
| 3870 |
|
|
@@ -3874,15 +3900,17 @@ def fix_monophonic_score_durations(monophonic_score):
|
|
| 3874 |
nmt = monophonic_score[i+1][0]
|
| 3875 |
|
| 3876 |
if note[0]+note[1] >= nmt:
|
| 3877 |
-
note_dur = nmt-note[0]-
|
| 3878 |
else:
|
| 3879 |
note_dur = note[1]
|
| 3880 |
-
|
| 3881 |
new_note = [note[0], note_dur] + note[2:]
|
| 3882 |
-
|
| 3883 |
-
|
| 3884 |
-
|
| 3885 |
-
|
|
|
|
|
|
|
| 3886 |
|
| 3887 |
return fixed_score
|
| 3888 |
|
|
@@ -4144,15 +4172,16 @@ def tones_chord_to_pitches(tones_chord, base_pitch=60):
|
|
| 4144 |
###################################################################################
|
| 4145 |
|
| 4146 |
def advanced_score_processor(raw_score,
|
| 4147 |
-
|
| 4148 |
-
|
| 4149 |
-
|
| 4150 |
-
|
| 4151 |
-
|
| 4152 |
-
|
| 4153 |
-
|
| 4154 |
-
|
| 4155 |
-
|
|
|
|
| 4156 |
):
|
| 4157 |
|
| 4158 |
'''TMIDIX Advanced Score Processor'''
|
|
@@ -4192,6 +4221,9 @@ def advanced_score_processor(raw_score,
|
|
| 4192 |
e[2] = e[2] % 16
|
| 4193 |
e[3] = e[3] % 128
|
| 4194 |
|
|
|
|
|
|
|
|
|
|
| 4195 |
basic_single_track_score.sort(key=lambda x: x[4] if x[0] == 'note' else 128, reverse=True)
|
| 4196 |
basic_single_track_score.sort(key=lambda x: x[1])
|
| 4197 |
|
|
@@ -4706,7 +4738,8 @@ def augment_enhanced_score_notes(enhanced_score_notes,
|
|
| 4706 |
ceil_timings=False,
|
| 4707 |
round_timings=False,
|
| 4708 |
legacy_timings=True,
|
| 4709 |
-
sort_drums_last=False
|
|
|
|
| 4710 |
):
|
| 4711 |
|
| 4712 |
esn = copy.deepcopy(enhanced_score_notes)
|
|
@@ -4749,6 +4782,16 @@ def augment_enhanced_score_notes(enhanced_score_notes,
|
|
| 4749 |
e[4] = max(1, min(127, e[4] + pitch_shift))
|
| 4750 |
|
| 4751 |
pe = enhanced_score_notes[i]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4752 |
|
| 4753 |
if full_sorting:
|
| 4754 |
|
|
@@ -6689,12 +6732,23 @@ def find_next_bar(escore_notes, bar_time, start_note_idx, cur_bar):
|
|
| 6689 |
def align_escore_notes_to_bars(escore_notes,
|
| 6690 |
bar_time=4000,
|
| 6691 |
trim_durations=False,
|
| 6692 |
-
split_durations=False
|
|
|
|
| 6693 |
):
|
| 6694 |
|
| 6695 |
#=============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6696 |
|
| 6697 |
-
aligned_escore_notes = copy.deepcopy(
|
| 6698 |
|
| 6699 |
abs_time = 0
|
| 6700 |
nidx = 0
|
|
@@ -6706,13 +6760,13 @@ def align_escore_notes_to_bars(escore_notes,
|
|
| 6706 |
|
| 6707 |
while next_bar:
|
| 6708 |
|
| 6709 |
-
next_bar = find_next_bar(
|
| 6710 |
|
| 6711 |
if next_bar:
|
| 6712 |
-
|
| 6713 |
-
|
| 6714 |
else:
|
| 6715 |
-
gescore_notes =
|
| 6716 |
|
| 6717 |
original_timings = [delta] + [(b[1]-a[1]) for a, b in zip(gescore_notes[:-1], gescore_notes[1:])]
|
| 6718 |
adj_timings = adjust_numbers_to_sum(original_timings, bar_time)
|
|
@@ -6727,7 +6781,8 @@ def align_escore_notes_to_bars(escore_notes,
|
|
| 6727 |
nidx += 1
|
| 6728 |
|
| 6729 |
if next_bar:
|
| 6730 |
-
delta =
|
|
|
|
| 6731 |
bcount += 1
|
| 6732 |
|
| 6733 |
#=============================================================================
|
|
@@ -11138,13 +11193,17 @@ def escore_notes_core(escore_notes, core_len=128):
|
|
| 11138 |
|
| 11139 |
###################################################################################
|
| 11140 |
|
| 11141 |
-
def multiprocessing_wrapper(function, data_list):
|
| 11142 |
|
| 11143 |
with multiprocessing.Pool() as pool:
|
| 11144 |
|
| 11145 |
results = []
|
| 11146 |
|
| 11147 |
-
for result in tqdm.tqdm(pool.imap_unordered(function, data_list),
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11148 |
results.append(result)
|
| 11149 |
|
| 11150 |
return results
|
|
@@ -11293,28 +11352,83 @@ def system_memory_utilization(return_dict=False):
|
|
| 11293 |
|
| 11294 |
###################################################################################
|
| 11295 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11296 |
def create_files_list(datasets_paths=['./'],
|
| 11297 |
files_exts=['.mid', '.midi', '.kar', '.MID', '.MIDI', '.KAR'],
|
|
|
|
|
|
|
|
|
|
| 11298 |
randomize_files_list=True,
|
|
|
|
|
|
|
|
|
|
| 11299 |
verbose=True
|
| 11300 |
):
|
|
|
|
| 11301 |
if verbose:
|
| 11302 |
print('=' * 70)
|
| 11303 |
print('Searching for files...')
|
| 11304 |
print('This may take a while on a large dataset in particular...')
|
| 11305 |
print('=' * 70)
|
| 11306 |
|
| 11307 |
-
filez_set = defaultdict(None)
|
| 11308 |
-
|
| 11309 |
files_exts = tuple(files_exts)
|
| 11310 |
|
| 11311 |
-
|
| 11312 |
-
|
| 11313 |
-
|
| 11314 |
-
|
| 11315 |
-
|
| 11316 |
-
|
| 11317 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11318 |
|
| 11319 |
if verbose:
|
| 11320 |
print('Done!')
|
|
@@ -11334,6 +11448,7 @@ def create_files_list(datasets_paths=['./'],
|
|
| 11334 |
|
| 11335 |
if verbose:
|
| 11336 |
print('Found', len(filez), 'files.')
|
|
|
|
| 11337 |
print('=' * 70)
|
| 11338 |
|
| 11339 |
else:
|
|
@@ -11341,8 +11456,20 @@ def create_files_list(datasets_paths=['./'],
|
|
| 11341 |
print('Could not find any files...')
|
| 11342 |
print('Please check dataset dirs and files extensions...')
|
| 11343 |
print('=' * 70)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11344 |
|
| 11345 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11346 |
|
| 11347 |
###################################################################################
|
| 11348 |
|
|
@@ -12163,8 +12290,16 @@ def escore_notes_pitches_chords_signature(escore_notes,
|
|
| 12163 |
sort_by_counts=False,
|
| 12164 |
use_full_chords=False
|
| 12165 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12166 |
|
| 12167 |
-
escore_notes = [e for e in escore_notes if e[6] <= max_patch
|
| 12168 |
|
| 12169 |
if escore_notes:
|
| 12170 |
|
|
@@ -12173,7 +12308,7 @@ def escore_notes_pitches_chords_signature(escore_notes,
|
|
| 12173 |
sig = []
|
| 12174 |
dsig = []
|
| 12175 |
|
| 12176 |
-
drums_offset =
|
| 12177 |
|
| 12178 |
bad_chords_counter = 0
|
| 12179 |
|
|
@@ -12190,10 +12325,10 @@ def escore_notes_pitches_chords_signature(escore_notes,
|
|
| 12190 |
tones_chord = sorted(set([p % 12 for p in pitches]))
|
| 12191 |
|
| 12192 |
try:
|
| 12193 |
-
sig_token =
|
| 12194 |
except:
|
| 12195 |
checked_tones_chord = check_and_fix_tones_chord(tones_chord, use_full_chords=use_full_chords)
|
| 12196 |
-
sig_token =
|
| 12197 |
bad_chords_counter += 1
|
| 12198 |
|
| 12199 |
elif len(pitches) == 1:
|
|
@@ -12226,6 +12361,792 @@ def escore_notes_pitches_chords_signature(escore_notes,
|
|
| 12226 |
else:
|
| 12227 |
return []
|
| 12228 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12229 |
###################################################################################
|
| 12230 |
# This is the end of the TMIDI X Python module
|
| 12231 |
###################################################################################
|
|
|
|
| 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.5.6"
|
| 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 |
+
|
| 66 |
Version = '6.7'
|
| 67 |
VersionDate = '20201120'
|
| 68 |
|
|
|
|
| 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
|
|
|
|
| 1488 |
|
| 1489 |
from collections import Counter
|
| 1490 |
from collections import defaultdict
|
| 1491 |
+
from collections import OrderedDict
|
| 1492 |
|
| 1493 |
from operator import itemgetter
|
| 1494 |
|
|
|
|
| 1505 |
|
| 1506 |
import json
|
| 1507 |
|
| 1508 |
+
from pathlib import Path
|
| 1509 |
+
|
| 1510 |
+
import shutil
|
| 1511 |
+
|
| 1512 |
+
import hashlib
|
| 1513 |
+
|
| 1514 |
+
from array import array
|
| 1515 |
+
|
| 1516 |
###################################################################################
|
| 1517 |
#
|
| 1518 |
# Original TMIDI Tegridy helper functions
|
|
|
|
| 3865 |
else:
|
| 3866 |
return None
|
| 3867 |
|
| 3868 |
+
def fix_monophonic_score_durations(monophonic_score,
|
| 3869 |
+
min_notes_gap=1,
|
| 3870 |
+
min_notes_dur=1
|
| 3871 |
+
):
|
| 3872 |
|
| 3873 |
fixed_score = []
|
| 3874 |
|
|
|
|
| 3880 |
nmt = monophonic_score[i+1][1]
|
| 3881 |
|
| 3882 |
if note[1]+note[2] >= nmt:
|
| 3883 |
+
note_dur = max(1, nmt-note[1]-min_notes_gap)
|
| 3884 |
else:
|
| 3885 |
note_dur = note[2]
|
| 3886 |
|
| 3887 |
new_note = [note[0], note[1], note_dur] + note[3:]
|
| 3888 |
+
|
| 3889 |
+
if new_note[2] >= min_notes_dur:
|
| 3890 |
+
fixed_score.append(new_note)
|
| 3891 |
+
|
| 3892 |
+
if monophonic_score[-1][2] >= min_notes_dur:
|
| 3893 |
+
fixed_score.append(monophonic_score[-1])
|
| 3894 |
|
| 3895 |
elif type(monophonic_score[0][0]) == int:
|
| 3896 |
|
|
|
|
| 3900 |
nmt = monophonic_score[i+1][0]
|
| 3901 |
|
| 3902 |
if note[0]+note[1] >= nmt:
|
| 3903 |
+
note_dur = max(1, nmt-note[0]-min_notes_gap)
|
| 3904 |
else:
|
| 3905 |
note_dur = note[1]
|
| 3906 |
+
|
| 3907 |
new_note = [note[0], note_dur] + note[2:]
|
| 3908 |
+
|
| 3909 |
+
if new_note[1] >= min_notes_dur:
|
| 3910 |
+
fixed_score.append(new_note)
|
| 3911 |
+
|
| 3912 |
+
if monophonic_score[-1][1] >= min_notes_dur:
|
| 3913 |
+
fixed_score.append(monophonic_score[-1])
|
| 3914 |
|
| 3915 |
return fixed_score
|
| 3916 |
|
|
|
|
| 4172 |
###################################################################################
|
| 4173 |
|
| 4174 |
def advanced_score_processor(raw_score,
|
| 4175 |
+
patches_to_analyze=list(range(129)),
|
| 4176 |
+
return_score_analysis=False,
|
| 4177 |
+
return_enhanced_score=False,
|
| 4178 |
+
return_enhanced_score_notes=False,
|
| 4179 |
+
return_enhanced_monophonic_melody=False,
|
| 4180 |
+
return_chordified_enhanced_score=False,
|
| 4181 |
+
return_chordified_enhanced_score_with_lyrics=False,
|
| 4182 |
+
return_score_tones_chords=False,
|
| 4183 |
+
return_text_and_lyric_events=False,
|
| 4184 |
+
apply_sustain=False
|
| 4185 |
):
|
| 4186 |
|
| 4187 |
'''TMIDIX Advanced Score Processor'''
|
|
|
|
| 4221 |
e[2] = e[2] % 16
|
| 4222 |
e[3] = e[3] % 128
|
| 4223 |
|
| 4224 |
+
if apply_sustain:
|
| 4225 |
+
apply_sustain_to_ms_score([1000, basic_single_track_score])
|
| 4226 |
+
|
| 4227 |
basic_single_track_score.sort(key=lambda x: x[4] if x[0] == 'note' else 128, reverse=True)
|
| 4228 |
basic_single_track_score.sort(key=lambda x: x[1])
|
| 4229 |
|
|
|
|
| 4738 |
ceil_timings=False,
|
| 4739 |
round_timings=False,
|
| 4740 |
legacy_timings=True,
|
| 4741 |
+
sort_drums_last=False,
|
| 4742 |
+
even_timings=False
|
| 4743 |
):
|
| 4744 |
|
| 4745 |
esn = copy.deepcopy(enhanced_score_notes)
|
|
|
|
| 4782 |
e[4] = max(1, min(127, e[4] + pitch_shift))
|
| 4783 |
|
| 4784 |
pe = enhanced_score_notes[i]
|
| 4785 |
+
|
| 4786 |
+
|
| 4787 |
+
if even_timings:
|
| 4788 |
+
|
| 4789 |
+
for e in esn:
|
| 4790 |
+
if e[1] % 2 != 0:
|
| 4791 |
+
e[1] += 1
|
| 4792 |
+
|
| 4793 |
+
if e[2] % 2 != 0:
|
| 4794 |
+
e[2] += 1
|
| 4795 |
|
| 4796 |
if full_sorting:
|
| 4797 |
|
|
|
|
| 6732 |
def align_escore_notes_to_bars(escore_notes,
|
| 6733 |
bar_time=4000,
|
| 6734 |
trim_durations=False,
|
| 6735 |
+
split_durations=False,
|
| 6736 |
+
even_timings=False
|
| 6737 |
):
|
| 6738 |
|
| 6739 |
#=============================================================================
|
| 6740 |
+
|
| 6741 |
+
escore = copy.deepcopy(escore_notes)
|
| 6742 |
+
|
| 6743 |
+
if even_timings:
|
| 6744 |
+
for e in escore:
|
| 6745 |
+
if e[1] % 2 != 0:
|
| 6746 |
+
e[1] += 1
|
| 6747 |
+
|
| 6748 |
+
if e[2] % 2 != 0:
|
| 6749 |
+
e[2] += 1
|
| 6750 |
|
| 6751 |
+
aligned_escore_notes = copy.deepcopy(escore)
|
| 6752 |
|
| 6753 |
abs_time = 0
|
| 6754 |
nidx = 0
|
|
|
|
| 6760 |
|
| 6761 |
while next_bar:
|
| 6762 |
|
| 6763 |
+
next_bar = find_next_bar(escore, bar_time, nidx, bcount)
|
| 6764 |
|
| 6765 |
if next_bar:
|
| 6766 |
+
gescore_notes = escore[nidx:next_bar[1]]
|
| 6767 |
+
|
| 6768 |
else:
|
| 6769 |
+
gescore_notes = escore[nidx:]
|
| 6770 |
|
| 6771 |
original_timings = [delta] + [(b[1]-a[1]) for a, b in zip(gescore_notes[:-1], gescore_notes[1:])]
|
| 6772 |
adj_timings = adjust_numbers_to_sum(original_timings, bar_time)
|
|
|
|
| 6781 |
nidx += 1
|
| 6782 |
|
| 6783 |
if next_bar:
|
| 6784 |
+
delta = escore[next_bar[1]][1]-escore[next_bar[1]-1][1]
|
| 6785 |
+
|
| 6786 |
bcount += 1
|
| 6787 |
|
| 6788 |
#=============================================================================
|
|
|
|
| 11193 |
|
| 11194 |
###################################################################################
|
| 11195 |
|
| 11196 |
+
def multiprocessing_wrapper(function, data_list, verbose=True):
|
| 11197 |
|
| 11198 |
with multiprocessing.Pool() as pool:
|
| 11199 |
|
| 11200 |
results = []
|
| 11201 |
|
| 11202 |
+
for result in tqdm.tqdm(pool.imap_unordered(function, data_list),
|
| 11203 |
+
total=len(data_list),
|
| 11204 |
+
disable=not verbose
|
| 11205 |
+
):
|
| 11206 |
+
|
| 11207 |
results.append(result)
|
| 11208 |
|
| 11209 |
return results
|
|
|
|
| 11352 |
|
| 11353 |
###################################################################################
|
| 11354 |
|
| 11355 |
+
def system_cpus_utilization(return_dict=False):
|
| 11356 |
+
|
| 11357 |
+
if return_dict:
|
| 11358 |
+
return {'num_cpus': psutil.cpu_count(),
|
| 11359 |
+
'cpus_util': psutil.cpu_percent()
|
| 11360 |
+
}
|
| 11361 |
+
|
| 11362 |
+
else:
|
| 11363 |
+
print('Number of CPUs:', psutil.cpu_count())
|
| 11364 |
+
print('CPUs utilization:', psutil.cpu_percent())
|
| 11365 |
+
|
| 11366 |
+
###################################################################################
|
| 11367 |
+
|
| 11368 |
def create_files_list(datasets_paths=['./'],
|
| 11369 |
files_exts=['.mid', '.midi', '.kar', '.MID', '.MIDI', '.KAR'],
|
| 11370 |
+
max_num_files_per_dir=-1,
|
| 11371 |
+
randomize_dir_files=False,
|
| 11372 |
+
max_total_files=-1,
|
| 11373 |
randomize_files_list=True,
|
| 11374 |
+
check_for_dupes=False,
|
| 11375 |
+
use_md5_hashes=False,
|
| 11376 |
+
return_dupes=False,
|
| 11377 |
verbose=True
|
| 11378 |
):
|
| 11379 |
+
|
| 11380 |
if verbose:
|
| 11381 |
print('=' * 70)
|
| 11382 |
print('Searching for files...')
|
| 11383 |
print('This may take a while on a large dataset in particular...')
|
| 11384 |
print('=' * 70)
|
| 11385 |
|
|
|
|
|
|
|
| 11386 |
files_exts = tuple(files_exts)
|
| 11387 |
|
| 11388 |
+
filez_set = defaultdict(None)
|
| 11389 |
+
dupes_list = []
|
| 11390 |
+
|
| 11391 |
+
for dataset_addr in datasets_paths:
|
| 11392 |
+
|
| 11393 |
+
print('=' * 70)
|
| 11394 |
+
print('Processing', dataset_addr)
|
| 11395 |
+
print('=' * 70)
|
| 11396 |
+
|
| 11397 |
+
for dirpath, dirnames, filenames in tqdm.tqdm(os.walk(dataset_addr), disable=not verbose):
|
| 11398 |
+
|
| 11399 |
+
if randomize_dir_files:
|
| 11400 |
+
random.shuffle(filenames)
|
| 11401 |
+
|
| 11402 |
+
if max_num_files_per_dir > 0:
|
| 11403 |
+
max_num_files = max_num_files_per_dir
|
| 11404 |
+
|
| 11405 |
+
else:
|
| 11406 |
+
max_num_files = len(filenames)
|
| 11407 |
+
|
| 11408 |
+
for file in filenames[:max_num_files]:
|
| 11409 |
+
if file.endswith(files_exts):
|
| 11410 |
+
if check_for_dupes:
|
| 11411 |
+
|
| 11412 |
+
if use_md5_hashes:
|
| 11413 |
+
md5_hash = hashlib.md5(open(os.path.join(dirpath, file), 'rb').read()).hexdigest()
|
| 11414 |
+
|
| 11415 |
+
if md5_hash not in filez_set:
|
| 11416 |
+
filez_set[md5_hash] = os.path.join(dirpath, file)
|
| 11417 |
+
|
| 11418 |
+
else:
|
| 11419 |
+
dupes_list.append(os.path.join(dirpath, file))
|
| 11420 |
+
|
| 11421 |
+
else:
|
| 11422 |
+
if file not in filez_set:
|
| 11423 |
+
filez_set[file] = os.path.join(dirpath, file)
|
| 11424 |
+
|
| 11425 |
+
else:
|
| 11426 |
+
dupes_list.append(os.path.join(dirpath, file))
|
| 11427 |
+
else:
|
| 11428 |
+
fpath = os.path.join(dirpath, file)
|
| 11429 |
+
filez_set[fpath] = fpath
|
| 11430 |
+
|
| 11431 |
+
filez = list(filez_set.values())
|
| 11432 |
|
| 11433 |
if verbose:
|
| 11434 |
print('Done!')
|
|
|
|
| 11448 |
|
| 11449 |
if verbose:
|
| 11450 |
print('Found', len(filez), 'files.')
|
| 11451 |
+
print('Skipped', len(dupes_list), 'duplicate files.')
|
| 11452 |
print('=' * 70)
|
| 11453 |
|
| 11454 |
else:
|
|
|
|
| 11456 |
print('Could not find any files...')
|
| 11457 |
print('Please check dataset dirs and files extensions...')
|
| 11458 |
print('=' * 70)
|
| 11459 |
+
|
| 11460 |
+
if max_total_files > 0:
|
| 11461 |
+
if return_dupes:
|
| 11462 |
+
return filez[:max_total_files], dupes_list
|
| 11463 |
|
| 11464 |
+
else:
|
| 11465 |
+
return filez[:max_total_files]
|
| 11466 |
+
|
| 11467 |
+
else:
|
| 11468 |
+
if return_dupes:
|
| 11469 |
+
return filez, dupes_list
|
| 11470 |
+
|
| 11471 |
+
else:
|
| 11472 |
+
return filez
|
| 11473 |
|
| 11474 |
###################################################################################
|
| 11475 |
|
|
|
|
| 12290 |
sort_by_counts=False,
|
| 12291 |
use_full_chords=False
|
| 12292 |
):
|
| 12293 |
+
|
| 12294 |
+
if use_full_chords:
|
| 12295 |
+
CHORDS = ALL_CHORDS_FULL
|
| 12296 |
+
|
| 12297 |
+
else:
|
| 12298 |
+
CHORDS = ALL_CHORDS_SORTED
|
| 12299 |
+
|
| 12300 |
+
max_patch = max(0, min(128, max_patch))
|
| 12301 |
|
| 12302 |
+
escore_notes = [e for e in escore_notes if e[6] <= max_patch]
|
| 12303 |
|
| 12304 |
if escore_notes:
|
| 12305 |
|
|
|
|
| 12308 |
sig = []
|
| 12309 |
dsig = []
|
| 12310 |
|
| 12311 |
+
drums_offset = len(CHORDS) + 128
|
| 12312 |
|
| 12313 |
bad_chords_counter = 0
|
| 12314 |
|
|
|
|
| 12325 |
tones_chord = sorted(set([p % 12 for p in pitches]))
|
| 12326 |
|
| 12327 |
try:
|
| 12328 |
+
sig_token = CHORDS.index(tones_chord) + 128
|
| 12329 |
except:
|
| 12330 |
checked_tones_chord = check_and_fix_tones_chord(tones_chord, use_full_chords=use_full_chords)
|
| 12331 |
+
sig_token = CHORDS.index(checked_tones_chord) + 128
|
| 12332 |
bad_chords_counter += 1
|
| 12333 |
|
| 12334 |
elif len(pitches) == 1:
|
|
|
|
| 12361 |
else:
|
| 12362 |
return []
|
| 12363 |
|
| 12364 |
+
###################################################################################
|
| 12365 |
+
|
| 12366 |
+
def compute_sustain_intervals(events):
|
| 12367 |
+
|
| 12368 |
+
intervals = []
|
| 12369 |
+
pedal_on = False
|
| 12370 |
+
current_start = None
|
| 12371 |
+
|
| 12372 |
+
for t, cc in events:
|
| 12373 |
+
if not pedal_on and cc >= 64:
|
| 12374 |
+
|
| 12375 |
+
pedal_on = True
|
| 12376 |
+
current_start = t
|
| 12377 |
+
elif pedal_on and cc < 64:
|
| 12378 |
+
|
| 12379 |
+
pedal_on = False
|
| 12380 |
+
intervals.append((current_start, t))
|
| 12381 |
+
current_start = None
|
| 12382 |
+
|
| 12383 |
+
if pedal_on:
|
| 12384 |
+
intervals.append((current_start, float('inf')))
|
| 12385 |
+
|
| 12386 |
+
merged = []
|
| 12387 |
+
|
| 12388 |
+
for interval in intervals:
|
| 12389 |
+
if merged and interval[0] <= merged[-1][1]:
|
| 12390 |
+
merged[-1] = (merged[-1][0], max(merged[-1][1], interval[1]))
|
| 12391 |
+
else:
|
| 12392 |
+
merged.append(interval)
|
| 12393 |
+
return merged
|
| 12394 |
+
|
| 12395 |
+
###################################################################################
|
| 12396 |
+
|
| 12397 |
+
def apply_sustain_to_ms_score(score):
|
| 12398 |
+
|
| 12399 |
+
sustain_by_channel = {}
|
| 12400 |
+
|
| 12401 |
+
for track in score[1:]:
|
| 12402 |
+
for event in track:
|
| 12403 |
+
if event[0] == 'control_change' and event[3] == 64:
|
| 12404 |
+
channel = event[2]
|
| 12405 |
+
sustain_by_channel.setdefault(channel, []).append((event[1], event[4]))
|
| 12406 |
+
|
| 12407 |
+
sustain_intervals_by_channel = {}
|
| 12408 |
+
|
| 12409 |
+
for channel, events in sustain_by_channel.items():
|
| 12410 |
+
events.sort(key=lambda x: x[0])
|
| 12411 |
+
sustain_intervals_by_channel[channel] = compute_sustain_intervals(events)
|
| 12412 |
+
|
| 12413 |
+
global_max_off = 0
|
| 12414 |
+
|
| 12415 |
+
for track in score[1:]:
|
| 12416 |
+
for event in track:
|
| 12417 |
+
if event[0] == 'note':
|
| 12418 |
+
global_max_off = max(global_max_off, event[1] + event[2])
|
| 12419 |
+
|
| 12420 |
+
for channel, intervals in sustain_intervals_by_channel.items():
|
| 12421 |
+
updated_intervals = []
|
| 12422 |
+
for start, end in intervals:
|
| 12423 |
+
if end == float('inf'):
|
| 12424 |
+
end = global_max_off
|
| 12425 |
+
updated_intervals.append((start, end))
|
| 12426 |
+
sustain_intervals_by_channel[channel] = updated_intervals
|
| 12427 |
+
|
| 12428 |
+
if sustain_intervals_by_channel:
|
| 12429 |
+
|
| 12430 |
+
for track in score[1:]:
|
| 12431 |
+
for event in track:
|
| 12432 |
+
if event[0] == 'note':
|
| 12433 |
+
start = event[1]
|
| 12434 |
+
nominal_dur = event[2]
|
| 12435 |
+
nominal_off = start + nominal_dur
|
| 12436 |
+
channel = event[3]
|
| 12437 |
+
|
| 12438 |
+
intervals = sustain_intervals_by_channel.get(channel, [])
|
| 12439 |
+
effective_off = nominal_off
|
| 12440 |
+
|
| 12441 |
+
for intv_start, intv_end in intervals:
|
| 12442 |
+
if intv_start < nominal_off < intv_end:
|
| 12443 |
+
effective_off = intv_end
|
| 12444 |
+
break
|
| 12445 |
+
|
| 12446 |
+
effective_dur = effective_off - start
|
| 12447 |
+
|
| 12448 |
+
event[2] = effective_dur
|
| 12449 |
+
|
| 12450 |
+
return score
|
| 12451 |
+
|
| 12452 |
+
###################################################################################
|
| 12453 |
+
|
| 12454 |
+
def copy_file(src_file: str, trg_dir: str, add_subdir: bool = False, verbose: bool = False):
|
| 12455 |
+
|
| 12456 |
+
src_path = Path(src_file)
|
| 12457 |
+
target_directory = Path(trg_dir)
|
| 12458 |
+
|
| 12459 |
+
if not src_path.is_file():
|
| 12460 |
+
if verbose:
|
| 12461 |
+
print("Source file does not exist or is not a file.")
|
| 12462 |
+
|
| 12463 |
+
return None
|
| 12464 |
+
|
| 12465 |
+
target_directory.mkdir(parents=True, exist_ok=True)
|
| 12466 |
+
|
| 12467 |
+
if add_subdir:
|
| 12468 |
+
first_letter = src_path.name[0]
|
| 12469 |
+
target_directory = target_directory / first_letter
|
| 12470 |
+
target_directory.mkdir(parents=True, exist_ok=True)
|
| 12471 |
+
|
| 12472 |
+
destination = target_directory / src_path.name
|
| 12473 |
+
|
| 12474 |
+
try:
|
| 12475 |
+
shutil.copy2(src_path, destination)
|
| 12476 |
+
|
| 12477 |
+
except:
|
| 12478 |
+
if verbose:
|
| 12479 |
+
print('File could not be copied!')
|
| 12480 |
+
|
| 12481 |
+
return None
|
| 12482 |
+
|
| 12483 |
+
if verbose:
|
| 12484 |
+
print('File copied!')
|
| 12485 |
+
|
| 12486 |
+
return None
|
| 12487 |
+
|
| 12488 |
+
###################################################################################
|
| 12489 |
+
|
| 12490 |
+
def escore_notes_even_timings(escore_notes, in_place=True):
|
| 12491 |
+
|
| 12492 |
+
if in_place:
|
| 12493 |
+
for e in escore_notes:
|
| 12494 |
+
if e[1] % 2 != 0:
|
| 12495 |
+
e[1] += 1
|
| 12496 |
+
|
| 12497 |
+
if e[2] % 2 != 0:
|
| 12498 |
+
e[2] += 1
|
| 12499 |
+
|
| 12500 |
+
return []
|
| 12501 |
+
|
| 12502 |
+
else:
|
| 12503 |
+
escore = copy.deepcopy(escore_notes)
|
| 12504 |
+
|
| 12505 |
+
for e in escore:
|
| 12506 |
+
if e[1] % 2 != 0:
|
| 12507 |
+
e[1] += 1
|
| 12508 |
+
|
| 12509 |
+
if e[2] % 2 != 0:
|
| 12510 |
+
e[2] += 1
|
| 12511 |
+
|
| 12512 |
+
return escore
|
| 12513 |
+
|
| 12514 |
+
###################################################################################
|
| 12515 |
+
|
| 12516 |
+
def both_chords(chord1, chord2, merge_threshold=2):
|
| 12517 |
+
|
| 12518 |
+
if len(chord1) > 1 and len(chord2) > 0 and chord2[0][1]-chord1[0][1] <= merge_threshold:
|
| 12519 |
+
return True
|
| 12520 |
+
|
| 12521 |
+
elif len(chord1) > 0 and len(chord2) > 1 and chord2[0][1]-chord1[0][1] <= merge_threshold:
|
| 12522 |
+
return True
|
| 12523 |
+
|
| 12524 |
+
else:
|
| 12525 |
+
return False
|
| 12526 |
+
|
| 12527 |
+
def merge_chords(chord1, chord2, sort_drums_last=False):
|
| 12528 |
+
|
| 12529 |
+
mchord = chord1
|
| 12530 |
+
|
| 12531 |
+
seen = []
|
| 12532 |
+
|
| 12533 |
+
for e in chord2:
|
| 12534 |
+
if tuple([e[4], e[6]]) not in seen:
|
| 12535 |
+
mchord.append(e)
|
| 12536 |
+
seen.append(tuple([e[4], e[6]]))
|
| 12537 |
+
|
| 12538 |
+
for e in mchord[1:]:
|
| 12539 |
+
e[1] = mchord[0][1]
|
| 12540 |
+
|
| 12541 |
+
if sort_drums_last:
|
| 12542 |
+
mchord.sort(key=lambda x: (-x[4], x[6]) if x[6] != 128 else (x[6], -x[4]))
|
| 12543 |
+
|
| 12544 |
+
else:
|
| 12545 |
+
mchord.sort(key=lambda x: (-x[4], x[6]))
|
| 12546 |
+
|
| 12547 |
+
return mchord
|
| 12548 |
+
|
| 12549 |
+
def merge_escore_notes(escore_notes, merge_threshold=2, sort_drums_last=False):
|
| 12550 |
+
|
| 12551 |
+
cscore = chordify_score([1000, escore_notes])
|
| 12552 |
+
|
| 12553 |
+
merged_chords = []
|
| 12554 |
+
merged_chord = cscore[0]
|
| 12555 |
+
|
| 12556 |
+
for i in range(1, len(cscore)):
|
| 12557 |
+
|
| 12558 |
+
cchord = cscore[i]
|
| 12559 |
+
|
| 12560 |
+
if both_chords(merged_chord, cchord, merge_threshold=merge_threshold):
|
| 12561 |
+
merged_chord = merge_chords(merged_chord, cchord, sort_drums_last=sort_drums_last)
|
| 12562 |
+
|
| 12563 |
+
else:
|
| 12564 |
+
merged_chords.append(merged_chord)
|
| 12565 |
+
merged_chord = cchord
|
| 12566 |
+
|
| 12567 |
+
return flatten(merged_chords)
|
| 12568 |
+
|
| 12569 |
+
###################################################################################
|
| 12570 |
+
|
| 12571 |
+
def solo_piano_escore_notes_tokenized(escore_notes,
|
| 12572 |
+
compress_start_times=True,
|
| 12573 |
+
encode_velocities=False,
|
| 12574 |
+
verbose=False
|
| 12575 |
+
):
|
| 12576 |
+
|
| 12577 |
+
if verbose:
|
| 12578 |
+
print('=' * 70)
|
| 12579 |
+
print('Encoding MIDI...')
|
| 12580 |
+
|
| 12581 |
+
sp_escore_notes = solo_piano_escore_notes(escore_notes)
|
| 12582 |
+
zscore = recalculate_score_timings(sp_escore_notes)
|
| 12583 |
+
dscore = delta_score_notes(zscore, timings_clip_value=127)
|
| 12584 |
+
|
| 12585 |
+
score = []
|
| 12586 |
+
|
| 12587 |
+
notes_counter = 0
|
| 12588 |
+
chords_counter = 1
|
| 12589 |
+
|
| 12590 |
+
for i, e in enumerate(dscore):
|
| 12591 |
+
|
| 12592 |
+
dtime = e[1]
|
| 12593 |
+
dur = e[2]
|
| 12594 |
+
ptc = e[4]
|
| 12595 |
+
vel = e[5]
|
| 12596 |
+
|
| 12597 |
+
if compress_start_times:
|
| 12598 |
+
|
| 12599 |
+
if i == 0:
|
| 12600 |
+
score.extend([0, dur+128, ptc+256])
|
| 12601 |
+
|
| 12602 |
+
if encode_velocities:
|
| 12603 |
+
score.append(vel+384)
|
| 12604 |
+
|
| 12605 |
+
else:
|
| 12606 |
+
if dtime == 0:
|
| 12607 |
+
score.extend([dur+128, ptc+256])
|
| 12608 |
+
|
| 12609 |
+
else:
|
| 12610 |
+
score.extend([dtime, dur+128, ptc+256])
|
| 12611 |
+
|
| 12612 |
+
if encode_velocities:
|
| 12613 |
+
score.append(vel+384)
|
| 12614 |
+
|
| 12615 |
+
if dtime != 0:
|
| 12616 |
+
chords_counter += 1
|
| 12617 |
+
|
| 12618 |
+
else:
|
| 12619 |
+
score.extend([dtime, dur+128, ptc+256])
|
| 12620 |
+
|
| 12621 |
+
if encode_velocities:
|
| 12622 |
+
score.append(vel+384)
|
| 12623 |
+
|
| 12624 |
+
if dtime != 0:
|
| 12625 |
+
chords_counter += 1
|
| 12626 |
+
|
| 12627 |
+
notes_counter += 1
|
| 12628 |
+
|
| 12629 |
+
if verbose:
|
| 12630 |
+
print('Done!')
|
| 12631 |
+
print('=' * 70)
|
| 12632 |
+
|
| 12633 |
+
print('Source MIDI composition has', len(zscore), 'notes')
|
| 12634 |
+
print('Source MIDI composition has', len([d[1] for d in dscore if d[1] !=0 ])+1, 'chords')
|
| 12635 |
+
print('-' * 70)
|
| 12636 |
+
print('Encoded sequence has', notes_counter, 'pitches')
|
| 12637 |
+
print('Encoded sequence has', chords_counter, 'chords')
|
| 12638 |
+
print('-' * 70)
|
| 12639 |
+
print('Final encoded sequence has', len(score), 'tokens')
|
| 12640 |
+
print('=' * 70)
|
| 12641 |
+
|
| 12642 |
+
return score
|
| 12643 |
+
|
| 12644 |
+
###################################################################################
|
| 12645 |
+
|
| 12646 |
+
def equalize_closest_elements_dynamic(seq,
|
| 12647 |
+
min_val=128,
|
| 12648 |
+
max_val=256,
|
| 12649 |
+
splitting_factor=1.5,
|
| 12650 |
+
tightness_threshold=0.15
|
| 12651 |
+
):
|
| 12652 |
+
|
| 12653 |
+
candidates = [(i, x) for i, x in enumerate(seq) if min_val <= x <= max_val]
|
| 12654 |
+
|
| 12655 |
+
if len(candidates) < 2:
|
| 12656 |
+
return seq.copy()
|
| 12657 |
+
|
| 12658 |
+
sorted_candidates = sorted(candidates, key=lambda pair: pair[1])
|
| 12659 |
+
candidate_values = [val for _, val in sorted_candidates]
|
| 12660 |
+
|
| 12661 |
+
differences = [candidate_values[i+1] - candidate_values[i] for i in range(len(candidate_values)-1)]
|
| 12662 |
+
|
| 12663 |
+
def median(lst):
|
| 12664 |
+
|
| 12665 |
+
n = len(lst)
|
| 12666 |
+
sorted_lst = sorted(lst)
|
| 12667 |
+
mid = n // 2
|
| 12668 |
+
|
| 12669 |
+
if n % 2 == 0:
|
| 12670 |
+
return (sorted_lst[mid - 1] + sorted_lst[mid]) / 2.0
|
| 12671 |
+
|
| 12672 |
+
else:
|
| 12673 |
+
return sorted_lst[mid]
|
| 12674 |
+
|
| 12675 |
+
med_diff = median(differences)
|
| 12676 |
+
|
| 12677 |
+
split_indices = [i for i, diff in enumerate(differences) if diff > splitting_factor * med_diff]
|
| 12678 |
+
|
| 12679 |
+
clusters = []
|
| 12680 |
+
|
| 12681 |
+
if split_indices:
|
| 12682 |
+
start = 0
|
| 12683 |
+
for split_index in split_indices:
|
| 12684 |
+
clusters.append(sorted_candidates[start:split_index+1])
|
| 12685 |
+
start = split_index + 1
|
| 12686 |
+
clusters.append(sorted_candidates[start:])
|
| 12687 |
+
|
| 12688 |
+
else:
|
| 12689 |
+
clusters = [sorted_candidates]
|
| 12690 |
+
|
| 12691 |
+
|
| 12692 |
+
valid_clusters = [cluster for cluster in clusters if len(cluster) >= 2]
|
| 12693 |
+
if not valid_clusters:
|
| 12694 |
+
return seq.copy()
|
| 12695 |
+
|
| 12696 |
+
def cluster_spread(cluster):
|
| 12697 |
+
values = [val for (_, val) in cluster]
|
| 12698 |
+
return max(values) - min(values)
|
| 12699 |
+
|
| 12700 |
+
valid_clusters.sort(key=lambda cluster: (len(cluster), -cluster_spread(cluster)), reverse=True)
|
| 12701 |
+
selected_cluster = valid_clusters[0]
|
| 12702 |
+
|
| 12703 |
+
allowed_range_width = max_val - min_val
|
| 12704 |
+
spread = cluster_spread(selected_cluster)
|
| 12705 |
+
ratio = spread / allowed_range_width
|
| 12706 |
+
|
| 12707 |
+
if ratio > tightness_threshold:
|
| 12708 |
+
return seq.copy()
|
| 12709 |
+
|
| 12710 |
+
cluster_values = [val for (_, val) in selected_cluster]
|
| 12711 |
+
equal_value = sum(cluster_values) // len(cluster_values)
|
| 12712 |
+
|
| 12713 |
+
|
| 12714 |
+
result = list(seq)
|
| 12715 |
+
for idx, _ in selected_cluster:
|
| 12716 |
+
result[idx] = equal_value
|
| 12717 |
+
|
| 12718 |
+
return result
|
| 12719 |
+
|
| 12720 |
+
###################################################################################
|
| 12721 |
+
|
| 12722 |
+
def chunk_list(lst, chunk_size):
|
| 12723 |
+
return [lst[i:i + chunk_size] for i in range(0, len(lst), chunk_size)]
|
| 12724 |
+
|
| 12725 |
+
###################################################################################
|
| 12726 |
+
|
| 12727 |
+
def compress_tokens_sequence(seq,
|
| 12728 |
+
min_val=128,
|
| 12729 |
+
max_val=256,
|
| 12730 |
+
group_size=2,
|
| 12731 |
+
splitting_factor=1.5,
|
| 12732 |
+
tightness_threshold=0.15
|
| 12733 |
+
):
|
| 12734 |
+
|
| 12735 |
+
comp_seq = equalize_closest_elements_dynamic(seq,
|
| 12736 |
+
min_val,
|
| 12737 |
+
max_val,
|
| 12738 |
+
splitting_factor=splitting_factor,
|
| 12739 |
+
tightness_threshold=tightness_threshold
|
| 12740 |
+
)
|
| 12741 |
+
|
| 12742 |
+
seq_split = sorted(chunk_list(comp_seq, group_size), key=lambda x: (-x[0], -x[1]))
|
| 12743 |
+
|
| 12744 |
+
seq_grouped = [[[k]] + [vv[1:] for vv in v] for k, v in groupby(seq_split, key=lambda x: x[0])]
|
| 12745 |
+
|
| 12746 |
+
return flatten(flatten(sorted(seq_grouped, key=lambda x: -x[1][0])))
|
| 12747 |
+
|
| 12748 |
+
###################################################################################
|
| 12749 |
+
|
| 12750 |
+
def merge_adjacent_pairs(values_counts):
|
| 12751 |
+
|
| 12752 |
+
merged = []
|
| 12753 |
+
i = 0
|
| 12754 |
+
|
| 12755 |
+
while i < len(values_counts):
|
| 12756 |
+
|
| 12757 |
+
if i < len(values_counts) - 1:
|
| 12758 |
+
value1, count1 = values_counts[i]
|
| 12759 |
+
value2, count2 = values_counts[i + 1]
|
| 12760 |
+
|
| 12761 |
+
if value2 - value1 == 1:
|
| 12762 |
+
if count2 > count1:
|
| 12763 |
+
merged_value = value2
|
| 12764 |
+
|
| 12765 |
+
else:
|
| 12766 |
+
merged_value = value1
|
| 12767 |
+
|
| 12768 |
+
merged_count = count1 + count2
|
| 12769 |
+
merged.append((merged_value, merged_count))
|
| 12770 |
+
|
| 12771 |
+
i += 2
|
| 12772 |
+
|
| 12773 |
+
continue
|
| 12774 |
+
|
| 12775 |
+
merged.append(values_counts[i])
|
| 12776 |
+
|
| 12777 |
+
i += 1
|
| 12778 |
+
|
| 12779 |
+
return merged
|
| 12780 |
+
|
| 12781 |
+
###################################################################################
|
| 12782 |
+
|
| 12783 |
+
def merge_escore_notes_start_times(escore_notes, num_merges=1):
|
| 12784 |
+
|
| 12785 |
+
new_dscore = delta_score_notes(escore_notes)
|
| 12786 |
+
|
| 12787 |
+
times = [e[1] for e in new_dscore if e[1] != 0]
|
| 12788 |
+
times_counts = sorted(Counter(times).most_common())
|
| 12789 |
+
|
| 12790 |
+
prev_counts = []
|
| 12791 |
+
new_times_counts = times_counts
|
| 12792 |
+
|
| 12793 |
+
mcount = 0
|
| 12794 |
+
|
| 12795 |
+
while prev_counts != new_times_counts:
|
| 12796 |
+
prev_counts = new_times_counts
|
| 12797 |
+
new_times_counts = merge_adjacent_pairs(new_times_counts)
|
| 12798 |
+
|
| 12799 |
+
mcount += 1
|
| 12800 |
+
|
| 12801 |
+
if mcount == num_merges:
|
| 12802 |
+
break
|
| 12803 |
+
|
| 12804 |
+
gtimes = [r[0] for r in new_times_counts]
|
| 12805 |
+
|
| 12806 |
+
for e in new_dscore:
|
| 12807 |
+
if e[1] > 0:
|
| 12808 |
+
e[1] = find_closest_value(gtimes, e[1])[0]
|
| 12809 |
+
e[2] -= num_merges
|
| 12810 |
+
|
| 12811 |
+
return delta_score_to_abs_score(new_dscore)
|
| 12812 |
+
|
| 12813 |
+
###################################################################################
|
| 12814 |
+
|
| 12815 |
+
def multi_instrumental_escore_notes_tokenized(escore_notes, compress_seq=False):
|
| 12816 |
+
|
| 12817 |
+
melody_chords = []
|
| 12818 |
+
|
| 12819 |
+
pe = escore_notes[0]
|
| 12820 |
+
|
| 12821 |
+
for i, e in enumerate(escore_notes):
|
| 12822 |
+
|
| 12823 |
+
dtime = max(0, min(255, e[1]-pe[1]))
|
| 12824 |
+
|
| 12825 |
+
dur = max(0, min(255, e[2]))
|
| 12826 |
+
|
| 12827 |
+
cha = max(0, min(15, e[3]))
|
| 12828 |
+
|
| 12829 |
+
if cha == 9:
|
| 12830 |
+
pat = 128
|
| 12831 |
+
|
| 12832 |
+
else:
|
| 12833 |
+
pat = max(0, min(127, e[6]))
|
| 12834 |
+
|
| 12835 |
+
ptc = max(0, min(127, e[4]))
|
| 12836 |
+
|
| 12837 |
+
vel = max(8, min(127, e[5]))
|
| 12838 |
+
velocity = round(vel / 15)-1
|
| 12839 |
+
|
| 12840 |
+
dur_vel = (8 * dur) + velocity
|
| 12841 |
+
pat_ptc = (129 * pat) + ptc
|
| 12842 |
+
|
| 12843 |
+
if compress_seq:
|
| 12844 |
+
if dtime != 0 or i == 0:
|
| 12845 |
+
melody_chords.extend([dtime, dur_vel+256, pat_ptc+2304])
|
| 12846 |
+
|
| 12847 |
+
else:
|
| 12848 |
+
melody_chords.extend([dur_vel+256, pat_ptc+2304])
|
| 12849 |
+
|
| 12850 |
+
else:
|
| 12851 |
+
melody_chords.extend([dtime, dur_vel+256, pat_ptc+2304])
|
| 12852 |
+
|
| 12853 |
+
pe = e
|
| 12854 |
+
|
| 12855 |
+
return melody_chords
|
| 12856 |
+
|
| 12857 |
+
###################################################################################
|
| 12858 |
+
|
| 12859 |
+
def merge_counts(data, return_lists=True):
|
| 12860 |
+
|
| 12861 |
+
merged = defaultdict(int)
|
| 12862 |
+
|
| 12863 |
+
for value, count in data:
|
| 12864 |
+
merged[value] += count
|
| 12865 |
+
|
| 12866 |
+
if return_lists:
|
| 12867 |
+
return [[k, v] for k, v in merged.items()]
|
| 12868 |
+
|
| 12869 |
+
else:
|
| 12870 |
+
return list(merged.items())
|
| 12871 |
+
|
| 12872 |
+
###################################################################################
|
| 12873 |
+
|
| 12874 |
+
def convert_escore_notes_pitches_chords_signature(signature, convert_to_full_chords=True):
|
| 12875 |
+
|
| 12876 |
+
if convert_to_full_chords:
|
| 12877 |
+
SRC_CHORDS = ALL_CHORDS_SORTED
|
| 12878 |
+
TRG_CHORDS = ALL_CHORDS_FULL
|
| 12879 |
+
|
| 12880 |
+
else:
|
| 12881 |
+
SRC_CHORDS = ALL_CHORDS_FULL
|
| 12882 |
+
TRG_CHORDS = ALL_CHORDS_SORTED
|
| 12883 |
+
|
| 12884 |
+
cdiff = len(TRG_CHORDS) - len(SRC_CHORDS)
|
| 12885 |
+
|
| 12886 |
+
pitches_counts = [c for c in signature if -1 < c[0] < 128]
|
| 12887 |
+
chords_counts = [c for c in signature if 127 < c[0] < len(SRC_CHORDS)+128]
|
| 12888 |
+
drums_counts = [[c[0]+cdiff, c[1]] for c in signature if len(SRC_CHORDS)+127 < c[0] < len(SRC_CHORDS)+256]
|
| 12889 |
+
bad_chords_count = [c for c in signature if c[0] == -1]
|
| 12890 |
+
|
| 12891 |
+
new_chords_counts = []
|
| 12892 |
+
|
| 12893 |
+
for c in chords_counts:
|
| 12894 |
+
tones_chord = SRC_CHORDS[c[0]-128]
|
| 12895 |
+
|
| 12896 |
+
if tones_chord not in TRG_CHORDS:
|
| 12897 |
+
tones_chord = check_and_fix_tones_chord(tones_chord, use_full_chords=convert_to_full_chords)
|
| 12898 |
+
bad_chords_count[0][1] += 1
|
| 12899 |
+
|
| 12900 |
+
new_chords_counts.append([TRG_CHORDS.index(tones_chord)+128, c[1]])
|
| 12901 |
+
|
| 12902 |
+
return pitches_counts + merge_counts(new_chords_counts) + drums_counts + bad_chords_count
|
| 12903 |
+
|
| 12904 |
+
###################################################################################
|
| 12905 |
+
|
| 12906 |
+
def convert_bytes_in_nested_list(lst, encoding='utf-8', errors='ignore'):
|
| 12907 |
+
|
| 12908 |
+
new_list = []
|
| 12909 |
+
|
| 12910 |
+
for item in lst:
|
| 12911 |
+
if isinstance(item, list):
|
| 12912 |
+
new_list.append(convert_bytes_in_nested_list(item))
|
| 12913 |
+
|
| 12914 |
+
elif isinstance(item, bytes):
|
| 12915 |
+
new_list.append(item.decode(encoding, errors=errors))
|
| 12916 |
+
|
| 12917 |
+
else:
|
| 12918 |
+
new_list.append(item)
|
| 12919 |
+
|
| 12920 |
+
return new_list
|
| 12921 |
+
|
| 12922 |
+
###################################################################################
|
| 12923 |
+
|
| 12924 |
+
def mult_pitches(pitches, min_oct=4, max_oct=6):
|
| 12925 |
+
|
| 12926 |
+
tones_chord = sorted(set([p % 12 for p in pitches]))
|
| 12927 |
+
|
| 12928 |
+
mult_ptcs = []
|
| 12929 |
+
|
| 12930 |
+
for t in tones_chord:
|
| 12931 |
+
for i in range(min_oct, max_oct):
|
| 12932 |
+
mult_ptcs.append((i*12)+t)
|
| 12933 |
+
|
| 12934 |
+
return mult_ptcs
|
| 12935 |
+
|
| 12936 |
+
###################################################################################
|
| 12937 |
+
|
| 12938 |
+
def find_next(pitches, cur_ptc):
|
| 12939 |
+
|
| 12940 |
+
i = 0
|
| 12941 |
+
|
| 12942 |
+
for i, p in enumerate(pitches):
|
| 12943 |
+
if p != cur_ptc:
|
| 12944 |
+
break
|
| 12945 |
+
|
| 12946 |
+
return i
|
| 12947 |
+
|
| 12948 |
+
###################################################################################
|
| 12949 |
+
|
| 12950 |
+
def ordered_groups_unsorted(data, key_index):
|
| 12951 |
+
|
| 12952 |
+
def keyfunc(sublist):
|
| 12953 |
+
return sublist[key_index]
|
| 12954 |
+
|
| 12955 |
+
groups = []
|
| 12956 |
+
|
| 12957 |
+
for key, group in groupby(data, key=keyfunc):
|
| 12958 |
+
groups.append((key, list(group)))
|
| 12959 |
+
|
| 12960 |
+
return groups
|
| 12961 |
+
|
| 12962 |
+
###################################################################################
|
| 12963 |
+
|
| 12964 |
+
def ordered_groups(data, key_index):
|
| 12965 |
+
|
| 12966 |
+
groups = OrderedDict()
|
| 12967 |
+
|
| 12968 |
+
for sublist in data:
|
| 12969 |
+
key = sublist[key_index]
|
| 12970 |
+
|
| 12971 |
+
if key not in groups:
|
| 12972 |
+
groups[key] = []
|
| 12973 |
+
|
| 12974 |
+
groups[key].append(sublist)
|
| 12975 |
+
|
| 12976 |
+
return list(groups.items())
|
| 12977 |
+
|
| 12978 |
+
###################################################################################
|
| 12979 |
+
|
| 12980 |
+
def merge_melody_notes(escore_notes, pitches_idx=4, max_dur=255, last_dur=128):
|
| 12981 |
+
|
| 12982 |
+
groups = ordered_groups_unsorted(escore_notes, pitches_idx)
|
| 12983 |
+
|
| 12984 |
+
merged_melody_notes = []
|
| 12985 |
+
|
| 12986 |
+
for i, (k, g) in enumerate(groups[:-1]):
|
| 12987 |
+
|
| 12988 |
+
if len(g) == 1:
|
| 12989 |
+
merged_melody_notes.extend(g)
|
| 12990 |
+
|
| 12991 |
+
else:
|
| 12992 |
+
dur = min(max_dur, groups[i+1][1][0][1] - g[0][1])
|
| 12993 |
+
|
| 12994 |
+
merged_melody_notes.append(['note',
|
| 12995 |
+
g[0][1],
|
| 12996 |
+
dur,
|
| 12997 |
+
g[0][3],
|
| 12998 |
+
g[0][4],
|
| 12999 |
+
g[0][5],
|
| 13000 |
+
g[0][6]
|
| 13001 |
+
])
|
| 13002 |
+
|
| 13003 |
+
merged_melody_notes.append(['note',
|
| 13004 |
+
groups[-1][1][0][1],
|
| 13005 |
+
last_dur,
|
| 13006 |
+
groups[-1][1][0][3],
|
| 13007 |
+
groups[-1][1][0][4],
|
| 13008 |
+
groups[-1][1][0][5],
|
| 13009 |
+
groups[-1][1][0][6]
|
| 13010 |
+
])
|
| 13011 |
+
|
| 13012 |
+
return merged_melody_notes
|
| 13013 |
+
|
| 13014 |
+
###################################################################################
|
| 13015 |
+
|
| 13016 |
+
def add_expressive_melody_to_enhanced_score_notes(escore_notes,
|
| 13017 |
+
melody_start_chord=0,
|
| 13018 |
+
melody_prime_pitch=60,
|
| 13019 |
+
melody_step=1,
|
| 13020 |
+
melody_channel=3,
|
| 13021 |
+
melody_patch=40,
|
| 13022 |
+
melody_notes_max_duration=255,
|
| 13023 |
+
melody_last_note_dur=128,
|
| 13024 |
+
melody_clip_max_min_durs=[],
|
| 13025 |
+
melody_max_velocity=120,
|
| 13026 |
+
acc_max_velocity=90,
|
| 13027 |
+
return_melody=False
|
| 13028 |
+
):
|
| 13029 |
+
|
| 13030 |
+
|
| 13031 |
+
score = copy.deepcopy(escore_notes)
|
| 13032 |
+
|
| 13033 |
+
adjust_score_velocities(score, acc_max_velocity)
|
| 13034 |
+
|
| 13035 |
+
cscore = chordify_score([1000, score])
|
| 13036 |
+
|
| 13037 |
+
melody_pitches = [melody_prime_pitch]
|
| 13038 |
+
|
| 13039 |
+
for i, c in enumerate(cscore[melody_start_chord:]):
|
| 13040 |
+
|
| 13041 |
+
if i % melody_step == 0:
|
| 13042 |
+
|
| 13043 |
+
pitches = [e[4] for e in c if e[3] != 9]
|
| 13044 |
+
|
| 13045 |
+
if pitches:
|
| 13046 |
+
cptc = find_closest_value(mult_pitches(pitches), melody_pitches[-1])[0]
|
| 13047 |
+
melody_pitches.append(cptc)
|
| 13048 |
+
|
| 13049 |
+
song_f = []
|
| 13050 |
+
mel_f = []
|
| 13051 |
+
|
| 13052 |
+
idx = 1
|
| 13053 |
+
|
| 13054 |
+
for i, c in enumerate(cscore[:-melody_step]):
|
| 13055 |
+
pitches = [e[4] for e in c if e[3] != 9]
|
| 13056 |
+
|
| 13057 |
+
if pitches and i >= melody_start_chord and i % melody_step == 0:
|
| 13058 |
+
dur = min(cscore[i+melody_step][0][1] - c[0][1], melody_notes_max_duration)
|
| 13059 |
+
|
| 13060 |
+
mel_f.append(['note',
|
| 13061 |
+
c[0][1],
|
| 13062 |
+
dur,
|
| 13063 |
+
melody_channel,
|
| 13064 |
+
60+(melody_pitches[idx] % 24),
|
| 13065 |
+
100 + ((melody_pitches[idx] % 12) * 2),
|
| 13066 |
+
melody_patch
|
| 13067 |
+
])
|
| 13068 |
+
idx += 1
|
| 13069 |
+
|
| 13070 |
+
song_f.extend(c)
|
| 13071 |
+
|
| 13072 |
+
song_f.extend(flatten(cscore[-melody_step:]))
|
| 13073 |
+
|
| 13074 |
+
if len(melody_clip_max_min_durs) == 2:
|
| 13075 |
+
for e in mel_f:
|
| 13076 |
+
if e[2] >= melody_clip_max_min_durs[0]:
|
| 13077 |
+
e[2] = melody_clip_max_min_durs[1]
|
| 13078 |
+
|
| 13079 |
+
adjust_score_velocities(mel_f, melody_max_velocity)
|
| 13080 |
+
|
| 13081 |
+
merged_melody_notes = merge_melody_notes(mel_f,
|
| 13082 |
+
max_dur=melody_notes_max_duration,
|
| 13083 |
+
last_dur=melody_last_note_dur
|
| 13084 |
+
)
|
| 13085 |
+
|
| 13086 |
+
song_f = sorted(merged_melody_notes + song_f,
|
| 13087 |
+
key=lambda x: x[1]
|
| 13088 |
+
)
|
| 13089 |
+
|
| 13090 |
+
if return_melody:
|
| 13091 |
+
return mel_f
|
| 13092 |
+
|
| 13093 |
+
else:
|
| 13094 |
+
return song_f
|
| 13095 |
+
|
| 13096 |
+
###################################################################################
|
| 13097 |
+
|
| 13098 |
+
def list_md5_hash(ints_list):
|
| 13099 |
+
|
| 13100 |
+
arr = array('H', ints_list)
|
| 13101 |
+
binary_data = arr.tobytes()
|
| 13102 |
+
|
| 13103 |
+
return hashlib.md5(binary_data).hexdigest()
|
| 13104 |
+
|
| 13105 |
+
###################################################################################
|
| 13106 |
+
|
| 13107 |
+
def fix_escore_notes_durations(escore_notes,
|
| 13108 |
+
min_notes_gap=1,
|
| 13109 |
+
min_notes_dur=1,
|
| 13110 |
+
times_idx=1,
|
| 13111 |
+
durs_idx=2,
|
| 13112 |
+
channels_idx = 3,
|
| 13113 |
+
pitches_idx=4
|
| 13114 |
+
):
|
| 13115 |
+
|
| 13116 |
+
notes = [e for e in escore_notes if e[channels_idx] != 9]
|
| 13117 |
+
drums = [e for e in escore_notes if e[channels_idx] == 9]
|
| 13118 |
+
|
| 13119 |
+
escore_groups = ordered_groups(notes, pitches_idx)
|
| 13120 |
+
|
| 13121 |
+
merged_score = []
|
| 13122 |
+
|
| 13123 |
+
for k, g in escore_groups:
|
| 13124 |
+
if len(g) > 2:
|
| 13125 |
+
fg = fix_monophonic_score_durations(g,
|
| 13126 |
+
min_notes_gap=min_notes_gap,
|
| 13127 |
+
min_notes_dur=min_notes_dur
|
| 13128 |
+
)
|
| 13129 |
+
merged_score.extend(fg)
|
| 13130 |
+
|
| 13131 |
+
elif len(g) == 2:
|
| 13132 |
+
|
| 13133 |
+
if g[0][times_idx]+g[0][durs_idx] >= g[1][times_idx]:
|
| 13134 |
+
g[0][durs_idx] = max(1, g[1][times_idx] - g[0][times_idx] - 1)
|
| 13135 |
+
|
| 13136 |
+
merged_score.extend(g)
|
| 13137 |
+
|
| 13138 |
+
else:
|
| 13139 |
+
merged_score.extend(g)
|
| 13140 |
+
|
| 13141 |
+
return sorted(merged_score + drums, key=lambda x: x[times_idx])
|
| 13142 |
+
|
| 13143 |
+
###################################################################################
|
| 13144 |
+
|
| 13145 |
+
print('Module loaded!')
|
| 13146 |
+
print('=' * 70)
|
| 13147 |
+
print('Enjoy! :)')
|
| 13148 |
+
print('=' * 70)
|
| 13149 |
+
|
| 13150 |
###################################################################################
|
| 13151 |
# This is the end of the TMIDI X Python module
|
| 13152 |
###################################################################################
|