#!/usr/bin/env python3

# Concatenate two MIDI files into a single file.

import sys
import mido

def get_absolute_messages(track):
    """Convert delta-time track to a list of (absolute_tick, message) tuples."""
    abs_time = 0
    abs_msgs = []
    for msg in track:
        abs_time += msg.time
        abs_msgs.append((abs_time, msg))
    return abs_msgs

def concatenate_midis(file1, file2, output_file):
    mid1 = mido.MidiFile(file1)
    mid2 = mido.MidiFile(file2)
    
    # Create output Type 0 (single track) file matching the tick resolution
    output = mido.MidiFile(ticks_per_beat=mid1.ticks_per_beat, type=0)
    new_track = mido.MidiTrack()
    output.tracks.append(new_track)
    
    # Merge all tracks of each file into chronological single tracks
    track1 = mido.merge_tracks(mid1.tracks)
    track2 = mido.merge_tracks(mid2.tracks)
    
    # Get absolute tick positions
    abs1 = get_absolute_messages(track1)
    max_tick1 = abs1[-1][0] if abs1 else 0
    
    abs2 = get_absolute_messages(track2)
    
    # Filter out end_of_track meta messages during combination
    clean_abs1 = [(t, msg) for t, msg in abs1 if not (msg.is_meta and msg.type == 'end_of_track')]
    clean_abs2 = [(t + max_tick1, msg) for t, msg in abs2 if not (msg.is_meta and msg.type == 'end_of_track')]
    
    # Combine both timelines
    combined_abs = clean_abs1 + clean_abs2
    
    # Convert absolute ticks back to delta times and append to the new track
    prev_tick = 0
    for t, msg in combined_abs:
        delta = t - prev_tick
        new_msg = msg.copy(time=delta)
        new_track.append(new_msg)
        prev_tick = t
        
    output.save(output_file)
    print(f"Successfully concatenated sequentially into {output_file}")

if __name__ == "__main__":
    if len(sys.argv) < 4:
        print(f'Usage: {sys.argv[0]} <file1.mid> <file2.mid> <output.mid>')
    else:
        concatenate_midis(sys.argv[1], sys.argv[2], sys.argv[3])
