Spaces:
Sleeping
Sleeping
Upload TMIDIX.py
Browse files
TMIDIX.py
CHANGED
|
@@ -9381,6 +9381,351 @@ def advanced_add_drums_to_escore_notes(escore_notes,
|
|
| 9381 |
|
| 9382 |
return delta_score_to_abs_score(drums_score)
|
| 9383 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9384 |
###################################################################################
|
| 9385 |
#
|
| 9386 |
# This is the end of the TMIDI X Python module
|
|
|
|
| 9381 |
|
| 9382 |
return delta_score_to_abs_score(drums_score)
|
| 9383 |
|
| 9384 |
+
###################################################################################
|
| 9385 |
+
|
| 9386 |
+
MIDI_TEXT_EVENTS = ['text_event',
|
| 9387 |
+
'copyright_text_event',
|
| 9388 |
+
'track_name',
|
| 9389 |
+
'instrument_name',
|
| 9390 |
+
'lyric',
|
| 9391 |
+
'marker',
|
| 9392 |
+
'cue_point',
|
| 9393 |
+
'text_event_08',
|
| 9394 |
+
'text_event_09',
|
| 9395 |
+
'text_event_0a',
|
| 9396 |
+
'text_event_0b',
|
| 9397 |
+
'text_event_0c',
|
| 9398 |
+
'text_event_0d',
|
| 9399 |
+
'text_event_0e',
|
| 9400 |
+
'text_event_0f'
|
| 9401 |
+
]
|
| 9402 |
+
|
| 9403 |
+
###################################################################################
|
| 9404 |
+
|
| 9405 |
+
import hashlib
|
| 9406 |
+
import re
|
| 9407 |
+
|
| 9408 |
+
###################################################################################
|
| 9409 |
+
|
| 9410 |
+
def get_md5_hash(data):
|
| 9411 |
+
return hashlib.md5(data).hexdigest()
|
| 9412 |
+
|
| 9413 |
+
###################################################################################
|
| 9414 |
+
|
| 9415 |
+
def is_valid_md5_hash(string):
|
| 9416 |
+
return bool(re.match(r'^[a-fA-F0-9]{32}$', string))
|
| 9417 |
+
|
| 9418 |
+
###################################################################################
|
| 9419 |
+
|
| 9420 |
+
def clean_string(original_string,
|
| 9421 |
+
regex=r'[^a-zA-Z0-9 ]',
|
| 9422 |
+
remove_duplicate_spaces=True,
|
| 9423 |
+
title=False
|
| 9424 |
+
):
|
| 9425 |
+
|
| 9426 |
+
cstr1 = re.sub(regex, '', original_string)
|
| 9427 |
+
|
| 9428 |
+
if title:
|
| 9429 |
+
cstr1 = cstr1.title()
|
| 9430 |
+
|
| 9431 |
+
if remove_duplicate_spaces:
|
| 9432 |
+
return re.sub(r'\s+', ' ', cstr1).strip()
|
| 9433 |
+
|
| 9434 |
+
else:
|
| 9435 |
+
return cstr1
|
| 9436 |
+
|
| 9437 |
+
###################################################################################
|
| 9438 |
+
|
| 9439 |
+
def encode_to_ord(text, chars_range=[], sub_char='', chars_shift=0):
|
| 9440 |
+
|
| 9441 |
+
if not chars_range:
|
| 9442 |
+
chars_range = [32] + list(range(65, 91)) + list(range(97, 123))
|
| 9443 |
+
|
| 9444 |
+
if sub_char:
|
| 9445 |
+
chars_range.append(ord(sub_char))
|
| 9446 |
+
|
| 9447 |
+
chars_range = sorted(set(chars_range))
|
| 9448 |
+
|
| 9449 |
+
encoded = []
|
| 9450 |
+
|
| 9451 |
+
for char in text:
|
| 9452 |
+
if ord(char) in chars_range:
|
| 9453 |
+
encoded.append(chars_range.index(ord(char)) + chars_shift)
|
| 9454 |
+
|
| 9455 |
+
else:
|
| 9456 |
+
if sub_char:
|
| 9457 |
+
encoded.append(chars_range.index(ord(sub_char)) + chars_shift)
|
| 9458 |
+
|
| 9459 |
+
|
| 9460 |
+
return [encoded, chars_range]
|
| 9461 |
+
|
| 9462 |
+
###################################################################################
|
| 9463 |
+
|
| 9464 |
+
def decode_from_ord(ord_list, chars_range=[], sub_char='', chars_shift=0):
|
| 9465 |
+
|
| 9466 |
+
if not chars_range:
|
| 9467 |
+
chars_range = [32] + list(range(65, 91)) + list(range(97, 123))
|
| 9468 |
+
|
| 9469 |
+
if sub_char:
|
| 9470 |
+
chars_range.append(ord(sub_char))
|
| 9471 |
+
|
| 9472 |
+
chars_range = sorted(set(chars_range))
|
| 9473 |
+
|
| 9474 |
+
return ''.join(chr(chars_range[num-chars_shift]) if 0 <= num-chars_shift < len(chars_range) else sub_char for num in ord_list)
|
| 9475 |
+
|
| 9476 |
+
###################################################################################
|
| 9477 |
+
|
| 9478 |
+
def lists_similarity(list1, list2, by_elements=True, by_sum=True):
|
| 9479 |
+
|
| 9480 |
+
if len(list1) != len(list2):
|
| 9481 |
+
return -1
|
| 9482 |
+
|
| 9483 |
+
element_ratios = []
|
| 9484 |
+
total_counts1 = sum(list1)
|
| 9485 |
+
total_counts2 = sum(list2)
|
| 9486 |
+
|
| 9487 |
+
for a, b in zip(list1, list2):
|
| 9488 |
+
if a == 0 and b == 0:
|
| 9489 |
+
element_ratios.append(1)
|
| 9490 |
+
elif a == 0 or b == 0:
|
| 9491 |
+
element_ratios.append(0)
|
| 9492 |
+
else:
|
| 9493 |
+
element_ratios.append(min(a, b) / max(a, b))
|
| 9494 |
+
|
| 9495 |
+
average_element_ratio = sum(element_ratios) / len(element_ratios)
|
| 9496 |
+
|
| 9497 |
+
total_counts_ratio = min(total_counts1, total_counts2) / max(total_counts1, total_counts2)
|
| 9498 |
+
|
| 9499 |
+
if by_elements and by_sum:
|
| 9500 |
+
return (average_element_ratio + total_counts_ratio) / 2
|
| 9501 |
+
|
| 9502 |
+
elif by_elements and not by_sum:
|
| 9503 |
+
return average_element_ratio
|
| 9504 |
+
|
| 9505 |
+
elif not by_elements and by_sum:
|
| 9506 |
+
return total_counts_ratio
|
| 9507 |
+
|
| 9508 |
+
else:
|
| 9509 |
+
return -1
|
| 9510 |
+
|
| 9511 |
+
###################################################################################
|
| 9512 |
+
|
| 9513 |
+
def find_indexes(lst, value, mode='equal', dual_mode=True):
|
| 9514 |
+
|
| 9515 |
+
indexes = []
|
| 9516 |
+
|
| 9517 |
+
if mode == 'equal' or dual_mode:
|
| 9518 |
+
indexes.extend([index for index, elem in enumerate(lst) if elem == value])
|
| 9519 |
+
|
| 9520 |
+
if mode == 'smaller':
|
| 9521 |
+
indexes.extend([index for index, elem in enumerate(lst) if elem < value])
|
| 9522 |
+
|
| 9523 |
+
if mode == 'larger':
|
| 9524 |
+
indexes.extend([index for index, elem in enumerate(lst) if elem > value])
|
| 9525 |
+
|
| 9526 |
+
return sorted(set(indexes))
|
| 9527 |
+
|
| 9528 |
+
###################################################################################
|
| 9529 |
+
|
| 9530 |
+
NUMERALS = ["one", "two", "three", "four",
|
| 9531 |
+
"five", "six", "seven", "eight",
|
| 9532 |
+
"nine", "ten", "eleven", "twelve",
|
| 9533 |
+
"thirteen", "fourteen", "fifteen", "sixteen"
|
| 9534 |
+
]
|
| 9535 |
+
|
| 9536 |
+
SEMITONES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
|
| 9537 |
+
|
| 9538 |
+
MOOD_SCALES = ['Major', 'Minor', 'Major Minor']
|
| 9539 |
+
|
| 9540 |
+
###################################################################################
|
| 9541 |
+
|
| 9542 |
+
def alpha_str(string):
|
| 9543 |
+
return re.sub(r'[^a-zA-Z ()]', '', string).strip()
|
| 9544 |
+
|
| 9545 |
+
###################################################################################
|
| 9546 |
+
|
| 9547 |
+
def escore_notes_to_text_description(escore_notes, song_name='', artist_name=''):
|
| 9548 |
+
|
| 9549 |
+
#==============================================================================
|
| 9550 |
+
|
| 9551 |
+
song_time_min = (escore_notes[-1][1] * 16) / 1000 / 60
|
| 9552 |
+
|
| 9553 |
+
if song_time_min < 1.5:
|
| 9554 |
+
song_length = 'short'
|
| 9555 |
+
|
| 9556 |
+
elif 1.5 <= song_time_min < 2.5:
|
| 9557 |
+
song_length = 'average'
|
| 9558 |
+
|
| 9559 |
+
elif song_time_min >= 2.5:
|
| 9560 |
+
song_length = 'long'
|
| 9561 |
+
|
| 9562 |
+
#==============================================================================
|
| 9563 |
+
|
| 9564 |
+
escore_times = [e[1] for e in escore_notes if e[3] != 9]
|
| 9565 |
+
|
| 9566 |
+
if len(escore_times) > 0:
|
| 9567 |
+
if len(escore_times) == len(set(escore_times)):
|
| 9568 |
+
comp_type = 'melody only'
|
| 9569 |
+
|
| 9570 |
+
elif len(escore_times) >= len(set(escore_times)) and 1 in Counter(escore_times).values():
|
| 9571 |
+
comp_type = 'melody and accompaniment'
|
| 9572 |
+
|
| 9573 |
+
elif len(escore_times) >= len(set(escore_times)) and 1 not in Counter(escore_times).values():
|
| 9574 |
+
comp_type = 'accompaniment only'
|
| 9575 |
+
|
| 9576 |
+
else:
|
| 9577 |
+
comp_type = 'mixed'
|
| 9578 |
+
|
| 9579 |
+
else:
|
| 9580 |
+
comp_type = 'drums only'
|
| 9581 |
+
|
| 9582 |
+
#==============================================================================
|
| 9583 |
+
|
| 9584 |
+
patches = sorted(set([e[6] for e in escore_notes]))
|
| 9585 |
+
|
| 9586 |
+
instruments = [alpha_str(Number2patch[p]) for p in patches if p < 128]
|
| 9587 |
+
|
| 9588 |
+
if 128 in patches:
|
| 9589 |
+
drums_present = True
|
| 9590 |
+
|
| 9591 |
+
else:
|
| 9592 |
+
drums_present = False
|
| 9593 |
+
|
| 9594 |
+
drums_pitches = [e[4] for e in escore_notes if e[3] == 9]
|
| 9595 |
+
|
| 9596 |
+
most_common_drums = [alpha_str(Notenum2percussion[p[0]]) for p in Counter(drums_pitches).most_common(3)]
|
| 9597 |
+
|
| 9598 |
+
#==============================================================================
|
| 9599 |
+
|
| 9600 |
+
pitches = [e[4] for e in escore_notes if e[3] != 9]
|
| 9601 |
+
|
| 9602 |
+
key = SEMITONES[statistics.mode(pitches) % 12]
|
| 9603 |
+
|
| 9604 |
+
#==============================================================================
|
| 9605 |
+
|
| 9606 |
+
cscore = chordify_score([1000, escore_notes])
|
| 9607 |
+
|
| 9608 |
+
tones_chords = Counter()
|
| 9609 |
+
|
| 9610 |
+
for c in cscore:
|
| 9611 |
+
if len([e for e in c if e[3] != 9]) > 1:
|
| 9612 |
+
tones_chords[tuple(sorted(set([e[4] % 12 for e in c if e[3] != 9])))] += 1
|
| 9613 |
+
|
| 9614 |
+
most_common_tones_chords = [check_and_fix_tones_chord(list(c[0])) for c in tones_chords.most_common(10)]
|
| 9615 |
+
|
| 9616 |
+
mood_scale = statistics.mode(tones_chords_to_types(most_common_tones_chords, return_chord_type_index=True)) % 3
|
| 9617 |
+
|
| 9618 |
+
mood = MOOD_SCALES[mood_scale]
|
| 9619 |
+
|
| 9620 |
+
#==============================================================================
|
| 9621 |
+
|
| 9622 |
+
escore_averages = escore_notes_averages(escore_notes, return_ptcs_and_vels=True)
|
| 9623 |
+
|
| 9624 |
+
if escore_averages[0] < 8:
|
| 9625 |
+
rythm = 'fast'
|
| 9626 |
+
|
| 9627 |
+
elif 8 <= escore_averages[0] <= 12:
|
| 9628 |
+
rythm = 'average'
|
| 9629 |
+
|
| 9630 |
+
elif escore_averages[0] > 12:
|
| 9631 |
+
rythm = 'slow'
|
| 9632 |
+
|
| 9633 |
+
if escore_averages[1] < 16:
|
| 9634 |
+
tempo = 'fast'
|
| 9635 |
+
|
| 9636 |
+
elif 16 <= escore_averages[1] <= 24:
|
| 9637 |
+
tempo = 'average'
|
| 9638 |
+
|
| 9639 |
+
elif escore_averages[1] > 24:
|
| 9640 |
+
tempo = 'slow'
|
| 9641 |
+
|
| 9642 |
+
if escore_averages[2] < 50:
|
| 9643 |
+
tone = 'bass'
|
| 9644 |
+
|
| 9645 |
+
elif 50 <= escore_averages[2] <= 70:
|
| 9646 |
+
tone = 'midrange'
|
| 9647 |
+
|
| 9648 |
+
elif escore_averages[2] > 70:
|
| 9649 |
+
tone = 'treble'
|
| 9650 |
+
|
| 9651 |
+
if escore_averages[3] < 80:
|
| 9652 |
+
dynamics = 'quiet'
|
| 9653 |
+
|
| 9654 |
+
elif 80 <= escore_averages[3] <= 100:
|
| 9655 |
+
dynamics = 'average'
|
| 9656 |
+
|
| 9657 |
+
elif escore_averages[3] > 100:
|
| 9658 |
+
dynamics = 'loud'
|
| 9659 |
+
|
| 9660 |
+
#==============================================================================
|
| 9661 |
+
|
| 9662 |
+
description = ''
|
| 9663 |
+
|
| 9664 |
+
if song_name != '':
|
| 9665 |
+
description = 'Song "' + song_name + '"'
|
| 9666 |
+
|
| 9667 |
+
if artist_name != '':
|
| 9668 |
+
description += ' by ' + artist_name
|
| 9669 |
+
|
| 9670 |
+
if song_name != '' or artist_name != '':
|
| 9671 |
+
description += '.'
|
| 9672 |
+
description += '\n'
|
| 9673 |
+
|
| 9674 |
+
description += 'The song is '
|
| 9675 |
+
|
| 9676 |
+
if song_length != 'average':
|
| 9677 |
+
description += 'a ' + song_length
|
| 9678 |
+
|
| 9679 |
+
else:
|
| 9680 |
+
description += 'an ' + song_length
|
| 9681 |
+
|
| 9682 |
+
description += ' duration '
|
| 9683 |
+
|
| 9684 |
+
description += comp_type + ' composition'
|
| 9685 |
+
|
| 9686 |
+
if comp_type != 'drums only' or comp_type != 'mixed':
|
| 9687 |
+
|
| 9688 |
+
if drums_present:
|
| 9689 |
+
description += ' with drums'
|
| 9690 |
+
|
| 9691 |
+
else:
|
| 9692 |
+
description += ' without drums'
|
| 9693 |
+
|
| 9694 |
+
if key and mood:
|
| 9695 |
+
description += ' in ' + key + ' ' + mood
|
| 9696 |
+
|
| 9697 |
+
description += '.'
|
| 9698 |
+
|
| 9699 |
+
description += '\n'
|
| 9700 |
+
|
| 9701 |
+
description += 'It has '
|
| 9702 |
+
|
| 9703 |
+
description += rythm + ' rythm, '
|
| 9704 |
+
description += tempo + ' tempo, '
|
| 9705 |
+
description += tone + ' tone and '
|
| 9706 |
+
description += dynamics + ' dynamics.'
|
| 9707 |
+
|
| 9708 |
+
description += '\n'
|
| 9709 |
+
|
| 9710 |
+
description += 'The song '
|
| 9711 |
+
|
| 9712 |
+
if len(instruments) == 1:
|
| 9713 |
+
description += 'is played on a solo ' + instruments + '.'
|
| 9714 |
+
|
| 9715 |
+
else:
|
| 9716 |
+
description += 'features ' + NUMERALS[len(instruments)-1] + ' instruments: '
|
| 9717 |
+
description += ', '.join(instruments[:-1]) + ' and ' + instruments[-1] + '.'
|
| 9718 |
+
|
| 9719 |
+
description += '\n'
|
| 9720 |
+
|
| 9721 |
+
if drums_present:
|
| 9722 |
+
description += 'The drum track has predominant '
|
| 9723 |
+
description += ', '.join(most_common_drums[:-1]) + ' and ' + most_common_drums[-1] + '.'
|
| 9724 |
+
|
| 9725 |
+
#==============================================================================
|
| 9726 |
+
|
| 9727 |
+
return description
|
| 9728 |
+
|
| 9729 |
###################################################################################
|
| 9730 |
#
|
| 9731 |
# This is the end of the TMIDI X Python module
|