import music21 import subprocess import sys import os MSCORE="mscore" REMOVE_MID_FILES=False def get_elements(stream, classe): elements = [] for el in stream[classe]: offset = el.activeSite.getOffsetBySite(stream.parts[0]) + el.getOffsetBySite(el.activeSite) elements.append((offset, el)) return elements def add_elements(stream, elements): st_elements = [(offset, el.number) for (offset, el) in get_elements(stream, 'MetronomeMark')] #print(st_elements) for offset, el in elements: if (offset, el.number) not in st_elements: stream.insert(offset, el) #print(f"Inserting {el}@{offset}") return stream def separate_instruments(input_midi_path, output_folder): # Load MIDI file stream = music21.converter.parse(input_midi_path) outputs = [] elements = get_elements(stream, 'MetronomeMark') #print(elements) # Extract each part (music21.instrument) and create a separate MIDI file for each for i, part in enumerate(stream.parts): part.makeRests(fillGaps=True, inPlace=True) part.makeMeasures(inPlace=True) part.makeTies(inPlace=True) # Create a new music21.stream for each part instrument_stream = music21.stream.Score() instrument_stream.append(part) instrument_stream = add_elements(instrument_stream, elements) # Create a new MIDI file for each music21.instrument output_path = f"{output_folder}/instrument_{i + 1}.mid" instrument_stream.write('midi', fp=output_path) outputs.append(output_path) return outputs def change_instrument(input, output): s = music21.converter.parse(input) for el in s.recurse(): if 'Instrument' in el.classes: # or 'Piano' el.activeSite.replace(el, music21.instrument.Piano()) s.write('midi', output) def basename(name): return '.'.join(name.split('/')[-1].split('.')[:-1]) def create_audios(files, dest="out"): if len(files) == 0: return for el in files: subprocess.call(["mscore", el, "-o", os.path.join(dest, basename(el))+".mp3"]) print(f"Converted {basename(el)}.mp3") def __main__(): SCORE=sys.argv[1] OUT=sys.argv[2] os.makedirs(OUT, exist_ok=True) # Create midi file subprocess.call([MSCORE, SCORE, "-o", f"{OUT}/{basename(SCORE)}.mid"]) midi_files = separate_instruments(f"{OUT}/{basename(SCORE)}.mid", OUT) for file in midi_files: change_instrument(file, file) print("=== Creating audios ===") #create_audios(midi_files, OUT) if REMOVE_MID_FILES: os.remove(f"{OUT}/{basename(SCORE)}.mid") for file in midi_files: os.remove(file) if __name__ == "__main__": __main__()