100 lines
2.7 KiB
Python
100 lines
2.7 KiB
Python
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__() |