mscz2video/src/mscz_to_mp3.py
2023-12-31 15:05:04 +01:00

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__()