-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathbatch_mtf2midi.py
More file actions
126 lines (110 loc) · 4.59 KB
/
batch_mtf2midi.py
File metadata and controls
126 lines (110 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import os
import math
import mido
import random
import argparse
from tqdm import tqdm
from multiprocessing import Pool
# Parse command-line arguments
def parse_args():
parser = argparse.ArgumentParser(description="Convert MTF files to MIDI format.")
parser.add_argument(
"input_dir",
type=str,
help="Path to the folder containing MTF (.mtf) files"
)
parser.add_argument(
"output_dir",
type=str,
help="Path to the folder where converted MIDI files will be saved"
)
return parser.parse_args()
def str_to_msg(str_msg):
"""
Converts a string representation of a MIDI message back into a mido.Message object.
"""
type = str_msg.split(" ")[0]
try:
msg = mido.Message(type)
except:
msg = mido.MetaMessage(type)
if type in ["text", "copyright", "track_name", "instrument_name",
"lyrics", "marker", "cue_marker", "device_name"]:
values = [type, " ".join(str_msg.split(" ")[1:-1]).encode('utf-8').decode('unicode_escape'), str_msg.split(" ")[-1]]
elif "[" in str_msg or "(" in str_msg:
is_bracket = "[" in str_msg
left_idx = str_msg.index("[") if is_bracket else str_msg.index("(")
right_idx = str_msg.index("]") if is_bracket else str_msg.index(")")
list_str = [int(num) for num in str_msg[left_idx+1:right_idx].split(", ")]
if not is_bracket:
list_str = tuple(list_str)
values = str_msg[:left_idx].split(" ") + [list_str] + str_msg[right_idx+1:].split(" ")
values = [value for value in values if value != ""]
else:
values = str_msg.split(" ")
if len(values) != 1:
for idx, (key, content) in enumerate(msg.__dict__.items()):
if key == "type":
continue
value = values[idx]
if isinstance(content, int) or isinstance(content, float):
float_value = float(value)
value = float_value
if value % 1 == 0:
value = int(value)
setattr(msg, key, value)
return msg
def convert_mtf2midi(file_list, input_dir, output_dir):
"""
Converts MTF files to MIDI format.
"""
for file in tqdm(file_list):
# Construct the output directory by replacing input_dir with output_dir
relative_path = os.path.relpath(os.path.dirname(file), input_dir)
output_folder = os.path.join(output_dir, relative_path)
os.makedirs(output_folder, exist_ok=True)
try:
with open(file, 'r', encoding='utf-8') as f:
msg_list = f.read().splitlines()
# Build a new MIDI file based on the MIDI messages
new_mid = mido.MidiFile()
new_mid.ticks_per_beat = int(msg_list[0].split(" ")[1])
track = mido.MidiTrack()
new_mid.tracks.append(track)
for msg in msg_list[1:]:
if "unknown_meta" in msg:
continue
new_msg = str_to_msg(msg)
track.append(new_msg)
output_file_path = os.path.join(output_folder, os.path.splitext(os.path.basename(file))[0] + '.mid')
new_mid.save(output_file_path)
except Exception as e:
with open('logs/mtf2midi_error_log.txt', 'a', encoding='utf-8') as f:
f.write(f"Error processing {file}: {str(e)}\n")
if __name__ == '__main__':
# Parse command-line arguments
args = parse_args()
input_dir = os.path.abspath(args.input_dir) # Ensure absolute path
output_dir = os.path.abspath(args.output_dir) # Ensure absolute path
file_list = []
os.makedirs("logs", exist_ok=True)
# Traverse the specified input folder for MTF files
for root, dirs, files in os.walk(input_dir):
for file in files:
if not file.endswith(".mtf"):
continue
filename = os.path.join(root, file).replace("\\", "/")
file_list.append(filename)
# Prepare for multiprocessing
file_lists = []
random.shuffle(file_list)
for i in range(os.cpu_count()):
start_idx = int(math.floor(i * len(file_list) / os.cpu_count()))
end_idx = int(math.floor((i + 1) * len(file_list) / os.cpu_count()))
file_lists.append(file_list[start_idx:end_idx])
# Use multiprocessing to speed up conversion
pool = Pool(processes=os.cpu_count())
pool.starmap(
convert_mtf2midi,
[(file_list_chunk, input_dir, output_dir) for file_list_chunk in file_lists]
)