asigalov61 commited on
Commit
8cad869
·
verified ·
1 Parent(s): 8b5344f

Upload TMIDIX.py

Browse files
Files changed (1) hide show
  1. TMIDIX.py +345 -0
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