Open claytonsulby opened 4 years ago
I haven't worked on this project in a while, but I've been thinking about it a lot recently! Thanks for the suggestion. I assigned it to me, but if there is anyone else out there in the wide wide open source world who feels like doing this, please feel free to pick it up
I've tried writing a script to merge the separated instrument section midi's into a single midi file, but I'm hitting a wall on getting the note timing of the secondary sections correct. MIDI timing, as I understand it, is based on a duration of ticks from the previous note. Each new section contains a 0-velocity, 1-tick note event at the start and then silence so the notes are aligned properly, but I just can't get the fiddling right to simply append the additional sections at their correct timing.
Here's my code at the moment if anyone feels like taking a stab at it:
import os
from mido import MidiFile, MidiTrack
def list_midi_files(directory):
"""List all MIDI files in the directory."""
return [f for f in os.listdir(directory) if f.endswith('.mid')]
def group_files_by_instrument(files):
"""Group files by the part of the instrument name."""
grouped_files = {}
for file in files:
parts = file.split('_')
instrument_name = '_'.join(parts[3:])
if instrument_name not in grouped_files:
grouped_files[instrument_name] = []
grouped_files[instrument_name].append(file)
return grouped_files
def merge_midi_files(directory, files):
"""Merge MIDI files by adjusting start times based on the previous section's duration."""
combined_track = MidiTrack()
last_note_off_time = 0 # Time of the last note_off
for index, file in enumerate(sorted(files)):
mid = MidiFile(os.path.join(directory, file))
track = mid.tracks[0]
current_time = 0 # Current time counter for the track
print(f"Processing file: {file}") # debugging
for msg in track:
if msg.type in ['note_on', 'note_off']:
current_time += msg.time
if index > 0: # Adjust the message time for all but the first file
adjusted_time = current_time - last_note_off_time
msg.time = max(0, adjusted_time) # Ensure no negative times
print(f"Adjusted msg: {msg} with adjusted_time: {adjusted_time}") # debugging
combined_track.append(msg)
if msg.type == 'note_off':
last_note_off_time = current_time # Update the last note_off time
print(f"Last note_off_time for {file}: {last_note_off_time}") # debugging
new_mid = MidiFile()
new_mid.tracks.append(combined_track)
return new_mid
def main(directory):
midi_files = list_midi_files(directory)
grouped_files = group_files_by_instrument(midi_files)
for instrument, files in grouped_files.items():
merged_midi = merge_midi_files(directory, files)
# Save the merged MIDI file
merged_filename = os.path.join(directory, f"{instrument}_merged.mid")
merged_midi.save(merged_filename)
print(f"Merged file created: {merged_filename}")
if __name__ == "__main__":
directory = '/AI/Projects/watson-beat/src/output/MIDIFiles/' # Specify the directory
main(directory)
`
Moving the midi files into a DAW and assigning instruments for a track is a timely endeavor with a few solutions. Here's one I've come up with, that I'd love to see implemented to speed up the process.
Another thought is to find a way to assign a name to the track. When imported into the DAW each midi file is named "Track 0" regardless of placement.