Spaces:
Running
Running
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.
|
@@ -7101,13 +7101,25 @@ def escore_notes_averages(escore_notes,
|
|
7101 |
else:
|
7102 |
durs = [e[durs_index] for e in escore_notes if e[chans_index] != 9]
|
7103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
7104 |
if return_ptcs_and_vels:
|
7105 |
if average_drums:
|
7106 |
ptcs = [e[ptcs_index] for e in escore_notes]
|
7107 |
vels = [e[vels_index] for e in escore_notes]
|
7108 |
else:
|
7109 |
ptcs = [e[ptcs_index] for e in escore_notes if e[chans_index] != 9]
|
7110 |
-
vels = [e[vels_index] for e in escore_notes if e[chans_index] != 9]
|
|
|
|
|
|
|
|
|
|
|
|
|
7111 |
|
7112 |
return [sum(times) / len(times), sum(durs) / len(durs), sum(ptcs) / len(ptcs), sum(vels) / len(vels)]
|
7113 |
|
@@ -9540,15 +9552,20 @@ MOOD_SCALES = ['Major', 'Minor', 'Major Minor']
|
|
9540 |
###################################################################################
|
9541 |
|
9542 |
def alpha_str(string):
|
9543 |
-
|
|
|
9544 |
|
9545 |
###################################################################################
|
9546 |
|
9547 |
-
def escore_notes_to_text_description(escore_notes,
|
|
|
|
|
|
|
|
|
9548 |
|
9549 |
#==============================================================================
|
9550 |
|
9551 |
-
song_time_min = (escore_notes[-1][1] *
|
9552 |
|
9553 |
if song_time_min < 1.5:
|
9554 |
song_length = 'short'
|
@@ -9567,23 +9584,29 @@ def escore_notes_to_text_description(escore_notes, song_name='', artist_name='')
|
|
9567 |
|
9568 |
if len(escore_times) > 0:
|
9569 |
if len(escore_times) == len(set(escore_times)):
|
9570 |
-
comp_type = 'melody
|
9571 |
|
9572 |
elif len(escore_times) >= len(set(escore_times)) and 1 in Counter(escore_times).values():
|
9573 |
comp_type = 'melody and accompaniment'
|
9574 |
|
9575 |
elif len(escore_times) >= len(set(escore_times)) and 1 not in Counter(escore_times).values():
|
9576 |
-
comp_type = 'accompaniment
|
9577 |
|
9578 |
else:
|
9579 |
comp_type = 'drums only'
|
9580 |
|
9581 |
#==============================================================================
|
9582 |
|
9583 |
-
|
|
|
|
|
9584 |
|
9585 |
instruments = [alpha_str(Number2patch[p]) for p in patches if p < 128]
|
9586 |
|
|
|
|
|
|
|
|
|
9587 |
if 128 in patches:
|
9588 |
drums_present = True
|
9589 |
|
@@ -9592,7 +9615,7 @@ def escore_notes_to_text_description(escore_notes, song_name='', artist_name='')
|
|
9592 |
|
9593 |
drums_pitches = [e[4] for e in escore_notes if e[3] == 9]
|
9594 |
|
9595 |
-
most_common_drums = [alpha_str(Notenum2percussion[p[0]]) for p in Counter(drums_pitches).most_common(3)]
|
9596 |
|
9597 |
#==============================================================================
|
9598 |
|
@@ -9629,22 +9652,22 @@ def escore_notes_to_text_description(escore_notes, song_name='', artist_name='')
|
|
9629 |
|
9630 |
escore_averages = escore_notes_averages(escore_notes, return_ptcs_and_vels=True)
|
9631 |
|
9632 |
-
if escore_averages[0] <
|
9633 |
rythm = 'fast'
|
9634 |
|
9635 |
-
elif
|
9636 |
rythm = 'average'
|
9637 |
|
9638 |
-
elif escore_averages[0] >
|
9639 |
rythm = 'slow'
|
9640 |
|
9641 |
-
if escore_averages[1] <
|
9642 |
tempo = 'fast'
|
9643 |
|
9644 |
-
elif
|
9645 |
tempo = 'average'
|
9646 |
|
9647 |
-
elif escore_averages[1] >
|
9648 |
tempo = 'slow'
|
9649 |
|
9650 |
if escore_averages[2] < 50:
|
@@ -9691,7 +9714,7 @@ def escore_notes_to_text_description(escore_notes, song_name='', artist_name='')
|
|
9691 |
|
9692 |
description += comp_type + ' composition'
|
9693 |
|
9694 |
-
if comp_type != '
|
9695 |
|
9696 |
if drums_present:
|
9697 |
description += ' with drums'
|
@@ -9723,19 +9746,579 @@ def escore_notes_to_text_description(escore_notes, song_name='', artist_name='')
|
|
9723 |
description += 'is played on a solo ' + instruments[0] + '.'
|
9724 |
|
9725 |
else:
|
9726 |
-
description += 'features ' + NUMERALS[len(instruments)-1] + ' instruments: '
|
9727 |
description += ', '.join(instruments[:-1]) + ' and ' + instruments[-1] + '.'
|
9728 |
|
9729 |
description += '\n'
|
9730 |
|
9731 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9732 |
description += 'The drum track has predominant '
|
9733 |
description += ', '.join(most_common_drums[:-1]) + ' and ' + most_common_drums[-1] + '.'
|
9734 |
|
|
|
|
|
9735 |
#==============================================================================
|
9736 |
|
9737 |
return description
|
9738 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9739 |
###################################################################################
|
9740 |
#
|
9741 |
# 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.
|
|
|
7101 |
else:
|
7102 |
durs = [e[durs_index] for e in escore_notes if e[chans_index] != 9]
|
7103 |
|
7104 |
+
if len(times) == 0:
|
7105 |
+
times = [0]
|
7106 |
+
|
7107 |
+
if len(durs) == 0:
|
7108 |
+
durs = [0]
|
7109 |
+
|
7110 |
if return_ptcs_and_vels:
|
7111 |
if average_drums:
|
7112 |
ptcs = [e[ptcs_index] for e in escore_notes]
|
7113 |
vels = [e[vels_index] for e in escore_notes]
|
7114 |
else:
|
7115 |
ptcs = [e[ptcs_index] for e in escore_notes if e[chans_index] != 9]
|
7116 |
+
vels = [e[vels_index] for e in escore_notes if e[chans_index] != 9]
|
7117 |
+
|
7118 |
+
if len(ptcs) == 0:
|
7119 |
+
ptcs = [0]
|
7120 |
+
|
7121 |
+
if len(vels) == 0:
|
7122 |
+
vels = [0]
|
7123 |
|
7124 |
return [sum(times) / len(times), sum(durs) / len(durs), sum(ptcs) / len(ptcs), sum(vels) / len(vels)]
|
7125 |
|
|
|
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'
|
|
|
9584 |
|
9585 |
if len(escore_times) > 0:
|
9586 |
if len(escore_times) == len(set(escore_times)):
|
9587 |
+
comp_type = 'monophonic melody'
|
9588 |
|
9589 |
elif len(escore_times) >= len(set(escore_times)) and 1 in Counter(escore_times).values():
|
9590 |
comp_type = 'melody and accompaniment'
|
9591 |
|
9592 |
elif len(escore_times) >= len(set(escore_times)) and 1 not in Counter(escore_times).values():
|
9593 |
+
comp_type = 'accompaniment'
|
9594 |
|
9595 |
else:
|
9596 |
comp_type = 'drums only'
|
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 |
|
|
|
9615 |
|
9616 |
drums_pitches = [e[4] for e in escore_notes if e[3] == 9]
|
9617 |
|
9618 |
+
most_common_drums = [alpha_str(Notenum2percussion[p[0]]) for p in Counter(drums_pitches).most_common(3) if p[0] in Notenum2percussion]
|
9619 |
|
9620 |
#==============================================================================
|
9621 |
|
|
|
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:
|
|
|
9714 |
|
9715 |
description += comp_type + ' composition'
|
9716 |
|
9717 |
+
if comp_type != 'drum track':
|
9718 |
|
9719 |
if drums_present:
|
9720 |
description += ' with drums'
|
|
|
9746 |
description += 'is played on a solo ' + instruments[0] + '.'
|
9747 |
|
9748 |
else:
|
9749 |
+
description += 'features ' + NUMERALS[max(0, min(15, len(instruments)-1))] + ' instruments: '
|
9750 |
description += ', '.join(instruments[:-1]) + ' and ' + instruments[-1] + '.'
|
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
|
9771 |
|
9772 |
+
###################################################################################
|
9773 |
+
|
9774 |
+
#==================================================================================
|
9775 |
+
#
|
9776 |
+
# Below constants code is a courtesy of MidiTok
|
9777 |
+
#
|
9778 |
+
# Retrieved on 12/29/2024
|
9779 |
+
#
|
9780 |
+
# https://github.com/Natooz/MidiTok/blob/main/src/miditok/constants.py
|
9781 |
+
#
|
9782 |
+
#==================================================================================
|
9783 |
+
|
9784 |
+
MIDI_FILES_EXTENSIONS = [".mid", ".midi", ".kar", ".MID", ".MIDI", ".KAR"]
|
9785 |
+
|
9786 |
+
# The recommended pitches for piano in the GM2 specs are from 21 to 108
|
9787 |
+
PIANO_PITCH_RANGE = range(21, 109)
|
9788 |
+
|
9789 |
+
# Chord params
|
9790 |
+
# "chord_unknown" specifies the range of number of notes that can form "unknown" chords
|
9791 |
+
# (that do not fit in "chord_maps") to add in tokens.
|
9792 |
+
# Known chord maps, with 0 as root note
|
9793 |
+
BASIC_CHORDS_MAP = {
|
9794 |
+
"min": (0, 3, 7),
|
9795 |
+
"maj": (0, 4, 7),
|
9796 |
+
"dim": (0, 3, 6),
|
9797 |
+
"aug": (0, 4, 8),
|
9798 |
+
"sus2": (0, 2, 7),
|
9799 |
+
"sus4": (0, 5, 7),
|
9800 |
+
"7dom": (0, 4, 7, 10),
|
9801 |
+
"7min": (0, 3, 7, 10),
|
9802 |
+
"7maj": (0, 4, 7, 11),
|
9803 |
+
"7halfdim": (0, 3, 6, 10),
|
9804 |
+
"7dim": (0, 3, 6, 9),
|
9805 |
+
"7aug": (0, 4, 8, 11),
|
9806 |
+
"9maj": (0, 4, 7, 10, 14),
|
9807 |
+
"9min": (0, 4, 7, 10, 13),
|
9808 |
+
}
|
9809 |
+
|
9810 |
+
# Drums
|
9811 |
+
# Recommended range from the GM2 specs
|
9812 |
+
DRUMS_PITCH_RANGE = range(27, 90)
|
9813 |
+
|
9814 |
+
# Used with chords
|
9815 |
+
PITCH_CLASSES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
|
9816 |
+
|
9817 |
+
# http://newt.phys.unsw.edu.au/jw/notes.html
|
9818 |
+
# https://www.midi.org/specifications
|
9819 |
+
|
9820 |
+
# index i = program i+1 in the GM2 specs (7. Appendix A)
|
9821 |
+
# index i = program i as retrieved by packages
|
9822 |
+
MIDI_INSTRUMENTS = [
|
9823 |
+
# Piano
|
9824 |
+
{"name": "Acoustic Grand Piano", "pitch_range": range(21, 109)},
|
9825 |
+
{"name": "Bright Acoustic Piano", "pitch_range": range(21, 109)},
|
9826 |
+
{"name": "Electric Grand Piano", "pitch_range": range(21, 109)},
|
9827 |
+
{"name": "Honky-tonk Piano", "pitch_range": range(21, 109)},
|
9828 |
+
{"name": "Electric Piano 1", "pitch_range": range(28, 104)},
|
9829 |
+
{"name": "Electric Piano 2", "pitch_range": range(28, 104)},
|
9830 |
+
{"name": "Harpsichord", "pitch_range": range(41, 90)},
|
9831 |
+
{"name": "Clavi", "pitch_range": range(36, 97)},
|
9832 |
+
# Chromatic Percussion
|
9833 |
+
{"name": "Celesta", "pitch_range": range(60, 109)},
|
9834 |
+
{"name": "Glockenspiel", "pitch_range": range(72, 109)},
|
9835 |
+
{"name": "Music Box", "pitch_range": range(60, 85)},
|
9836 |
+
{"name": "Vibraphone", "pitch_range": range(53, 90)},
|
9837 |
+
{"name": "Marimba", "pitch_range": range(48, 85)},
|
9838 |
+
{"name": "Xylophone", "pitch_range": range(65, 97)},
|
9839 |
+
{"name": "Tubular Bells", "pitch_range": range(60, 78)},
|
9840 |
+
{"name": "Dulcimer", "pitch_range": range(60, 85)},
|
9841 |
+
# Organs
|
9842 |
+
{"name": "Drawbar Organ", "pitch_range": range(36, 97)},
|
9843 |
+
{"name": "Percussive Organ", "pitch_range": range(36, 97)},
|
9844 |
+
{"name": "Rock Organ", "pitch_range": range(36, 97)},
|
9845 |
+
{"name": "Church Organ", "pitch_range": range(21, 109)},
|
9846 |
+
{"name": "Reed Organ", "pitch_range": range(36, 97)},
|
9847 |
+
{"name": "Accordion", "pitch_range": range(53, 90)},
|
9848 |
+
{"name": "Harmonica", "pitch_range": range(60, 85)},
|
9849 |
+
{"name": "Tango Accordion", "pitch_range": range(53, 90)},
|
9850 |
+
# Guitars
|
9851 |
+
{"name": "Acoustic Guitar (nylon)", "pitch_range": range(40, 85)},
|
9852 |
+
{"name": "Acoustic Guitar (steel)", "pitch_range": range(40, 85)},
|
9853 |
+
{"name": "Electric Guitar (jazz)", "pitch_range": range(40, 87)},
|
9854 |
+
{"name": "Electric Guitar (clean)", "pitch_range": range(40, 87)},
|
9855 |
+
{"name": "Electric Guitar (muted)", "pitch_range": range(40, 87)},
|
9856 |
+
{"name": "Overdriven Guitar", "pitch_range": range(40, 87)},
|
9857 |
+
{"name": "Distortion Guitar", "pitch_range": range(40, 87)},
|
9858 |
+
{"name": "Guitar Harmonics", "pitch_range": range(40, 87)},
|
9859 |
+
# Bass
|
9860 |
+
{"name": "Acoustic Bass", "pitch_range": range(28, 56)},
|
9861 |
+
{"name": "Electric Bass (finger)", "pitch_range": range(28, 56)},
|
9862 |
+
{"name": "Electric Bass (pick)", "pitch_range": range(28, 56)},
|
9863 |
+
{"name": "Fretless Bass", "pitch_range": range(28, 56)},
|
9864 |
+
{"name": "Slap Bass 1", "pitch_range": range(28, 56)},
|
9865 |
+
{"name": "Slap Bass 2", "pitch_range": range(28, 56)},
|
9866 |
+
{"name": "Synth Bass 1", "pitch_range": range(28, 56)},
|
9867 |
+
{"name": "Synth Bass 2", "pitch_range": range(28, 56)},
|
9868 |
+
# Strings & Orchestral instruments
|
9869 |
+
{"name": "Violin", "pitch_range": range(55, 94)},
|
9870 |
+
{"name": "Viola", "pitch_range": range(48, 85)},
|
9871 |
+
{"name": "Cello", "pitch_range": range(36, 73)},
|
9872 |
+
{"name": "Contrabass", "pitch_range": range(28, 56)},
|
9873 |
+
{"name": "Tremolo Strings", "pitch_range": range(28, 94)},
|
9874 |
+
{"name": "Pizzicato Strings", "pitch_range": range(28, 94)},
|
9875 |
+
{"name": "Orchestral Harp", "pitch_range": range(23, 104)},
|
9876 |
+
{"name": "Timpani", "pitch_range": range(36, 58)},
|
9877 |
+
# Ensembles
|
9878 |
+
{"name": "String Ensembles 1", "pitch_range": range(28, 97)},
|
9879 |
+
{"name": "String Ensembles 2", "pitch_range": range(28, 97)},
|
9880 |
+
{"name": "SynthStrings 1", "pitch_range": range(36, 97)},
|
9881 |
+
{"name": "SynthStrings 2", "pitch_range": range(36, 97)},
|
9882 |
+
{"name": "Choir Aahs", "pitch_range": range(48, 80)},
|
9883 |
+
{"name": "Voice Oohs", "pitch_range": range(48, 80)},
|
9884 |
+
{"name": "Synth Voice", "pitch_range": range(48, 85)},
|
9885 |
+
{"name": "Orchestra Hit", "pitch_range": range(48, 73)},
|
9886 |
+
# Brass
|
9887 |
+
{"name": "Trumpet", "pitch_range": range(58, 95)},
|
9888 |
+
{"name": "Trombone", "pitch_range": range(34, 76)},
|
9889 |
+
{"name": "Tuba", "pitch_range": range(29, 56)},
|
9890 |
+
{"name": "Muted Trumpet", "pitch_range": range(58, 83)},
|
9891 |
+
{"name": "French Horn", "pitch_range": range(41, 78)},
|
9892 |
+
{"name": "Brass Section", "pitch_range": range(36, 97)},
|
9893 |
+
{"name": "Synth Brass 1", "pitch_range": range(36, 97)},
|
9894 |
+
{"name": "Synth Brass 2", "pitch_range": range(36, 97)},
|
9895 |
+
# Reed
|
9896 |
+
{"name": "Soprano Sax", "pitch_range": range(54, 88)},
|
9897 |
+
{"name": "Alto Sax", "pitch_range": range(49, 81)},
|
9898 |
+
{"name": "Tenor Sax", "pitch_range": range(42, 76)},
|
9899 |
+
{"name": "Baritone Sax", "pitch_range": range(37, 69)},
|
9900 |
+
{"name": "Oboe", "pitch_range": range(58, 92)},
|
9901 |
+
{"name": "English Horn", "pitch_range": range(52, 82)},
|
9902 |
+
{"name": "Bassoon", "pitch_range": range(34, 73)},
|
9903 |
+
{"name": "Clarinet", "pitch_range": range(50, 92)},
|
9904 |
+
# Pipe
|
9905 |
+
{"name": "Piccolo", "pitch_range": range(74, 109)},
|
9906 |
+
{"name": "Flute", "pitch_range": range(60, 97)},
|
9907 |
+
{"name": "Recorder", "pitch_range": range(60, 97)},
|
9908 |
+
{"name": "Pan Flute", "pitch_range": range(60, 97)},
|
9909 |
+
{"name": "Blown Bottle", "pitch_range": range(60, 97)},
|
9910 |
+
{"name": "Shakuhachi", "pitch_range": range(55, 85)},
|
9911 |
+
{"name": "Whistle", "pitch_range": range(60, 97)},
|
9912 |
+
{"name": "Ocarina", "pitch_range": range(60, 85)},
|
9913 |
+
# Synth Lead
|
9914 |
+
{"name": "Lead 1 (square)", "pitch_range": range(21, 109)},
|
9915 |
+
{"name": "Lead 2 (sawtooth)", "pitch_range": range(21, 109)},
|
9916 |
+
{"name": "Lead 3 (calliope)", "pitch_range": range(36, 97)},
|
9917 |
+
{"name": "Lead 4 (chiff)", "pitch_range": range(36, 97)},
|
9918 |
+
{"name": "Lead 5 (charang)", "pitch_range": range(36, 97)},
|
9919 |
+
{"name": "Lead 6 (voice)", "pitch_range": range(36, 97)},
|
9920 |
+
{"name": "Lead 7 (fifths)", "pitch_range": range(36, 97)},
|
9921 |
+
{"name": "Lead 8 (bass + lead)", "pitch_range": range(21, 109)},
|
9922 |
+
# Synth Pad
|
9923 |
+
{"name": "Pad 1 (new age)", "pitch_range": range(36, 97)},
|
9924 |
+
{"name": "Pad 2 (warm)", "pitch_range": range(36, 97)},
|
9925 |
+
{"name": "Pad 3 (polysynth)", "pitch_range": range(36, 97)},
|
9926 |
+
{"name": "Pad 4 (choir)", "pitch_range": range(36, 97)},
|
9927 |
+
{"name": "Pad 5 (bowed)", "pitch_range": range(36, 97)},
|
9928 |
+
{"name": "Pad 6 (metallic)", "pitch_range": range(36, 97)},
|
9929 |
+
{"name": "Pad 7 (halo)", "pitch_range": range(36, 97)},
|
9930 |
+
{"name": "Pad 8 (sweep)", "pitch_range": range(36, 97)},
|
9931 |
+
# Synth SFX
|
9932 |
+
{"name": "FX 1 (rain)", "pitch_range": range(36, 97)},
|
9933 |
+
{"name": "FX 2 (soundtrack)", "pitch_range": range(36, 97)},
|
9934 |
+
{"name": "FX 3 (crystal)", "pitch_range": range(36, 97)},
|
9935 |
+
{"name": "FX 4 (atmosphere)", "pitch_range": range(36, 97)},
|
9936 |
+
{"name": "FX 5 (brightness)", "pitch_range": range(36, 97)},
|
9937 |
+
{"name": "FX 6 (goblins)", "pitch_range": range(36, 97)},
|
9938 |
+
{"name": "FX 7 (echoes)", "pitch_range": range(36, 97)},
|
9939 |
+
{"name": "FX 8 (sci-fi)", "pitch_range": range(36, 97)},
|
9940 |
+
# Ethnic Misc.
|
9941 |
+
{"name": "Sitar", "pitch_range": range(48, 78)},
|
9942 |
+
{"name": "Banjo", "pitch_range": range(48, 85)},
|
9943 |
+
{"name": "Shamisen", "pitch_range": range(50, 80)},
|
9944 |
+
{"name": "Koto", "pitch_range": range(55, 85)},
|
9945 |
+
{"name": "Kalimba", "pitch_range": range(48, 80)},
|
9946 |
+
{"name": "Bag pipe", "pitch_range": range(36, 78)},
|
9947 |
+
{"name": "Fiddle", "pitch_range": range(55, 97)},
|
9948 |
+
{"name": "Shanai", "pitch_range": range(48, 73)},
|
9949 |
+
# Percussive
|
9950 |
+
{"name": "Tinkle Bell", "pitch_range": range(72, 85)},
|
9951 |
+
{"name": "Agogo", "pitch_range": range(60, 73)},
|
9952 |
+
{"name": "Steel Drums", "pitch_range": range(52, 77)},
|
9953 |
+
{"name": "Woodblock", "pitch_range": range(128)},
|
9954 |
+
{"name": "Taiko Drum", "pitch_range": range(128)},
|
9955 |
+
{"name": "Melodic Tom", "pitch_range": range(128)},
|
9956 |
+
{"name": "Synth Drum", "pitch_range": range(128)},
|
9957 |
+
{"name": "Reverse Cymbal", "pitch_range": range(128)},
|
9958 |
+
# SFX
|
9959 |
+
{"name": "Guitar Fret Noise, Guitar Cutting Noise", "pitch_range": range(128)},
|
9960 |
+
{"name": "Breath Noise, Flute Key Click", "pitch_range": range(128)},
|
9961 |
+
{
|
9962 |
+
"name": "Seashore, Rain, Thunder, Wind, Stream, Bubbles",
|
9963 |
+
"pitch_range": range(128),
|
9964 |
+
},
|
9965 |
+
{"name": "Bird Tweet, Dog, Horse Gallop", "pitch_range": range(128)},
|
9966 |
+
{
|
9967 |
+
"name": "Telephone Ring, Door Creaking, Door, Scratch, Wind Chime",
|
9968 |
+
"pitch_range": range(128),
|
9969 |
+
},
|
9970 |
+
{"name": "Helicopter, Car Sounds", "pitch_range": range(128)},
|
9971 |
+
{
|
9972 |
+
"name": "Applause, Laughing, Screaming, Punch, Heart Beat, Footstep",
|
9973 |
+
"pitch_range": range(128),
|
9974 |
+
},
|
9975 |
+
{"name": "Gunshot, Machine Gun, Lasergun, Explosion", "pitch_range": range(128)},
|
9976 |
+
]
|
9977 |
+
|
9978 |
+
INSTRUMENTS_CLASSES = [
|
9979 |
+
{"name": "Piano", "program_range": range(8)}, # 0
|
9980 |
+
{"name": "Chromatic Percussion", "program_range": range(8, 16)},
|
9981 |
+
{"name": "Organ", "program_range": range(16, 24)},
|
9982 |
+
{"name": "Guitar", "program_range": range(24, 32)},
|
9983 |
+
{"name": "Bass", "program_range": range(32, 40)},
|
9984 |
+
{"name": "Strings", "program_range": range(40, 48)}, # 5
|
9985 |
+
{"name": "Ensemble", "program_range": range(48, 56)},
|
9986 |
+
{"name": "Brass", "program_range": range(56, 64)},
|
9987 |
+
{"name": "Reed", "program_range": range(64, 72)},
|
9988 |
+
{"name": "Pipe", "program_range": range(72, 80)},
|
9989 |
+
{"name": "Synth Lead", "program_range": range(80, 88)}, # 10
|
9990 |
+
{"name": "Synth Pad", "program_range": range(88, 96)},
|
9991 |
+
{"name": "Synth Effects", "program_range": range(96, 104)},
|
9992 |
+
{"name": "Ethnic", "program_range": range(104, 112)},
|
9993 |
+
{"name": "Percussive", "program_range": range(112, 120)},
|
9994 |
+
{"name": "Sound Effects", "program_range": range(120, 128)}, # 15
|
9995 |
+
{"name": "Drums", "program_range": range(-1, 0)},
|
9996 |
+
]
|
9997 |
+
|
9998 |
+
# To easily get the class index of any instrument program
|
9999 |
+
CLASS_OF_INST = [
|
10000 |
+
i
|
10001 |
+
for i, inst_class in enumerate(INSTRUMENTS_CLASSES)
|
10002 |
+
for _ in inst_class["program_range"]
|
10003 |
+
]
|
10004 |
+
|
10005 |
+
# index i = program i+1 in the GM2 specs (8. Appendix B)
|
10006 |
+
# index i = program i retrieved by packages
|
10007 |
+
DRUMS_SETS = {
|
10008 |
+
0: "Standard",
|
10009 |
+
8: "Room",
|
10010 |
+
16: "Power",
|
10011 |
+
24: "Electronic",
|
10012 |
+
25: "Analog",
|
10013 |
+
32: "Jazz",
|
10014 |
+
40: "Brush",
|
10015 |
+
48: "Orchestra",
|
10016 |
+
56: "SFX",
|
10017 |
+
}
|
10018 |
+
|
10019 |
+
# Control changes list (without specifications):
|
10020 |
+
# https://www.midi.org/specifications-old/item/table-3-control-change-messages-data-bytes-2
|
10021 |
+
# Undefined and general control changes are not considered here
|
10022 |
+
# All these attributes can take values from 0 to 127, with some of them being on/off
|
10023 |
+
CONTROL_CHANGES = {
|
10024 |
+
# MSB
|
10025 |
+
0: "Bank Select",
|
10026 |
+
1: "Modulation Depth",
|
10027 |
+
2: "Breath Controller",
|
10028 |
+
4: "Foot Controller",
|
10029 |
+
5: "Portamento Time",
|
10030 |
+
6: "Data Entry",
|
10031 |
+
7: "Channel Volume",
|
10032 |
+
8: "Balance",
|
10033 |
+
10: "Pan",
|
10034 |
+
11: "Expression Controller",
|
10035 |
+
# LSB
|
10036 |
+
32: "Bank Select",
|
10037 |
+
33: "Modulation Depth",
|
10038 |
+
34: "Breath Controller",
|
10039 |
+
36: "Foot Controller",
|
10040 |
+
37: "Portamento Time",
|
10041 |
+
38: "Data Entry",
|
10042 |
+
39: "Channel Volume",
|
10043 |
+
40: "Balance",
|
10044 |
+
42: "Pan",
|
10045 |
+
43: "Expression Controller",
|
10046 |
+
# On / Off control changes, ≤63 off, ≥64 on
|
10047 |
+
64: "Damper Pedal",
|
10048 |
+
65: "Portamento",
|
10049 |
+
66: "Sostenuto",
|
10050 |
+
67: "Soft Pedal",
|
10051 |
+
68: "Legato Footswitch",
|
10052 |
+
69: "Hold 2",
|
10053 |
+
# Continuous controls
|
10054 |
+
70: "Sound Variation",
|
10055 |
+
71: "Timbre/Harmonic Intensity",
|
10056 |
+
72: "Release Time",
|
10057 |
+
73: "Attack Time",
|
10058 |
+
74: "Brightness",
|
10059 |
+
75: "Decay Time",
|
10060 |
+
76: "Vibrato Rate",
|
10061 |
+
77: "Vibrato Depth",
|
10062 |
+
78: "Vibrato Delay",
|
10063 |
+
84: "Portamento Control",
|
10064 |
+
88: "High Resolution Velocity Prefix",
|
10065 |
+
# Effects depths
|
10066 |
+
91: "Reverb Depth",
|
10067 |
+
92: "Tremolo Depth",
|
10068 |
+
93: "Chorus Depth",
|
10069 |
+
94: "Celeste Depth",
|
10070 |
+
95: "Phaser Depth",
|
10071 |
+
# Registered parameters numbers
|
10072 |
+
96: "Data Increment",
|
10073 |
+
97: "Data Decrement",
|
10074 |
+
# 98: 'Non-Registered Parameter Number (NRPN) - LSB',
|
10075 |
+
# 99: 'Non-Registered Parameter Number (NRPN) - MSB',
|
10076 |
+
100: "Registered Parameter Number (RPN) - LSB",
|
10077 |
+
101: "Registered Parameter Number (RPN) - MSB",
|
10078 |
+
# Channel mode controls
|
10079 |
+
120: "All Sound Off",
|
10080 |
+
121: "Reset All Controllers",
|
10081 |
+
122: "Local Control On/Off",
|
10082 |
+
123: "All Notes Off",
|
10083 |
+
124: "Omni Mode Off", # + all notes off
|
10084 |
+
125: "Omni Mode On", # + all notes off
|
10085 |
+
126: "Mono Mode On", # + poly off, + all notes off
|
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
|