Upload TMIDIX.py
Browse files
TMIDIX.py
CHANGED
|
@@ -14,14 +14,14 @@ r'''############################################################################
|
|
| 14 |
#
|
| 15 |
# Project Los Angeles
|
| 16 |
#
|
| 17 |
-
# Tegridy Code
|
| 18 |
#
|
| 19 |
# https://github.com/Tegridy-Code/Project-Los-Angeles
|
| 20 |
#
|
| 21 |
#
|
| 22 |
###################################################################################
|
| 23 |
###################################################################################
|
| 24 |
-
# Copyright
|
| 25 |
#
|
| 26 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 27 |
# you may not use this file except in compliance with the License.
|
|
@@ -9552,15 +9552,20 @@ MOOD_SCALES = ['Major', 'Minor', 'Major Minor']
|
|
| 9552 |
###################################################################################
|
| 9553 |
|
| 9554 |
def alpha_str(string):
|
| 9555 |
-
|
|
|
|
| 9556 |
|
| 9557 |
###################################################################################
|
| 9558 |
|
| 9559 |
-
def escore_notes_to_text_description(escore_notes,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9560 |
|
| 9561 |
#==============================================================================
|
| 9562 |
|
| 9563 |
-
song_time_min = (escore_notes[-1][1] *
|
| 9564 |
|
| 9565 |
if song_time_min < 1.5:
|
| 9566 |
song_length = 'short'
|
|
@@ -9592,10 +9597,16 @@ def escore_notes_to_text_description(escore_notes, song_name='', artist_name='')
|
|
| 9592 |
|
| 9593 |
#==============================================================================
|
| 9594 |
|
| 9595 |
-
|
|
|
|
|
|
|
| 9596 |
|
| 9597 |
instruments = [alpha_str(Number2patch[p]) for p in patches if p < 128]
|
| 9598 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9599 |
if 128 in patches:
|
| 9600 |
drums_present = True
|
| 9601 |
|
|
@@ -9641,22 +9652,22 @@ def escore_notes_to_text_description(escore_notes, song_name='', artist_name='')
|
|
| 9641 |
|
| 9642 |
escore_averages = escore_notes_averages(escore_notes, return_ptcs_and_vels=True)
|
| 9643 |
|
| 9644 |
-
if escore_averages[0] <
|
| 9645 |
rythm = 'fast'
|
| 9646 |
|
| 9647 |
-
elif
|
| 9648 |
rythm = 'average'
|
| 9649 |
|
| 9650 |
-
elif escore_averages[0] >
|
| 9651 |
rythm = 'slow'
|
| 9652 |
|
| 9653 |
-
if escore_averages[1] <
|
| 9654 |
tempo = 'fast'
|
| 9655 |
|
| 9656 |
-
elif
|
| 9657 |
tempo = 'average'
|
| 9658 |
|
| 9659 |
-
elif escore_averages[1] >
|
| 9660 |
tempo = 'slow'
|
| 9661 |
|
| 9662 |
if escore_averages[2] < 50:
|
|
@@ -9740,10 +9751,20 @@ def escore_notes_to_text_description(escore_notes, song_name='', artist_name='')
|
|
| 9740 |
|
| 9741 |
description += '\n'
|
| 9742 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9743 |
if drums_present and most_common_drums:
|
| 9744 |
description += 'The drum track has predominant '
|
| 9745 |
description += ', '.join(most_common_drums[:-1]) + ' and ' + most_common_drums[-1] + '.'
|
| 9746 |
|
|
|
|
|
|
|
| 9747 |
#==============================================================================
|
| 9748 |
|
| 9749 |
return description
|
|
@@ -10065,6 +10086,239 @@ CONTROL_CHANGES = {
|
|
| 10065 |
127: "Poly Mode On", # + mono off, +all notes off
|
| 10066 |
}
|
| 10067 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10068 |
###################################################################################
|
| 10069 |
#
|
| 10070 |
# This is the end of the TMIDI X Python module
|
|
|
|
| 14 |
#
|
| 15 |
# Project Los Angeles
|
| 16 |
#
|
| 17 |
+
# Tegridy Code 2024
|
| 18 |
#
|
| 19 |
# https://github.com/Tegridy-Code/Project-Los-Angeles
|
| 20 |
#
|
| 21 |
#
|
| 22 |
###################################################################################
|
| 23 |
###################################################################################
|
| 24 |
+
# Copyright 2024 Project Los Angeles / Tegridy Code
|
| 25 |
#
|
| 26 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 27 |
# you may not use this file except in compliance with the License.
|
|
|
|
| 9552 |
###################################################################################
|
| 9553 |
|
| 9554 |
def alpha_str(string):
|
| 9555 |
+
astr = re.sub(r'[^a-zA-Z ()]', '', string).strip()
|
| 9556 |
+
return re.sub(r'\s+', ' ', astr).strip()
|
| 9557 |
|
| 9558 |
###################################################################################
|
| 9559 |
|
| 9560 |
+
def escore_notes_to_text_description(escore_notes,
|
| 9561 |
+
song_name='',
|
| 9562 |
+
artist_name='',
|
| 9563 |
+
timings_divider=16,
|
| 9564 |
+
):
|
| 9565 |
|
| 9566 |
#==============================================================================
|
| 9567 |
|
| 9568 |
+
song_time_min = (escore_notes[-1][1] * timings_divider) / 1000 / 60
|
| 9569 |
|
| 9570 |
if song_time_min < 1.5:
|
| 9571 |
song_length = 'short'
|
|
|
|
| 9597 |
|
| 9598 |
#==============================================================================
|
| 9599 |
|
| 9600 |
+
all_patches = [e[6] for e in escore_notes]
|
| 9601 |
+
|
| 9602 |
+
patches = ordered_set(all_patches)
|
| 9603 |
|
| 9604 |
instruments = [alpha_str(Number2patch[p]) for p in patches if p < 128]
|
| 9605 |
|
| 9606 |
+
nd_patches_counts = Counter([p for p in all_patches if p < 128]).most_common()
|
| 9607 |
+
|
| 9608 |
+
dominant_instrument = alpha_str(Number2patch[nd_patches_counts[0][0]])
|
| 9609 |
+
|
| 9610 |
if 128 in patches:
|
| 9611 |
drums_present = True
|
| 9612 |
|
|
|
|
| 9652 |
|
| 9653 |
escore_averages = escore_notes_averages(escore_notes, return_ptcs_and_vels=True)
|
| 9654 |
|
| 9655 |
+
if escore_averages[0] < (128 / timings_divider):
|
| 9656 |
rythm = 'fast'
|
| 9657 |
|
| 9658 |
+
elif (128 / timings_divider) <= escore_averages[0] <= (192 / timings_divider):
|
| 9659 |
rythm = 'average'
|
| 9660 |
|
| 9661 |
+
elif escore_averages[0] > (192 / timings_divider):
|
| 9662 |
rythm = 'slow'
|
| 9663 |
|
| 9664 |
+
if escore_averages[1] < (256 / timings_divider):
|
| 9665 |
tempo = 'fast'
|
| 9666 |
|
| 9667 |
+
elif (256 / timings_divider) <= escore_averages[1] <= (384 / timings_divider):
|
| 9668 |
tempo = 'average'
|
| 9669 |
|
| 9670 |
+
elif escore_averages[1] > (384 / timings_divider):
|
| 9671 |
tempo = 'slow'
|
| 9672 |
|
| 9673 |
if escore_averages[2] < 50:
|
|
|
|
| 9751 |
|
| 9752 |
description += '\n'
|
| 9753 |
|
| 9754 |
+
description += 'The song starts with ' + instruments[0] + '.'
|
| 9755 |
+
|
| 9756 |
+
description += '\n'
|
| 9757 |
+
|
| 9758 |
+
description += 'The song main instrument is ' + dominant_instrument + '.'
|
| 9759 |
+
|
| 9760 |
+
description += '\n'
|
| 9761 |
+
|
| 9762 |
if drums_present and most_common_drums:
|
| 9763 |
description += 'The drum track has predominant '
|
| 9764 |
description += ', '.join(most_common_drums[:-1]) + ' and ' + most_common_drums[-1] + '.'
|
| 9765 |
|
| 9766 |
+
description += '\n'
|
| 9767 |
+
|
| 9768 |
#==============================================================================
|
| 9769 |
|
| 9770 |
return description
|
|
|
|
| 10086 |
127: "Poly Mode On", # + mono off, +all notes off
|
| 10087 |
}
|
| 10088 |
|
| 10089 |
+
###################################################################################
|
| 10090 |
+
|
| 10091 |
+
def patches_onset_times(escore_notes, times_idx=1, patches_idx=6):
|
| 10092 |
+
|
| 10093 |
+
patches = [e[patches_idx] for e in escore_notes]
|
| 10094 |
+
|
| 10095 |
+
patches_oset = ordered_set(patches)
|
| 10096 |
+
|
| 10097 |
+
patches_onset_times = []
|
| 10098 |
+
|
| 10099 |
+
for p in patches_oset:
|
| 10100 |
+
for e in escore_notes:
|
| 10101 |
+
if e[patches_idx] == p:
|
| 10102 |
+
patches_onset_times.append([p, e[times_idx]])
|
| 10103 |
+
break
|
| 10104 |
+
|
| 10105 |
+
return patches_onset_times
|
| 10106 |
+
|
| 10107 |
+
###################################################################################
|
| 10108 |
+
|
| 10109 |
+
def count_escore_notes_patches(escore_notes, patches_idx=6):
|
| 10110 |
+
|
| 10111 |
+
patches = [e[patches_idx] for e in escore_notes]
|
| 10112 |
+
|
| 10113 |
+
return Counter(patches).most_common()
|
| 10114 |
+
|
| 10115 |
+
###################################################################################
|
| 10116 |
+
|
| 10117 |
+
def escore_notes_monoponic_melodies(escore_notes,
|
| 10118 |
+
bad_notes_ratio=0.0,
|
| 10119 |
+
times_idx=1,
|
| 10120 |
+
patches_idx=6
|
| 10121 |
+
):
|
| 10122 |
+
|
| 10123 |
+
patches = escore_notes_patches(escore_notes, patches_index=patches_idx)
|
| 10124 |
+
|
| 10125 |
+
monophonic_melodies = []
|
| 10126 |
+
|
| 10127 |
+
for p in patches:
|
| 10128 |
+
patch_score = [e for e in escore_notes if e[patches_idx] == p]
|
| 10129 |
+
|
| 10130 |
+
ps_times = [e[times_idx] for e in patch_score]
|
| 10131 |
+
|
| 10132 |
+
if len(ps_times) <= len(set(ps_times)) * (1+bad_notes_ratio):
|
| 10133 |
+
monophonic_melodies.append([p, len(patch_score)])
|
| 10134 |
+
|
| 10135 |
+
return monophonic_melodies
|
| 10136 |
+
|
| 10137 |
+
###################################################################################
|
| 10138 |
+
|
| 10139 |
+
from itertools import groupby
|
| 10140 |
+
from operator import itemgetter
|
| 10141 |
+
|
| 10142 |
+
def group_by_threshold(data, threshold, groupby_idx):
|
| 10143 |
+
|
| 10144 |
+
data.sort(key=itemgetter(groupby_idx))
|
| 10145 |
+
|
| 10146 |
+
grouped_data = []
|
| 10147 |
+
cluster = []
|
| 10148 |
+
|
| 10149 |
+
for i, item in enumerate(data):
|
| 10150 |
+
if not cluster:
|
| 10151 |
+
cluster.append(item)
|
| 10152 |
+
elif abs(item[groupby_idx] - cluster[-1][groupby_idx]) <= threshold:
|
| 10153 |
+
cluster.append(item)
|
| 10154 |
+
else:
|
| 10155 |
+
grouped_data.append(cluster)
|
| 10156 |
+
cluster = [item]
|
| 10157 |
+
|
| 10158 |
+
if cluster:
|
| 10159 |
+
grouped_data.append(cluster)
|
| 10160 |
+
|
| 10161 |
+
return grouped_data
|
| 10162 |
+
|
| 10163 |
+
###################################################################################
|
| 10164 |
+
|
| 10165 |
+
def split_escore_notes_by_time(escore_notes, time_threshold=256):
|
| 10166 |
+
|
| 10167 |
+
dscore = delta_score_notes(escore_notes, timings_clip_value=time_threshold-1)
|
| 10168 |
+
|
| 10169 |
+
score_chunks = []
|
| 10170 |
+
|
| 10171 |
+
ctime = 0
|
| 10172 |
+
pchunk_idx = 0
|
| 10173 |
+
|
| 10174 |
+
for i, e in enumerate(dscore):
|
| 10175 |
+
|
| 10176 |
+
ctime += e[1]
|
| 10177 |
+
|
| 10178 |
+
if ctime >= time_threshold:
|
| 10179 |
+
score_chunks.append(escore_notes[pchunk_idx:i])
|
| 10180 |
+
pchunk_idx = i
|
| 10181 |
+
ctime = 0
|
| 10182 |
+
|
| 10183 |
+
return score_chunks
|
| 10184 |
+
|
| 10185 |
+
###################################################################################
|
| 10186 |
+
|
| 10187 |
+
def escore_notes_grouped_patches(escore_notes, time_threshold=256):
|
| 10188 |
+
|
| 10189 |
+
split_score_chunks = split_escore_notes_by_time(escore_notes,
|
| 10190 |
+
time_threshold=time_threshold
|
| 10191 |
+
)
|
| 10192 |
+
|
| 10193 |
+
chunks_patches = []
|
| 10194 |
+
|
| 10195 |
+
for s in split_score_chunks:
|
| 10196 |
+
chunks_patches.append(escore_notes_patches(s))
|
| 10197 |
+
|
| 10198 |
+
return chunks_patches
|
| 10199 |
+
|
| 10200 |
+
###################################################################################
|
| 10201 |
+
|
| 10202 |
+
def computeLPSArray(pattern, M, lps):
|
| 10203 |
+
length = 0
|
| 10204 |
+
i = 1
|
| 10205 |
+
|
| 10206 |
+
lps[0] = 0
|
| 10207 |
+
|
| 10208 |
+
while i < M:
|
| 10209 |
+
if pattern[i] == pattern[length]:
|
| 10210 |
+
length += 1
|
| 10211 |
+
lps[i] = length
|
| 10212 |
+
i += 1
|
| 10213 |
+
else:
|
| 10214 |
+
if length != 0:
|
| 10215 |
+
length = lps[length-1]
|
| 10216 |
+
else:
|
| 10217 |
+
lps[i] = 0
|
| 10218 |
+
i += 1
|
| 10219 |
+
|
| 10220 |
+
###################################################################################
|
| 10221 |
+
|
| 10222 |
+
def find_pattern_idxs(sub_pattern, pattern):
|
| 10223 |
+
|
| 10224 |
+
lst = pattern
|
| 10225 |
+
pattern = sub_pattern
|
| 10226 |
+
|
| 10227 |
+
M = len(pattern)
|
| 10228 |
+
N = len(lst)
|
| 10229 |
+
|
| 10230 |
+
lps = [0] * M
|
| 10231 |
+
j = 0 # index for pattern[]
|
| 10232 |
+
|
| 10233 |
+
computeLPSArray(pattern, M, lps)
|
| 10234 |
+
|
| 10235 |
+
i = 0 # index for lst[]
|
| 10236 |
+
indexes = []
|
| 10237 |
+
|
| 10238 |
+
while i < N:
|
| 10239 |
+
if pattern[j] == lst[i]:
|
| 10240 |
+
i += 1
|
| 10241 |
+
j += 1
|
| 10242 |
+
|
| 10243 |
+
if j == M:
|
| 10244 |
+
end_index = i - 1
|
| 10245 |
+
start_index = end_index - M + 1
|
| 10246 |
+
indexes.append((start_index, end_index))
|
| 10247 |
+
j = lps[j-1]
|
| 10248 |
+
elif i < N and pattern[j] != lst[i]:
|
| 10249 |
+
if j != 0:
|
| 10250 |
+
j = lps[j-1]
|
| 10251 |
+
else:
|
| 10252 |
+
i += 1
|
| 10253 |
+
|
| 10254 |
+
return indexes
|
| 10255 |
+
|
| 10256 |
+
###################################################################################
|
| 10257 |
+
|
| 10258 |
+
def escore_notes_patch_lrno_patterns(escore_notes,
|
| 10259 |
+
patch=0,
|
| 10260 |
+
zero_score_timings=False,
|
| 10261 |
+
pitches_idx=4,
|
| 10262 |
+
patches_idx=6
|
| 10263 |
+
):
|
| 10264 |
+
|
| 10265 |
+
patch_escore = [e for e in escore_notes if e[patches_idx] == patch]
|
| 10266 |
+
|
| 10267 |
+
if patch_escore:
|
| 10268 |
+
|
| 10269 |
+
patch_cscore = chordify_score([1000, patch_escore])
|
| 10270 |
+
|
| 10271 |
+
patch_tscore = []
|
| 10272 |
+
|
| 10273 |
+
for c in patch_cscore:
|
| 10274 |
+
|
| 10275 |
+
tones_chord = sorted(set([p[pitches_idx] % 12 for p in c]))
|
| 10276 |
+
|
| 10277 |
+
if tones_chord not in ALL_CHORDS_SORTED:
|
| 10278 |
+
tnoes_chord = check_and_fix_tones_chord(tones_chord)
|
| 10279 |
+
|
| 10280 |
+
patch_tscore.append(ALL_CHORDS_SORTED.index(tones_chord))
|
| 10281 |
+
|
| 10282 |
+
pattern = find_lrno_pattern_fast(patch_tscore)
|
| 10283 |
+
|
| 10284 |
+
patterns_idxs = find_pattern_idxs(pattern, patch_tscore)
|
| 10285 |
+
|
| 10286 |
+
patch_lrno_scores = []
|
| 10287 |
+
|
| 10288 |
+
for idxs in patterns_idxs:
|
| 10289 |
+
|
| 10290 |
+
score = patch_escore[idxs[0]:idxs[1]]
|
| 10291 |
+
|
| 10292 |
+
if zero_score_timings:
|
| 10293 |
+
score = recalculate_score_timings(score)
|
| 10294 |
+
|
| 10295 |
+
patch_lrno_scores.append(score)
|
| 10296 |
+
|
| 10297 |
+
return patch_lrno_scores
|
| 10298 |
+
|
| 10299 |
+
else:
|
| 10300 |
+
return []
|
| 10301 |
+
|
| 10302 |
+
###################################################################################
|
| 10303 |
+
|
| 10304 |
+
ALL_BASE_CHORDS_SORTED = [[0], [0, 2], [0, 2, 4], [0, 2, 4, 6], [0, 2, 4, 6, 8], [0, 2, 4, 6, 8, 10],
|
| 10305 |
+
[0, 2, 4, 6, 9], [0, 2, 4, 6, 10], [0, 2, 4, 7], [0, 2, 4, 7, 9],
|
| 10306 |
+
[0, 2, 4, 7, 10], [0, 2, 4, 8], [0, 2, 4, 8, 10], [0, 2, 4, 9], [0, 2, 4, 10],
|
| 10307 |
+
[0, 2, 5], [0, 2, 5, 7], [0, 2, 5, 7, 9], [0, 2, 5, 7, 10], [0, 2, 5, 8],
|
| 10308 |
+
[0, 2, 5, 8, 10], [0, 2, 5, 9], [0, 2, 5, 10], [0, 2, 6], [0, 2, 6, 8],
|
| 10309 |
+
[0, 2, 6, 8, 10], [0, 2, 6, 9], [0, 2, 6, 10], [0, 2, 7], [0, 2, 7, 9],
|
| 10310 |
+
[0, 2, 7, 10], [0, 2, 8], [0, 2, 8, 10], [0, 2, 9], [0, 2, 10], [0, 3],
|
| 10311 |
+
[0, 3, 5], [0, 3, 5, 7], [0, 3, 5, 7, 9], [0, 3, 5, 7, 10], [0, 3, 5, 8],
|
| 10312 |
+
[0, 3, 5, 8, 10], [0, 3, 5, 9], [0, 3, 5, 10], [0, 3, 6], [0, 3, 6, 8],
|
| 10313 |
+
[0, 3, 6, 8, 10], [0, 3, 6, 9], [0, 3, 6, 10], [0, 3, 7], [0, 3, 7, 9],
|
| 10314 |
+
[0, 3, 7, 10], [0, 3, 8], [0, 3, 8, 10], [0, 3, 9], [0, 3, 10], [0, 4],
|
| 10315 |
+
[0, 4, 6], [0, 4, 6, 8], [0, 4, 6, 8, 10], [0, 4, 6, 9], [0, 4, 6, 10],
|
| 10316 |
+
[0, 4, 7], [0, 4, 7, 9], [0, 4, 7, 10], [0, 4, 8], [0, 4, 8, 10], [0, 4, 9],
|
| 10317 |
+
[0, 4, 10], [0, 5], [0, 5, 7], [0, 5, 7, 9], [0, 5, 7, 10], [0, 5, 8],
|
| 10318 |
+
[0, 5, 8, 10], [0, 5, 9], [0, 5, 10], [0, 6], [0, 6, 8], [0, 6, 8, 10],
|
| 10319 |
+
[0, 6, 9], [0, 6, 10], [0, 7], [0, 7, 9], [0, 7, 10], [0, 8], [0, 8, 10],
|
| 10320 |
+
[0, 9], [0, 10]]
|
| 10321 |
+
|
| 10322 |
###################################################################################
|
| 10323 |
#
|
| 10324 |
# This is the end of the TMIDI X Python module
|