#!/usr/bin/perl -w
# Time-stamp: "2005-11-28 18:27:54 AST"

#
# catmidi -- for appending together several midi files into one.
#              sburke@cpan.org
#              Note: sometimes it just plain doesn't work right.
#


use constant DEBUG => 0;
use strict;
use warnings;
use MIDI;
use MIDI::Score;

@ARGV > 2 or  die "Usage: $0 in1.mid in2.mid... out.mid";

my @in = @ARGV;
my $out = pop @in;
die "But $out already exists!" if -e $out;
foreach my $f (@in) {
  -e $f or die "but $f doesn't exist!";
  -f $f or die "but $f isn't a file!";
  -r $f or die "but $f isn't readable!";
}

my @granularities;

my( @out_tracks );
my $time_now = 0;
foreach my $f (@in) {
  my $opus = MIDI::Opus->new( { 'from_file' => $f } );
  DEBUG and printf "Done reading %s, which has %s tracks.\n",
   $f, scalar($opus->tracks);

  my @ticks;
  foreach my $t ($opus->tracks) {
    if($t->events_r and @{$t->events_r}) {
      my($score_r, $ticks) = MIDI::Score::events_r_to_score_r(
	MIDI::Event::copy_structure( $t->events_r ));
      DEBUG > 1 and print " * Track lasts $ticks ticks\n";
      push @ticks, $ticks;
      if($time_now) {
	unshift @{$t->events_r}, ['text_event', $time_now, "_"];
	DEBUG > 4 and print "    Just added: @{$t->events_r->[0]}\n";
      }
    } else {
      DEBUG > 1 and print " * Track is eventless.  Skipping.\n";
    }
    push @out_tracks, $t;
  }
  push @granularities, $opus->ticks;

  my $length = max(@ticks);
  $time_now += $length;
  DEBUG and print " Opus is $length ticks long.  At end, time is $time_now.\n";
}

die "No tracks in any of: @in" unless @out_tracks;


warn "The opuses have different granularities: @granularities.  The output will be weird!"
 if grep $granularities[0] != $_, @granularities;


my $o = MIDI::Opus->new();
$o->ticks($granularities[0]);
$o->tracks( @out_tracks );
DEBUG and print "Writing to $out\n";
$o->write_to_file( $out );

DEBUG and print "Done.\n";
exit;

sub max {
  return 0 unless @_;
  my $max = shift;
  for(@_){$max=$_ if $_ > $max};
  return $max;
}

__END__
