asigalov61 commited on
Commit
140ba03
1 Parent(s): 8d69657

Upload TMIDIX.py

Browse files
Files changed (1) hide show
  1. TMIDIX.py +324 -113
TMIDIX.py CHANGED
@@ -56,6 +56,8 @@ VersionDate = '20201120'
56
 
57
  _previous_warning = '' # 5.4
58
  _previous_times = 0 # 5.4
 
 
59
  #------------------------------- Encoding stuff --------------------------
60
 
61
  def opus2midi(opus=[], text_encoding='ISO-8859-1'):
@@ -845,10 +847,11 @@ def _unshift_ber_int(ba):
845
  r'''Given a bytearray, returns a tuple of (the ber-integer at the
846
  start, and the remainder of the bytearray).
847
  '''
848
- if not len(ba): # 6.7
849
  _warn('_unshift_ber_int: no integer found')
850
  return ((0, b""))
851
- byte = ba.pop(0)
 
852
  integer = 0
853
  while True:
854
  integer += (byte & 0x7F)
@@ -857,13 +860,17 @@ start, and the remainder of the bytearray).
857
  if not len(ba):
858
  _warn('_unshift_ber_int: no end-of-integer found')
859
  return ((0, ba))
860
- byte = ba.pop(0)
 
861
  integer <<= 7
862
 
 
863
  def _clean_up_warnings(): # 5.4
864
  # Call this before returning from any publicly callable function
865
  # whenever there's a possibility that a warning might have been printed
866
  # by the function, or by any private functions it might have called.
 
 
867
  global _previous_times
868
  global _previous_warning
869
  if _previous_times > 1:
@@ -876,27 +883,32 @@ def _clean_up_warnings(): # 5.4
876
  _previous_times = 0
877
  _previous_warning = ''
878
 
 
879
  def _warn(s=''):
 
 
880
  global _previous_times
881
  global _previous_warning
882
  if s == _previous_warning: # 5.4
883
  _previous_times = _previous_times + 1
884
  else:
885
  _clean_up_warnings()
886
- sys.stderr.write(str(s)+"\n")
887
  _previous_warning = s
888
 
 
889
  def _some_text_event(which_kind=0x01, text=b'some_text', text_encoding='ISO-8859-1'):
890
- if str(type(text)).find("'str'") >= 0: # 6.4 test for back-compatibility
891
  data = bytes(text, encoding=text_encoding)
892
  else:
893
  data = bytes(text)
894
- return b'\xFF'+bytes((which_kind,))+_ber_compressed_int(len(data))+data
 
895
 
896
  def _consistentise_ticks(scores): # 3.6
897
  # used by mix_scores, merge_scores, concatenate_scores
898
  if len(scores) == 1:
899
- return copy.deepcopy(scores)
900
  are_consistent = True
901
  ticks = scores[0][0]
902
  iscore = 1
@@ -917,9 +929,8 @@ def _consistentise_ticks(scores): # 3.6
917
 
918
 
919
  ###########################################################################
920
-
921
  def _decode(trackdata=b'', exclude=None, include=None,
922
- event_callback=None, exclusive_event_callback=None, no_eot_magic=False):
923
  r'''Decodes MIDI track data into an opus-style list of events.
924
  The options:
925
  'exclude' is a list of event types which will be ignored SHOULD BE A SET
@@ -939,24 +950,24 @@ The options:
939
  exclude = set(exclude)
940
 
941
  # Pointer = 0; not used here; we eat through the bytearray instead.
942
- event_code = -1; # used for running status
943
  event_count = 0;
944
  events = []
945
 
946
- while(len(trackdata)):
947
  # loop while there's anything to analyze ...
948
- eot = False # When True, the event registrar aborts this loop
949
  event_count += 1
950
 
951
  E = []
952
  # E for events - we'll feed it to the event registrar at the end.
953
 
954
  # Slice off the delta time code, and analyze it
955
- [time, remainder] = _unshift_ber_int(trackdata)
956
 
957
  # Now let's see what we can make of the command
958
- first_byte = trackdata.pop(0) & 0xFF
959
-
960
  if (first_byte < 0xF0): # It's a MIDI event
961
  if (first_byte & 0x80):
962
  event_code = first_byte
@@ -970,17 +981,19 @@ The options:
970
  command = event_code & 0xF0
971
  channel = event_code & 0x0F
972
 
973
- if (command == 0xF6): # 0-byte argument
974
  pass
975
- elif (command == 0xC0 or command == 0xD0): # 1-byte argument
976
- parameter = trackdata.pop(0) # could be B
977
- else: # 2-byte argument could be BB or 14-bit
978
- parameter = (trackdata.pop(0), trackdata.pop(0))
 
 
979
 
980
  #################################################################
981
  # MIDI events
982
 
983
- if (command == 0x80):
984
  if 'note_off' in exclude:
985
  continue
986
  E = ['note_off', time, channel, parameter[0], parameter[1]]
@@ -991,11 +1004,11 @@ The options:
991
  elif (command == 0xA0):
992
  if 'key_after_touch' in exclude:
993
  continue
994
- E = ['key_after_touch',time,channel,parameter[0],parameter[1]]
995
  elif (command == 0xB0):
996
  if 'control_change' in exclude:
997
  continue
998
- E = ['control_change',time,channel,parameter[0],parameter[1]]
999
  elif (command == 0xC0):
1000
  if 'patch_change' in exclude:
1001
  continue
@@ -1008,93 +1021,94 @@ The options:
1008
  if 'pitch_wheel_change' in exclude:
1009
  continue
1010
  E = ['pitch_wheel_change', time, channel,
1011
- _read_14_bit(parameter)-0x2000]
1012
  else:
1013
- _warn("Shouldn't get here; command="+hex(command))
1014
 
1015
  elif (first_byte == 0xFF): # It's a Meta-Event! ##################
1016
- #[command, length, remainder] =
1017
  # unpack("xCwa*", substr(trackdata, $Pointer, 6));
1018
- #Pointer += 6 - len(remainder);
1019
  # # Move past JUST the length-encoded.
1020
- command = trackdata.pop(0) & 0xFF
 
1021
  [length, trackdata] = _unshift_ber_int(trackdata)
1022
- if (command == 0x00):
1023
- if (length == 2):
1024
- E = ['set_sequence_number',time,_twobytes2int(trackdata)]
1025
- else:
1026
- _warn('set_sequence_number: length must be 2, not '+str(length))
1027
- E = ['set_sequence_number', time, 0]
1028
-
1029
- elif command >= 0x01 and command <= 0x0f: # Text events
1030
  # 6.2 take it in bytes; let the user get the right encoding.
1031
  # text_str = trackdata[0:length].decode('ascii','ignore')
1032
  # text_str = trackdata[0:length].decode('ISO-8859-1')
1033
  # 6.4 take it in bytes; let the user get the right encoding.
1034
- text_data = bytes(trackdata[0:length]) # 6.4
1035
  # Defined text events
1036
  if (command == 0x01):
1037
- E = ['text_event', time, text_data]
1038
  elif (command == 0x02):
1039
- E = ['copyright_text_event', time, text_data]
1040
  elif (command == 0x03):
1041
- E = ['track_name', time, text_data]
1042
  elif (command == 0x04):
1043
- E = ['instrument_name', time, text_data]
1044
  elif (command == 0x05):
1045
- E = ['lyric', time, text_data]
1046
  elif (command == 0x06):
1047
- E = ['marker', time, text_data]
1048
  elif (command == 0x07):
1049
- E = ['cue_point', time, text_data]
1050
  # Reserved but apparently unassigned text events
1051
  elif (command == 0x08):
1052
- E = ['text_event_08', time, text_data]
1053
  elif (command == 0x09):
1054
- E = ['text_event_09', time, text_data]
1055
  elif (command == 0x0a):
1056
- E = ['text_event_0a', time, text_data]
1057
  elif (command == 0x0b):
1058
- E = ['text_event_0b', time, text_data]
1059
  elif (command == 0x0c):
1060
- E = ['text_event_0c', time, text_data]
1061
  elif (command == 0x0d):
1062
- E = ['text_event_0d', time, text_data]
1063
  elif (command == 0x0e):
1064
- E = ['text_event_0e', time, text_data]
1065
  elif (command == 0x0f):
1066
- E = ['text_event_0f', time, text_data]
1067
 
1068
  # Now the sticky events -------------------------------------
1069
  elif (command == 0x2F):
1070
- E = ['end_track', time]
1071
- # The code for handling this, oddly, comes LATER,
1072
- # in the event registrar.
1073
- elif (command == 0x51): # DTime, Microseconds/Crochet
1074
- if length != 3:
1075
- _warn('set_tempo event, but length='+str(length))
1076
- E = ['set_tempo', time,
1077
- struct.unpack(">I", b'\x00'+trackdata[0:3])[0]]
1078
  elif (command == 0x54):
1079
- if length != 5: # DTime, HR, MN, SE, FR, FF
1080
- _warn('smpte_offset event, but length='+str(length))
1081
- E = ['smpte_offset',time] + list(struct.unpack(">BBBBB",trackdata[0:5]))
1082
  elif (command == 0x58):
1083
- if length != 4: # DTime, NN, DD, CC, BB
1084
- _warn('time_signature event, but length='+str(length))
1085
- E = ['time_signature', time]+list(trackdata[0:4])
1086
  elif (command == 0x59):
1087
- if length != 2: # DTime, SF(signed), MI
1088
- _warn('key_signature event, but length='+str(length))
1089
- E = ['key_signature',time] + list(struct.unpack(">bB",trackdata[0:2]))
1090
- elif (command == 0x7F): # 6.4
1091
- E = ['sequencer_specific',time, bytes(trackdata[0:length])]
1092
  else:
1093
- E = ['raw_meta_event', time, command,
1094
- bytes(trackdata[0:length])] # 6.0
1095
- #"[uninterpretable meta-event command of length length]"
1096
- # DTime, Command, Binary Data
1097
- # It's uninterpretable; record it as raw_data.
1098
 
1099
  # Pointer += length; # Now move Pointer
1100
  trackdata = trackdata[length:]
@@ -1111,7 +1125,7 @@ The options:
1111
  # is omitted if this is a non-final block in a multiblock sysex;
1112
  # but the F7 (if there) is counted in the message's declared
1113
  # length, so we don't have to think about it anyway.)
1114
- #command = trackdata.pop(0)
1115
  [length, trackdata] = _unshift_ber_int(trackdata)
1116
  if first_byte == 0xF0:
1117
  # 20091008 added ISO-8859-1 to get an 8-bit str
@@ -1135,32 +1149,32 @@ The options:
1135
  # from the MIDI file spec. So, I'm going to assume that
1136
  # they CAN, in practice, occur. I don't know whether it's
1137
  # proper for you to actually emit these into a MIDI file.
1138
-
1139
- elif (first_byte == 0xF2): # DTime, Beats
1140
  # <song position msg> ::= F2 <data pair>
1141
  E = ['song_position', time, _read_14_bit(trackdata[:2])]
1142
  trackdata = trackdata[2:]
1143
 
1144
- elif (first_byte == 0xF3): # <song select msg> ::= F3 <data singlet>
1145
  # E = ['song_select', time, struct.unpack('>B',trackdata.pop(0))[0]]
1146
  E = ['song_select', time, trackdata[0]]
1147
  trackdata = trackdata[1:]
1148
  # DTime, Thing (what?! song number? whatever ...)
1149
 
1150
- elif (first_byte == 0xF6): # DTime
1151
  E = ['tune_request', time]
1152
  # What would a tune request be doing in a MIDI /file/?
1153
 
1154
- #########################################################
1155
- # ADD MORE META-EVENTS HERE. TODO:
1156
- # f1 -- MTC Quarter Frame Message. One data byte follows
1157
- # the Status; it's the time code value, from 0 to 127.
1158
- # f8 -- MIDI clock. no data.
1159
- # fa -- MIDI start. no data.
1160
- # fb -- MIDI continue. no data.
1161
- # fc -- MIDI stop. no data.
1162
- # fe -- Active sense. no data.
1163
- # f4 f5 f9 fd -- unallocated
1164
 
1165
  r'''
1166
  elif (first_byte > 0xF0) { # Some unknown kinda F-series event ####
@@ -1175,31 +1189,30 @@ The options:
1175
  elif first_byte > 0xF0: # Some unknown F-series event
1176
  # Here we only produce a one-byte piece of raw data.
1177
  # E = ['raw_data', time, bytest(trackdata[0])] # 6.4
1178
- E = ['raw_data', time, trackdata[0]] # 6.4 6.7
1179
  trackdata = trackdata[1:]
1180
  else: # Fallthru.
1181
- _warn("Aborting track. Command-byte first_byte="+hex(first_byte))
1182
  break
1183
  # End of the big if-group
1184
 
1185
-
1186
  ######################################################################
1187
  # THE EVENT REGISTRAR...
1188
- if E and (E[0] == 'end_track'):
1189
  # This is the code for exceptional handling of the EOT event.
1190
  eot = True
1191
  if not no_eot_magic:
1192
  if E[1] > 0: # a null text-event to carry the delta-time
1193
  E = ['text_event', E[1], '']
1194
  else:
1195
- E = [] # EOT with a delta-time of 0; ignore it.
1196
-
1197
  if E and not (E[0] in exclude):
1198
- #if ( $exclusive_event_callback ):
1199
  # &{ $exclusive_event_callback }( @E );
1200
- #else:
1201
  # &{ $event_callback }( @E ) if $event_callback;
1202
- events.append(E)
1203
  if eot:
1204
  break
1205
 
@@ -1819,6 +1832,7 @@ def plot_ms_SONG(ms_song,
1819
  plt.close()
1820
 
1821
  if return_plt:
 
1822
  return fig
1823
 
1824
  plt.show()
@@ -4595,12 +4609,18 @@ def ascii_text_words_counter(ascii_text):
4595
 
4596
  ###################################################################################
4597
 
4598
- def check_and_fix_tones_chord(tones_chord):
4599
 
4600
  tones_chord_combs = [list(comb) for i in range(len(tones_chord), 0, -1) for comb in combinations(tones_chord, i)]
4601
 
 
 
 
 
 
 
4602
  for c in tones_chord_combs:
4603
- if c in ALL_CHORDS_FULL:
4604
  checked_tones_chord = c
4605
  break
4606
 
@@ -4613,12 +4633,18 @@ def find_closest_tone(tones, tone):
4613
 
4614
  ###################################################################################
4615
 
4616
- def advanced_check_and_fix_tones_chord(tones_chord, high_pitch=0):
4617
 
4618
  tones_chord_combs = [list(comb) for i in range(len(tones_chord), 0, -1) for comb in combinations(tones_chord, i)]
4619
 
 
 
 
 
 
 
4620
  for c in tones_chord_combs:
4621
- if c in ALL_CHORDS_FULL:
4622
  tchord = c
4623
 
4624
  if 0 < high_pitch < 128 and len(tchord) == 1:
@@ -4664,7 +4690,7 @@ def augment_enhanced_score_notes(enhanced_score_notes,
4664
  pitch_shift=0,
4665
  ceil_timings=False,
4666
  round_timings=False,
4667
- legacy_timings=False
4668
  ):
4669
 
4670
  esn = copy.deepcopy(enhanced_score_notes)
@@ -7857,19 +7883,21 @@ def solo_piano_escore_notes(escore_notes,
7857
  chord = []
7858
 
7859
  for cc in c:
7860
- if cc[pitches_index] not in seen:
7861
 
7862
- if cc[channels_index] != 9:
 
 
7863
  cc[channels_index] = 0
7864
  cc[patches_index] = 0
7865
-
7866
  chord.append(cc)
7867
  seen.append(cc[pitches_index])
7868
-
7869
- else:
7870
- if keep_drums:
 
7871
  chord.append(cc)
7872
- seen.append(cc[pitches_index])
7873
 
7874
  sp_escore_notes.append(chord)
7875
 
@@ -9045,7 +9073,190 @@ def escore_notes_lrno_pattern_fast(escore_notes,
9045
  else:
9046
  return None
9047
 
9048
- ###################################################################################
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9049
  #
9050
  # This is the end of the TMIDI X Python module
9051
  #
 
56
 
57
  _previous_warning = '' # 5.4
58
  _previous_times = 0 # 5.4
59
+ _no_warning = False
60
+
61
  #------------------------------- Encoding stuff --------------------------
62
 
63
  def opus2midi(opus=[], text_encoding='ISO-8859-1'):
 
847
  r'''Given a bytearray, returns a tuple of (the ber-integer at the
848
  start, and the remainder of the bytearray).
849
  '''
850
+ if not len(ba): # 6.7
851
  _warn('_unshift_ber_int: no integer found')
852
  return ((0, b""))
853
+ byte = ba[0]
854
+ ba = ba[1:]
855
  integer = 0
856
  while True:
857
  integer += (byte & 0x7F)
 
860
  if not len(ba):
861
  _warn('_unshift_ber_int: no end-of-integer found')
862
  return ((0, ba))
863
+ byte = ba[0]
864
+ ba = ba[1:]
865
  integer <<= 7
866
 
867
+
868
  def _clean_up_warnings(): # 5.4
869
  # Call this before returning from any publicly callable function
870
  # whenever there's a possibility that a warning might have been printed
871
  # by the function, or by any private functions it might have called.
872
+ if _no_warning:
873
+ return
874
  global _previous_times
875
  global _previous_warning
876
  if _previous_times > 1:
 
883
  _previous_times = 0
884
  _previous_warning = ''
885
 
886
+
887
  def _warn(s=''):
888
+ if _no_warning:
889
+ return
890
  global _previous_times
891
  global _previous_warning
892
  if s == _previous_warning: # 5.4
893
  _previous_times = _previous_times + 1
894
  else:
895
  _clean_up_warnings()
896
+ sys.stderr.write(str(s) + "\n")
897
  _previous_warning = s
898
 
899
+
900
  def _some_text_event(which_kind=0x01, text=b'some_text', text_encoding='ISO-8859-1'):
901
+ if str(type(text)).find("'str'") >= 0: # 6.4 test for back-compatibility
902
  data = bytes(text, encoding=text_encoding)
903
  else:
904
  data = bytes(text)
905
+ return b'\xFF' + bytes((which_kind,)) + _ber_compressed_int(len(data)) + data
906
+
907
 
908
  def _consistentise_ticks(scores): # 3.6
909
  # used by mix_scores, merge_scores, concatenate_scores
910
  if len(scores) == 1:
911
+ return copy.deepcopy(scores)
912
  are_consistent = True
913
  ticks = scores[0][0]
914
  iscore = 1
 
929
 
930
 
931
  ###########################################################################
 
932
  def _decode(trackdata=b'', exclude=None, include=None,
933
+ event_callback=None, exclusive_event_callback=None, no_eot_magic=False):
934
  r'''Decodes MIDI track data into an opus-style list of events.
935
  The options:
936
  'exclude' is a list of event types which will be ignored SHOULD BE A SET
 
950
  exclude = set(exclude)
951
 
952
  # Pointer = 0; not used here; we eat through the bytearray instead.
953
+ event_code = -1; # used for running status
954
  event_count = 0;
955
  events = []
956
 
957
+ while (len(trackdata)):
958
  # loop while there's anything to analyze ...
959
+ eot = False # When True, the event registrar aborts this loop
960
  event_count += 1
961
 
962
  E = []
963
  # E for events - we'll feed it to the event registrar at the end.
964
 
965
  # Slice off the delta time code, and analyze it
966
+ [time, trackdata] = _unshift_ber_int(trackdata)
967
 
968
  # Now let's see what we can make of the command
969
+ first_byte = trackdata[0] & 0xFF
970
+ trackdata = trackdata[1:]
971
  if (first_byte < 0xF0): # It's a MIDI event
972
  if (first_byte & 0x80):
973
  event_code = first_byte
 
981
  command = event_code & 0xF0
982
  channel = event_code & 0x0F
983
 
984
+ if (command == 0xF6): # 0-byte argument
985
  pass
986
+ elif (command == 0xC0 or command == 0xD0): # 1-byte argument
987
+ parameter = trackdata[0] # could be B
988
+ trackdata = trackdata[1:]
989
+ else: # 2-byte argument could be BB or 14-bit
990
+ parameter = (trackdata[0], trackdata[1])
991
+ trackdata = trackdata[2:]
992
 
993
  #################################################################
994
  # MIDI events
995
 
996
+ if (command == 0x80):
997
  if 'note_off' in exclude:
998
  continue
999
  E = ['note_off', time, channel, parameter[0], parameter[1]]
 
1004
  elif (command == 0xA0):
1005
  if 'key_after_touch' in exclude:
1006
  continue
1007
+ E = ['key_after_touch', time, channel, parameter[0], parameter[1]]
1008
  elif (command == 0xB0):
1009
  if 'control_change' in exclude:
1010
  continue
1011
+ E = ['control_change', time, channel, parameter[0], parameter[1]]
1012
  elif (command == 0xC0):
1013
  if 'patch_change' in exclude:
1014
  continue
 
1021
  if 'pitch_wheel_change' in exclude:
1022
  continue
1023
  E = ['pitch_wheel_change', time, channel,
1024
+ _read_14_bit(parameter) - 0x2000]
1025
  else:
1026
+ _warn("Shouldn't get here; command=" + hex(command))
1027
 
1028
  elif (first_byte == 0xFF): # It's a Meta-Event! ##################
1029
+ # [command, length, remainder] =
1030
  # unpack("xCwa*", substr(trackdata, $Pointer, 6));
1031
+ # Pointer += 6 - len(remainder);
1032
  # # Move past JUST the length-encoded.
1033
+ command = trackdata[0] & 0xFF
1034
+ trackdata = trackdata[1:]
1035
  [length, trackdata] = _unshift_ber_int(trackdata)
1036
+ if (command == 0x00):
1037
+ if (length == 2):
1038
+ E = ['set_sequence_number', time, _twobytes2int(trackdata)]
1039
+ else:
1040
+ _warn('set_sequence_number: length must be 2, not ' + str(length))
1041
+ E = ['set_sequence_number', time, 0]
1042
+
1043
+ elif command >= 0x01 and command <= 0x0f: # Text events
1044
  # 6.2 take it in bytes; let the user get the right encoding.
1045
  # text_str = trackdata[0:length].decode('ascii','ignore')
1046
  # text_str = trackdata[0:length].decode('ISO-8859-1')
1047
  # 6.4 take it in bytes; let the user get the right encoding.
1048
+ text_data = bytes(trackdata[0:length]) # 6.4
1049
  # Defined text events
1050
  if (command == 0x01):
1051
+ E = ['text_event', time, text_data]
1052
  elif (command == 0x02):
1053
+ E = ['copyright_text_event', time, text_data]
1054
  elif (command == 0x03):
1055
+ E = ['track_name', time, text_data]
1056
  elif (command == 0x04):
1057
+ E = ['instrument_name', time, text_data]
1058
  elif (command == 0x05):
1059
+ E = ['lyric', time, text_data]
1060
  elif (command == 0x06):
1061
+ E = ['marker', time, text_data]
1062
  elif (command == 0x07):
1063
+ E = ['cue_point', time, text_data]
1064
  # Reserved but apparently unassigned text events
1065
  elif (command == 0x08):
1066
+ E = ['text_event_08', time, text_data]
1067
  elif (command == 0x09):
1068
+ E = ['text_event_09', time, text_data]
1069
  elif (command == 0x0a):
1070
+ E = ['text_event_0a', time, text_data]
1071
  elif (command == 0x0b):
1072
+ E = ['text_event_0b', time, text_data]
1073
  elif (command == 0x0c):
1074
+ E = ['text_event_0c', time, text_data]
1075
  elif (command == 0x0d):
1076
+ E = ['text_event_0d', time, text_data]
1077
  elif (command == 0x0e):
1078
+ E = ['text_event_0e', time, text_data]
1079
  elif (command == 0x0f):
1080
+ E = ['text_event_0f', time, text_data]
1081
 
1082
  # Now the sticky events -------------------------------------
1083
  elif (command == 0x2F):
1084
+ E = ['end_track', time]
1085
+ # The code for handling this, oddly, comes LATER,
1086
+ # in the event registrar.
1087
+ elif (command == 0x51): # DTime, Microseconds/Crochet
1088
+ if length != 3:
1089
+ _warn('set_tempo event, but length=' + str(length))
1090
+ E = ['set_tempo', time,
1091
+ struct.unpack(">I", b'\x00' + trackdata[0:3])[0]]
1092
  elif (command == 0x54):
1093
+ if length != 5: # DTime, HR, MN, SE, FR, FF
1094
+ _warn('smpte_offset event, but length=' + str(length))
1095
+ E = ['smpte_offset', time] + list(struct.unpack(">BBBBB", trackdata[0:5]))
1096
  elif (command == 0x58):
1097
+ if length != 4: # DTime, NN, DD, CC, BB
1098
+ _warn('time_signature event, but length=' + str(length))
1099
+ E = ['time_signature', time] + list(trackdata[0:4])
1100
  elif (command == 0x59):
1101
+ if length != 2: # DTime, SF(signed), MI
1102
+ _warn('key_signature event, but length=' + str(length))
1103
+ E = ['key_signature', time] + list(struct.unpack(">bB", trackdata[0:2]))
1104
+ elif (command == 0x7F): # 6.4
1105
+ E = ['sequencer_specific', time, bytes(trackdata[0:length])]
1106
  else:
1107
+ E = ['raw_meta_event', time, command,
1108
+ bytes(trackdata[0:length])] # 6.0
1109
+ # "[uninterpretable meta-event command of length length]"
1110
+ # DTime, Command, Binary Data
1111
+ # It's uninterpretable; record it as raw_data.
1112
 
1113
  # Pointer += length; # Now move Pointer
1114
  trackdata = trackdata[length:]
 
1125
  # is omitted if this is a non-final block in a multiblock sysex;
1126
  # but the F7 (if there) is counted in the message's declared
1127
  # length, so we don't have to think about it anyway.)
1128
+ # command = trackdata.pop(0)
1129
  [length, trackdata] = _unshift_ber_int(trackdata)
1130
  if first_byte == 0xF0:
1131
  # 20091008 added ISO-8859-1 to get an 8-bit str
 
1149
  # from the MIDI file spec. So, I'm going to assume that
1150
  # they CAN, in practice, occur. I don't know whether it's
1151
  # proper for you to actually emit these into a MIDI file.
1152
+
1153
+ elif (first_byte == 0xF2): # DTime, Beats
1154
  # <song position msg> ::= F2 <data pair>
1155
  E = ['song_position', time, _read_14_bit(trackdata[:2])]
1156
  trackdata = trackdata[2:]
1157
 
1158
+ elif (first_byte == 0xF3): # <song select msg> ::= F3 <data singlet>
1159
  # E = ['song_select', time, struct.unpack('>B',trackdata.pop(0))[0]]
1160
  E = ['song_select', time, trackdata[0]]
1161
  trackdata = trackdata[1:]
1162
  # DTime, Thing (what?! song number? whatever ...)
1163
 
1164
+ elif (first_byte == 0xF6): # DTime
1165
  E = ['tune_request', time]
1166
  # What would a tune request be doing in a MIDI /file/?
1167
 
1168
+ #########################################################
1169
+ # ADD MORE META-EVENTS HERE. TODO:
1170
+ # f1 -- MTC Quarter Frame Message. One data byte follows
1171
+ # the Status; it's the time code value, from 0 to 127.
1172
+ # f8 -- MIDI clock. no data.
1173
+ # fa -- MIDI start. no data.
1174
+ # fb -- MIDI continue. no data.
1175
+ # fc -- MIDI stop. no data.
1176
+ # fe -- Active sense. no data.
1177
+ # f4 f5 f9 fd -- unallocated
1178
 
1179
  r'''
1180
  elif (first_byte > 0xF0) { # Some unknown kinda F-series event ####
 
1189
  elif first_byte > 0xF0: # Some unknown F-series event
1190
  # Here we only produce a one-byte piece of raw data.
1191
  # E = ['raw_data', time, bytest(trackdata[0])] # 6.4
1192
+ E = ['raw_data', time, trackdata[0]] # 6.4 6.7
1193
  trackdata = trackdata[1:]
1194
  else: # Fallthru.
1195
+ _warn("Aborting track. Command-byte first_byte=" + hex(first_byte))
1196
  break
1197
  # End of the big if-group
1198
 
 
1199
  ######################################################################
1200
  # THE EVENT REGISTRAR...
1201
+ if E and (E[0] == 'end_track'):
1202
  # This is the code for exceptional handling of the EOT event.
1203
  eot = True
1204
  if not no_eot_magic:
1205
  if E[1] > 0: # a null text-event to carry the delta-time
1206
  E = ['text_event', E[1], '']
1207
  else:
1208
+ E = [] # EOT with a delta-time of 0; ignore it.
1209
+
1210
  if E and not (E[0] in exclude):
1211
+ # if ( $exclusive_event_callback ):
1212
  # &{ $exclusive_event_callback }( @E );
1213
+ # else:
1214
  # &{ $event_callback }( @E ) if $event_callback;
1215
+ events.append(E)
1216
  if eot:
1217
  break
1218
 
 
1832
  plt.close()
1833
 
1834
  if return_plt:
1835
+ plt.close(fig)
1836
  return fig
1837
 
1838
  plt.show()
 
4609
 
4610
  ###################################################################################
4611
 
4612
+ def check_and_fix_tones_chord(tones_chord, use_full_chords=True):
4613
 
4614
  tones_chord_combs = [list(comb) for i in range(len(tones_chord), 0, -1) for comb in combinations(tones_chord, i)]
4615
 
4616
+ if use_full_chords:
4617
+ CHORDS = ALL_CHORDS_FULL
4618
+
4619
+ else:
4620
+ CHORDS = ALL_CHORDS_SORTED
4621
+
4622
  for c in tones_chord_combs:
4623
+ if c in CHORDS:
4624
  checked_tones_chord = c
4625
  break
4626
 
 
4633
 
4634
  ###################################################################################
4635
 
4636
+ def advanced_check_and_fix_tones_chord(tones_chord, high_pitch=0, use_full_chords=True):
4637
 
4638
  tones_chord_combs = [list(comb) for i in range(len(tones_chord), 0, -1) for comb in combinations(tones_chord, i)]
4639
 
4640
+ if use_full_chords:
4641
+ CHORDS = ALL_CHORDS_FULL
4642
+
4643
+ else:
4644
+ CHORDS = ALL_CHORDS_SORTED
4645
+
4646
  for c in tones_chord_combs:
4647
+ if c in CHORDS:
4648
  tchord = c
4649
 
4650
  if 0 < high_pitch < 128 and len(tchord) == 1:
 
4690
  pitch_shift=0,
4691
  ceil_timings=False,
4692
  round_timings=False,
4693
+ legacy_timings=True
4694
  ):
4695
 
4696
  esn = copy.deepcopy(enhanced_score_notes)
 
7883
  chord = []
7884
 
7885
  for cc in c:
 
7886
 
7887
+ if cc[channels_index] != 9:
7888
+ if cc[pitches_index] not in seen:
7889
+
7890
  cc[channels_index] = 0
7891
  cc[patches_index] = 0
7892
+
7893
  chord.append(cc)
7894
  seen.append(cc[pitches_index])
7895
+
7896
+ else:
7897
+ if keep_drums:
7898
+ if cc[pitches_index]+128 not in seen:
7899
  chord.append(cc)
7900
+ seen.append(cc[pitches_index]+128)
7901
 
7902
  sp_escore_notes.append(chord)
7903
 
 
9073
  else:
9074
  return None
9075
 
9076
+ ###################################################################################
9077
+
9078
+ def escore_notes_durations_counter(escore_notes,
9079
+ min_duration=0,
9080
+ durations_index=2,
9081
+ channels_index=3
9082
+ ):
9083
+
9084
+ escore = [e for e in escore_notes if e[channels_index] != 9]
9085
+ durs = [e[durations_index] for e in escore if e[durations_index] >= min_duration]
9086
+ zero_durs = sum([1 for e in escore if e[durations_index] == 0])
9087
+
9088
+ return [len(durs), len(escore), zero_durs, Counter(durs).most_common()]
9089
+
9090
+ ###################################################################################
9091
+
9092
+ def count_bad_chords_in_chordified_score(chordified_score,
9093
+ pitches_index=4,
9094
+ patches_index=6,
9095
+ max_patch=127,
9096
+ use_full_chords=False
9097
+ ):
9098
+
9099
+ if use_full_chords:
9100
+ CHORDS = ALL_CHORDS_FULL
9101
+
9102
+ else:
9103
+ CHORDS = ALL_CHORDS_SORTED
9104
+
9105
+ bad_chords_count = 0
9106
+
9107
+ for c in chordified_score:
9108
+
9109
+ cpitches = [e[pitches_index] for e in c if e[patches_index] <= max_patch]
9110
+ tones_chord = sorted(set([p % 12 for p in cpitches]))
9111
+
9112
+ if tones_chord:
9113
+ if tones_chord not in CHORDS:
9114
+ bad_chords_count += 1
9115
+
9116
+ return [bad_chords_count, len(chordified_score)]
9117
+
9118
+ ###################################################################################
9119
+
9120
+ def needleman_wunsch_aligner(seq1,
9121
+ seq2,
9122
+ align_idx,
9123
+ gap_penalty=-1,
9124
+ match_score=2,
9125
+ mismatch_penalty=-1
9126
+ ):
9127
+
9128
+ n = len(seq1)
9129
+ m = len(seq2)
9130
+
9131
+ score_matrix = [[0] * (m + 1) for _ in range(n + 1)]
9132
+
9133
+ for i in range(1, n + 1):
9134
+ score_matrix[i][0] = gap_penalty * i
9135
+ for j in range(1, m + 1):
9136
+ score_matrix[0][j] = gap_penalty * j
9137
+
9138
+ for i in range(1, n + 1):
9139
+ for j in range(1, m + 1):
9140
+ match = score_matrix[i-1][j-1] + (match_score if seq1[i-1][align_idx] == seq2[j-1][align_idx] else mismatch_penalty)
9141
+ delete = score_matrix[i-1][j] + gap_penalty
9142
+ insert = score_matrix[i][j-1] + gap_penalty
9143
+ score_matrix[i][j] = max(match, delete, insert)
9144
+
9145
+ align1, align2 = [], []
9146
+ i, j = n, m
9147
+
9148
+ while i > 0 and j > 0:
9149
+
9150
+ score = score_matrix[i][j]
9151
+ score_diag = score_matrix[i-1][j-1]
9152
+ score_up = score_matrix[i-1][j]
9153
+ score_left = score_matrix[i][j-1]
9154
+
9155
+ if score == score_diag + (match_score if seq1[i-1][align_idx] == seq2[j-1][align_idx] else mismatch_penalty):
9156
+ align1.append(seq1[i-1])
9157
+ align2.append(seq2[j-1])
9158
+ i -= 1
9159
+ j -= 1
9160
+ elif score == score_up + gap_penalty:
9161
+ align1.append(seq1[i-1])
9162
+ align2.append([None] * 6)
9163
+ i -= 1
9164
+ elif score == score_left + gap_penalty:
9165
+ align1.append([None] * 6)
9166
+ align2.append(seq2[j-1])
9167
+ j -= 1
9168
+
9169
+ while i > 0:
9170
+ align1.append(seq1[i-1])
9171
+ align2.append([None] * 6)
9172
+ i -= 1
9173
+ while j > 0:
9174
+ align1.append([None] * 6)
9175
+ align2.append(seq2[j-1])
9176
+ j -= 1
9177
+
9178
+ align1.reverse()
9179
+ align2.reverse()
9180
+
9181
+ return align1, align2
9182
+
9183
+ ###################################################################################
9184
+
9185
+ def align_escore_notes_to_escore_notes(src_escore_notes,
9186
+ trg_escore_notes,
9187
+ recalculate_scores_timings=True,
9188
+ pitches_idx=4
9189
+ ):
9190
+
9191
+ if recalculate_scores_timings:
9192
+ src_escore_notes = recalculate_score_timings(src_escore_notes)
9193
+ trg_escore_notes = recalculate_score_timings(trg_escore_notes)
9194
+
9195
+ src_align1, trg_align2 = needleman_wunsch_aligner(src_escore_notes, trg_escore_notes, pitches_idx)
9196
+
9197
+ aligned_scores = [[al[0], al[1]] for al in zip(src_align1, trg_align2) if al[0][0] is not None and al[1][0] is not None]
9198
+
9199
+ return aligned_scores
9200
+
9201
+ ###################################################################################
9202
+
9203
+ def t_to_n(arr, si, t):
9204
+
9205
+ ct = 0
9206
+ ci = si
9207
+
9208
+ while ct + arr[ci][1] < t and ci < len(arr)-1:
9209
+ ct += arr[ci][1]
9210
+ ci += 1
9211
+
9212
+ return ci+1
9213
+
9214
+ ###################################################################################
9215
+
9216
+ def max_sum_chunk_idxs(arr, t=255):
9217
+
9218
+ n = t_to_n(arr, 0, t)
9219
+
9220
+ if n > len(arr):
9221
+ return [0, n]
9222
+
9223
+ max_sum = 0
9224
+ max_sum_start_index = 0
9225
+
9226
+ max_sum_start_idxs = [0, len(arr), sum([a[0] for a in arr])]
9227
+
9228
+ for i in range(len(arr)):
9229
+
9230
+ n = t_to_n(arr, i, t)
9231
+
9232
+ current_sum = sum([a[0] for a in arr[i:n]])
9233
+ current_time = sum([a[1] for a in arr[i:n]])
9234
+
9235
+ if current_sum > max_sum and current_time <= t:
9236
+ max_sum = current_sum
9237
+ max_sum_start_idxs = [i, n, max_sum]
9238
+
9239
+ return max_sum_start_idxs
9240
+
9241
+ ###################################################################################
9242
+
9243
+ def find_highest_density_escore_notes_chunk(escore_notes, max_chunk_time=512):
9244
+
9245
+ dscore = delta_score_notes(escore_notes)
9246
+
9247
+ cscore = chordify_score([d[1:] for d in dscore])
9248
+
9249
+ notes_counts = [[len(c), c[0][0]] for c in cscore]
9250
+
9251
+ msc_idxs = max_sum_chunk_idxs(notes_counts, max_chunk_time)
9252
+
9253
+ chunk_dscore = [['note'] + c for c in flatten(cscore[msc_idxs[0]:msc_idxs[1]])]
9254
+
9255
+ chunk_escore = recalculate_score_timings(delta_score_to_abs_score(chunk_dscore))
9256
+
9257
+ return chunk_escore
9258
+
9259
+ ###################################################################################
9260
  #
9261
  # This is the end of the TMIDI X Python module
9262
  #