freude/midi2csv.py

46 lines
1.7 KiB
Python
Executable file

#!/usr/bin/env python
import argparse
import csv
import mido
import sys
parser = argparse.ArgumentParser()
parser.add_argument("input", help="input file (midi)")
parser.add_argument(
"-o", "--output", default="/dev/stdout", help="output CSV (pitch, duration, pause)"
)
parser.add_argument("-t", "--track", default=0, type=int, help="track number")
parser.add_argument("-c", "--channel", default=0, type=int, help="channel number")
args = parser.parse_args()
octave = ["c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b"]
pitches = [f"{octave[i % 12]}{i // 12 + 3}" for i in range(36)]
midifile = mido.MidiFile(args.input)
time = 0
note = 0
time_on = 0
time_off = 0
with open(args.output, "w") as notes:
writer = csv.writer(notes)
for event in midifile.tracks[args.track]:
writer.writerow(["", "", event])
# convert time to 1/16th beats
time += event.time * 16 // midifile.ticks_per_beat
if event.type == "note_on" and event.channel == args.channel:
# if mulitple notes start at the same time, play the highest
if event.velocity != 0 and (time_on != time or note < event.note):
if time_off <= time_on:
time_off = time
if note != 0 and time_off - time_on > 0:
writer.writerow(
[pitches[note - 60], time_off - time_on, time - time_off]
)
note = event.note
if note - 60 < 0 or note - 60 >= len(pitches):
sys.exit("note out of range c3 to b5")
time_on = time
elif note == event.note:
time_off = time
writer.writerow([pitches[note - 60], time - time_on, 0])