asigalov61 commited on
Commit
0ac918e
·
verified ·
1 Parent(s): f2bdfe6

Upload TMIDIX.py

Browse files
Files changed (1) hide show
  1. TMIDIX.py +355 -0
TMIDIX.py CHANGED
@@ -9381,6 +9381,361 @@ 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
+ comp_type = ''
9567
+
9568
+ if len(escore_times) > 0:
9569
+ if len(escore_times) == len(set(escore_times)):
9570
+ comp_type = 'melody only'
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 only'
9577
+
9578
+ else:
9579
+ comp_type = 'drums only'
9580
+
9581
+ #==============================================================================
9582
+
9583
+ patches = sorted(set([e[6] for e in escore_notes]))
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
+
9590
+ else:
9591
+ drums_present = False
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
+
9599
+ pitches = [e[4] for e in escore_notes if e[3] != 9]
9600
+
9601
+ key = ''
9602
+
9603
+ if pitches:
9604
+ key = SEMITONES[statistics.mode(pitches) % 12]
9605
+
9606
+ #==============================================================================
9607
+
9608
+ mood = ''
9609
+
9610
+ if pitches:
9611
+
9612
+ cscore = chordify_score([1000, escore_notes])
9613
+
9614
+ tones_chords = Counter()
9615
+
9616
+ for c in cscore:
9617
+ if len([e for e in c if e[3] != 9]) > 0:
9618
+ tones_chords[tuple(sorted(set([e[4] % 12 for e in c if e[3] != 9])))] += 1
9619
+
9620
+ most_common_tones_chords = [check_and_fix_tones_chord(list(c[0])) for c in tones_chords.most_common(10)]
9621
+
9622
+ mood_scale = statistics.mode(tones_chords_to_types(most_common_tones_chords, return_chord_type_index=True)) % 3
9623
+
9624
+ mood = MOOD_SCALES[mood_scale]
9625
+
9626
+ #==============================================================================
9627
+
9628
+ if pitches:
9629
+
9630
+ escore_averages = escore_notes_averages(escore_notes, return_ptcs_and_vels=True)
9631
+
9632
+ if escore_averages[0] < 8:
9633
+ rythm = 'fast'
9634
+
9635
+ elif 8 <= escore_averages[0] <= 12:
9636
+ rythm = 'average'
9637
+
9638
+ elif escore_averages[0] > 12:
9639
+ rythm = 'slow'
9640
+
9641
+ if escore_averages[1] < 16:
9642
+ tempo = 'fast'
9643
+
9644
+ elif 16 <= escore_averages[1] <= 24:
9645
+ tempo = 'average'
9646
+
9647
+ elif escore_averages[1] > 24:
9648
+ tempo = 'slow'
9649
+
9650
+ if escore_averages[2] < 50:
9651
+ tone = 'bass'
9652
+
9653
+ elif 50 <= escore_averages[2] <= 70:
9654
+ tone = 'midrange'
9655
+
9656
+ elif escore_averages[2] > 70:
9657
+ tone = 'treble'
9658
+
9659
+ if escore_averages[3] < 80:
9660
+ dynamics = 'quiet'
9661
+
9662
+ elif 80 <= escore_averages[3] <= 100:
9663
+ dynamics = 'average'
9664
+
9665
+ elif escore_averages[3] > 100:
9666
+ dynamics = 'loud'
9667
+
9668
+ #==============================================================================
9669
+
9670
+ description = ''
9671
+
9672
+ if song_name != '':
9673
+ description = 'Song "' + song_name + '"'
9674
+
9675
+ if artist_name != '':
9676
+ description += ' by ' + artist_name
9677
+
9678
+ if song_name != '' or artist_name != '':
9679
+ description += '.'
9680
+ description += '\n'
9681
+
9682
+ description += 'The song is '
9683
+
9684
+ if song_length != 'average':
9685
+ description += 'a ' + song_length
9686
+
9687
+ else:
9688
+ description += 'an ' + song_length
9689
+
9690
+ description += ' duration '
9691
+
9692
+ description += comp_type + ' composition'
9693
+
9694
+ if comp_type != 'drums only':
9695
+
9696
+ if drums_present:
9697
+ description += ' with drums'
9698
+
9699
+ else:
9700
+ description += ' without drums'
9701
+
9702
+ if key and mood:
9703
+ description += ' in ' + key + ' ' + mood
9704
+
9705
+ description += '.'
9706
+
9707
+ description += '\n'
9708
+
9709
+ if pitches:
9710
+
9711
+ description += 'It has '
9712
+
9713
+ description += rythm + ' rythm, '
9714
+ description += tempo + ' tempo, '
9715
+ description += tone + ' tone and '
9716
+ description += dynamics + ' dynamics.'
9717
+
9718
+ description += '\n'
9719
+
9720
+ description += 'The song '
9721
+
9722
+ if len(instruments) == 1:
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
+ if drums_present:
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