Skip to content

Instantly share code, notes, and snippets.

@sumpygump
Created March 18, 2024 12:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sumpygump/de33e8242569499679a6b57b8869bf41 to your computer and use it in GitHub Desktop.
Save sumpygump/de33e8242569499679a6b57b8869bf41 to your computer and use it in GitHub Desktop.
Merge midi channels
"""Merge midi data"""
import argparse
import csv
import glob
import os
import subprocess
import sys
POS_TRACK = 0
POS_TIME = 1
POS_TYPE = 2
POS_CHANNEL = 3
POS_NOTE = 4
POS_VELOCITY = 5
POS_PROGRAM = 4
def collect_filenames(path):
"""Collect filenames from a path that may be a directory"""
if os.path.isdir(path):
files = glob.glob(f"{path}/*.mid")
return files
return [path]
def merge_midi(path, mode="single_channel"):
"""Merge midi channel/track data"""
all_files = collect_filenames(path)
for filename in all_files:
print(filename, end="")
csv_filename = f"{filename}.csv"
cmd = ["midicsv", filename, csv_filename]
subprocess.run(cmd, check=False)
data = read_csv(csv_filename)
for event in data:
if event[POS_TYPE] in ["Note_on_c", "Note_off_c"]:
event[POS_CHANNEL] = 0
elif event[POS_TYPE] in ["Program_c"]:
event[POS_CHANNEL] = 0
event[POS_PROGRAM] = 1 # Force to piano
write_csv(data, csv_filename)
out_filename = filename.replace(".mid", "_single_channel.mid")
cmd = ["csvmidi", csv_filename, out_filename]
subprocess.run(cmd, check=False)
print(" > Wrote to file", out_filename)
os.unlink(csv_filename)
def read_csv(filename):
"""Read midi csv file"""
events = []
with open(filename, encoding="ISO-8859-1", newline="") as csvfile:
reader = csv.reader(csvfile, quotechar='"', skipinitialspace=True)
for row in reader:
events.append(row)
return events
def write_csv(data, filename):
"""Write midi csv file"""
with open(filename, "w", encoding="ISO-8859-1", newline="\n") as csvfile:
writer = csv.writer(csvfile)
for row in data:
writer.writerow(row)
return filename
if __name__ == "__main__":
if len(sys.argv) == 1:
print("Usage: merge_midi [--mode=<mode>] <path>")
sys.exit(1)
parser = argparse.ArgumentParser()
parser.add_argument(
"-m",
"--mode",
default="single_channel",
help="Set mode for merge strategy",
)
parser.add_argument("path", help="Midi filename or path")
# Returns tuple of known args and unknown args
(args, _) = parser.parse_known_args(sys.argv[1:])
print("Mode:", args.mode)
merge_midi(args.path, mode=args.mode)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment