[nexuiz-commits] r6509 - trunk/misc/tools
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Thu Apr 16 11:10:58 EDT 2009
Author: div0
Date: 2009-04-16 11:10:58 -0400 (Thu, 16 Apr 2009)
New Revision: 6509
Modified:
trunk/misc/tools/midi2bgs.pl
Log:
midi2bgs: handle MIDIs correctly where a note from one track is stopped on another
Modified: trunk/misc/tools/midi2bgs.pl
===================================================================
--- trunk/misc/tools/midi2bgs.pl 2009-04-16 15:03:25 UTC (rev 6508)
+++ trunk/misc/tools/midi2bgs.pl 2009-04-16 15:10:58 UTC (rev 6509)
@@ -2,17 +2,23 @@
# converter from Type 1 MIDI files to BGS files that control particle effects on maps
# usage:
-# perl midi2bgs.pl filename.mid tracknumber channelnumber offset prefix > filename.bgs
+# perl midi2bgs.pl filename.mid tracknumber channelnumber offset notepattern > filename.bgs
# track and channel numbers -1 include all events
+# in patterns, %1$s inserts the note name, %2$d inserts the track number, and %3$d inserts the channel number
# example:
-# perl midi2bgs.pl filename.mid -1 10 0.3 note_ > filename.bgs
+# perl midi2bgs.pl filename.mid -1 10 0.3 'note_%1$s_%3$d_%2$d' > filename.bgs
use strict;
use warnings;
use MIDI;
use MIDI::Opus;
-my ($filename, $trackno, $channelno, $offset, $noteprefix) = @ARGV;
+my ($filename, $trackno, $channelno, $offset, $notepattern) = @ARGV;
+$notepattern = '%1$s'
+ unless defined $notepattern;
+defined $offset
+ or die "usage: $0 filename.mid {trackno|-1} {channelno|-1} offset [notepattern]\n";
+
my $opus = MIDI::Opus->new({from_file => $filename});
my $ticksperquarter = $opus->ticks();
my $tracks = $opus->tracks_r();
@@ -69,33 +75,59 @@
}
}
+# merge all to a single track
+my @allmidievents = ();
+my $sequence = 0;
+for my $track(0..@$tracks-1)
+{
+ $tick = 0;
+ for($tracks->[$track]->events())
+ {
+ my ($command, $delta, @data) = @$_;
+ $tick += $delta;
+ push @allmidievents, [$command, $tick, $sequence++, $track, @data];
+ }
+}
+ at allmidievents = sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] } @allmidievents;
+
my @outevents = (); # format: name, time in seconds, velocity
$tick = 0;
-for my $thistrackno($trackno >= 0 ? $trackno : (0..@$tracks - 1))
+
+my %notecounters;
+my %notecounters_converted;
+for(@allmidievents)
{
- for($tracks->[$thistrackno]->events())
+ my $t = tick2sec $_->[1];
+ my $track = $_->[3];
+ next
+ unless $trackno < 0 || $trackno == $track;
+ if($_->[0] eq 'note_on')
{
- $tick += $_->[1];
- my $t = tick2sec $tick;
- if($_->[0] eq 'note_on')
+ my $chan = $_->[4];
+ my $note = sprintf $notepattern, $notenames[$_->[5]], $trackno, $channelno;
+ my $velocity = $_->[6] / 127.0;
+ push @outevents, [$note, $t, $velocity]
+ if($channelno < 0 || $channelno == $chan);
+ ++$notecounters_converted{$note}
+ unless $notecounters{$chan}{$_->[5]};
+ $notecounters{$chan}{$_->[5]} = 1;
+ }
+ elsif($_->[0] eq 'note_off')
+ {
+ my $chan = $_->[4];
+ my $note = sprintf $notepattern, $notenames[$_->[5]], $trackno, $channelno;
+ my $velocity = $_->[6] / 127.0;
+ --$notecounters_converted{$note}
+ if $notecounters{$chan}{$_->[5]};
+ $notecounters{$chan}{$_->[5]} = 0;
+ if($notecounters_converted{$note} == 0)
{
- my $chan = $_->[2];
- my $note = $notenames[$_->[3]];
- my $velocity = $_->[4] / 127.0;
- push @outevents, [$note, $t, $velocity]
- if($channelno < 0 || $channelno == $chan);
- }
- elsif($_->[0] eq 'note_off')
- {
- my $chan = $_->[2];
- my $note = $notenames[$_->[3]];
- my $velocity = $_->[4] / 127.0;
push @outevents, [$note, $t, 0]
if($channelno < 0 || $channelno == $chan);
}
- }
+ }
}
for(sort { $a->[0] cmp $b->[0] or $a->[1] <=> $b->[1] } @outevents)
{
- printf "%s%s %f %f\n", $noteprefix, @$_;
+ printf "%s %13.6f %13.6f\n", @$_;
}
More information about the nexuiz-commits
mailing list