File size: 3,727 Bytes
3c428bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
input_dir = "<path_to_your_mtf_files>"  # Replace with the path to your folder containing MTF (.mtf) files

import os
import math
import mido
import random
from tqdm import tqdm
from multiprocessing import Pool

def str_to_msg(str_msg):
    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):
    for file in tqdm(file_list):
        filename = file.split('/')[-1]
        output_dir = file.split('/')[:-1]
        output_dir[0] = output_dir[0] + '_midi'
        output_dir = '/'.join(output_dir)
        os.makedirs(output_dir, 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_dir, os.path.basename(file).replace('.mtf', '.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__':
    file_list = []
    os.makedirs("logs", exist_ok=True)

    # Traverse the specified 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])

    pool = Pool(processes=os.cpu_count())
    pool.map(convert_mtf2midi, file_lists)