Re: midi re-tempoizer

[email protected] (Jean-Pierre Vidal) Sun, 5 Dec 2004 08:52:34 +0000
Newsgroups perl.midi
Message-ID <[email protected]>
Le vendredi 3 D=E9cembre 2004 10:18, zentara a =E9crit=A0:

[snip]

>=20
> Cool. This is a much asked for utility.
>=20
> I've been wracking my brain trying to figure out how to
> get the total playlength of a midi using Perl.
>=20
> Would anyone know how to do this?
>=20

Try this:

#!perl -w
use strict;
use MIDI;

my $filename =3D shift;
die "usage : perl $0 midifile\n" if !defined $filename;

my @tempo_ticks;
my @tempo_value;

my $total_ticks;
my $max_ticks =3D 0;

my $opus =3D new MIDI::Opus({'from_file' =3D> $filename});
my $tpqn =3D $opus->ticks(); # ticks per quarter note

my @tracks =3D $opus->tracks();
for my $tr (@tracks) {
	$total_ticks =3D 0;
	my $tempo_ix =3D 0;
	my @events =3D $tr->events();
	for my $e (@events) {
		if ($$e[0] eq 'set_tempo' ) {
			$tempo_ticks[$tempo_ix] =3D $$e[1];
			$tempo_ticks[$tempo_ix] +=3D $tempo_ticks[$tempo_ix - 1] if $tempo_ix > =
0;
			$tempo_value[$tempo_ix] =3D $$e[2];=20
			$tempo_ix++;=20
		}
		if ($$e[0] =3D~ 'note') {
			$total_ticks +=3D $$e[1]; # add deltatime for note_on and note_off
		}
	}
	$max_ticks =3D $total_ticks if $total_ticks > $max_ticks;
}

my $duration =3D 0;
if ($#tempo_ticks =3D=3D 0) {
	$duration =3D $max_ticks / $tpqn * $tempo_value[0] / 1000000;
}=20
else {
	for (1..$#tempo_ticks) {
		$duration +=3D ($tempo_ticks[$_] - $tempo_ticks[$_-1]) / $tpqn *=20
$tempo_value[$_-1] / 1000000;
		$max_ticks -=3D $tempo_ticks[$_];
	}
}
$duration =3D int($duration + .5);
print "duration : $duration s\n";
__END__

Better would be a bridge between MIDI::Opus and MIDI::Score, and a function=
=20
$score->duration;-)

Jean-Pierre