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