[nexuiz-commits] r6499 - trunk/misc/tools
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Thu Apr 16 04:11:50 EDT 2009
Author: div0
Date: 2009-04-16 04:11:41 -0400 (Thu, 16 Apr 2009)
New Revision: 6499
Added:
trunk/misc/tools/midi2bgs.pl
Log:
add a MIDI to BGS converter
Added: trunk/misc/tools/midi2bgs.pl
===================================================================
--- trunk/misc/tools/midi2bgs.pl (rev 0)
+++ trunk/misc/tools/midi2bgs.pl 2009-04-16 08:11:41 UTC (rev 6499)
@@ -0,0 +1,101 @@
+#!/usr/bin/perl
+
+# 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
+# track and channel numbers -1 include all events
+# example:
+# perl midi2bgs.pl filename.mid -1 10 0.3 note_ > filename.bgs
+
+use strict;
+use warnings;
+use MIDI;
+use MIDI::Opus;
+
+my ($filename, $trackno, $channelno, $offset, $noteprefix) = @ARGV;
+my $opus = MIDI::Opus->new({from_file => $filename});
+my $ticksperquarter = $opus->ticks();
+my $tracks = $opus->tracks_r();
+my @tempi = (); # list of start tick, time per tick pairs (calculated as seconds per quarter / ticks per quarter)
+my $tick;
+
+$tick = 0;
+for($tracks->[0]->events())
+{
+ $tick += $_->[1];
+ if($_->[0] eq 'set_tempo')
+ {
+ push @tempi, [$_->[1], $_->[2] * 0.000001 / $ticksperquarter];
+ }
+}
+sub tick2sec($)
+{
+ my ($tick) = @_;
+ my $sec = 0;
+ my $curtempo = [0, 0.5 / $ticksperquarter];
+ for(@tempi)
+ {
+ if($_->[0] < $tick)
+ {
+ # this event is in the past
+ # we add the full time since the last one then
+ $sec += ($_->[0] - $curtempo->[0]) * $curtempo->[1];
+ }
+ else
+ {
+ # if this event is in the future, we break
+ last;
+ }
+ $curtempo = $_;
+ }
+ $sec += ($tick - $curtempo->[0]) * $curtempo->[1];
+ return $sec + $offset;
+}
+
+my @notes = ('c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b');
+my @notenames = ();
+for my $octave (0..11)
+{
+ for(@notes)
+ {
+ if($octave <= 3)
+ {
+ push @notenames, uc($_) . ',' x (3 - $octave);
+ }
+ else
+ {
+ push @notenames, lc($_) . "'" x ($octave - 4);
+ }
+ }
+}
+
+my @outevents = (); # format: name, time in seconds, velocity
+$tick = 0;
+for my $thistrackno($trackno >= 0 ? $trackno : (0..@$tracks - 1))
+{
+ for($tracks->[$thistrackno]->events())
+ {
+ $tick += $_->[1];
+ my $t = tick2sec $tick;
+ if($_->[0] eq 'note_on')
+ {
+ 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, @$_;
+}
More information about the nexuiz-commits
mailing list