[nexuiz-commits] r7036 - trunk/misc/tools
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Sun Jun 14 06:33:44 EDT 2009
Author: div0
Date: 2009-06-14 06:33:44 -0400 (Sun, 14 Jun 2009)
New Revision: 7036
Modified:
trunk/misc/tools/midi2cfg-ng.pl
Log:
midi2cfg-ng: new command syntax, support multiple MIDIs (yet to be tested)
Modified: trunk/misc/tools/midi2cfg-ng.pl
===================================================================
--- trunk/misc/tools/midi2cfg-ng.pl 2009-06-14 09:39:31 UTC (rev 7035)
+++ trunk/misc/tools/midi2cfg-ng.pl 2009-06-14 10:33:44 UTC (rev 7036)
@@ -1,8 +1,6 @@
#!/usr/bin/perl
# converter from Type 1 MIDI files to CFG files that control bots with the Tuba and other weapons for percussion (requires g_weaponarena all)
-# usage:
-# perl midi2cfg.pl filename.mid basenote walktime "x y z" "x y z" "x y z" ... "/" "x y z" "x y z" ... > filename.cfg
use strict;
use warnings;
@@ -13,77 +11,23 @@
use constant MIDI_FIRST_NONCHANNEL => 17;
use constant MIDI_DRUMS_CHANNEL => 10;
-die "Usage: $0 filename.conf filename.mid transpose timeoffset timeoffset2 timeoffset3 timeoffset4 preallocatedbots..."
- unless @ARGV >= 7;
-my ($config, $filename, $transpose, $timeoffset, $timeoffset2, $timeoffset3, $timeoffset4, @preallocate) = @ARGV;
+die "Usage: $0 filename.conf timeoffset_preinit timeoffset_postinit timeoffset_predone timeoffset_postdone timeoffset_preintermission timeoffset_postintermission midifile1 transpose1 midifile2 transpose2 ..."
+ unless @ARGV > 7 and @ARGV % 2;
+my ($config, $timeoffset_preinit, $timeoffset_postinit, $timeoffset_predone, $timeoffset_postdone, $timeoffset_preintermission, $timeoffset_postintermission, @midilist) = @ARGV;
-my $opus = MIDI::Opus->new({from_file => $filename});
-#$opus->write_to_file("/tmp/y.mid");
-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, [$tick, $_->[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;
-}
-
-# 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) = @$_;
- $command = 'note_off' if $command eq 'note_on' and $data[2] == 0;
- $tick += $delta;
- push @allmidievents, [$command, $tick, $sequence++, $track, @data];
- }
-}
- at allmidievents = sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] } @allmidievents;
-
-
sub unsort(@)
{
return map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [$_, rand] } @_;
}
-
-
-
-
+my $precommands = "";
+my $commands = "";
+my $busybots;
+my @busybots_allocated;
+my %notechannelbots;
+my $transpose = 0;
my $notetime = undef;
+my $lowestnotestart = undef;
sub botconfig_read($)
{
my ($fn) = @_;
@@ -182,7 +126,7 @@
}
elsif(/^raw (.*)/)
{
- printf "$1\n";
+ $precommands .= "$1\n";
}
else
{
@@ -190,7 +134,6 @@
}
}
- my $lowestnotestart = undef;
for(values %bots)
{
for(values %{$_->{notes_on}}, values %{$_->{percussion}})
@@ -200,11 +143,11 @@
}
}
- $notetime = $timeoffset2 - $lowestnotestart;
-
return \%bots;
}
+my $busybots_orig = botconfig_read $config;
+
sub busybot_cmd_bot_test($$@)
{
my ($bot, $time, @commands) = @_;
@@ -231,7 +174,7 @@
{
if($_->[0] eq 'time')
{
- printf "sv_cmd bot_cmd %d wait_until %f\n", $bot->{id}, $time + $_->[1];
+ $commands .= sprintf "sv_cmd bot_cmd %d wait_until %f\n", $bot->{id}, $time + $_->[1];
$bot->{timer} = $time + $_->[1];
}
elsif($_->[0] eq 'busy')
@@ -248,33 +191,55 @@
}
for(keys %buttons_release)
{
- printf "sv_cmd bot_cmd %d releasekey %s\n", $bot->{id}, $_;
+ $commands .= sprintf "sv_cmd bot_cmd %d releasekey %s\n", $bot->{id}, $_;
delete $bot->{buttons}->{$_};
}
for(@{$_}[1..@$_-1])
{
/(.*)(\?)?/ or next;
defined $2 and next;
- printf "sv_cmd bot_cmd %d presskey %s\n", $bot->{id}, $_;
+ $commands .= sprintf "sv_cmd bot_cmd %d presskey %s\n", $bot->{id}, $_;
$bot->{buttons}->{$_} = 1;
}
}
elsif($_->[0] eq 'cmd')
{
- printf "sv_cmd bot_cmd %d %s\n", $bot->{id}, join " ", @{$_}[1..@$_-1];
+ $commands .= sprintf "sv_cmd bot_cmd %d %s\n", $bot->{id}, join " ", @{$_}[1..@$_-1];
}
+ elsif($_->[0] eq 'barrier')
+ {
+ $commands .= sprintf "sv_cmd bot_cmd %d barrier\n", $bot->{id};
+ $bot->{timer} = $bot->{busytimer} = 0;
+ }
elsif($_->[0] eq 'raw')
{
- printf "%s\n", join " ", @{$_}[1..@$_-1];
+ $commands .= sprintf "%s\n", join " ", @{$_}[1..@$_-1];
}
}
return 1;
}
+my $intermissions = 0;
+
+sub busybot_intermission_bot($)
+{
+ my ($bot) = @_;
+ busybot_cmd_bot_execute $bot, 0, ['cmd', 'wait', $timeoffset_preintermission];
+ busybot_cmd_bot_execute $bot, 0, ['barrier'];
+ if($bot->{intermission})
+ {
+ busybot_cmd_bot_execute $bot, 0, @{$bot->{intermission}};
+ }
+ busybot_cmd_bot_execute $bot, 0, ['barrier'];
+ $notetime = $timeoffset_postintermission - $lowestnotestart;
+}
+
sub busybot_note_off_bot($$$$)
{
my ($bot, $time, $channel, $note) = @_;
+ return 1
+ if $channel == 10;
my $cmds = $bot->{notes_off}->{$note - $bot->{transpose} - $transpose};
return 1
if not defined $cmds; # note off cannot fail
@@ -310,12 +275,15 @@
{
return 0
if not busybot_cmd_bot_test $bot, $time + $notetime, @$cmds;
- busybot_cmd_bot_execute $bot, 0, ['cmd', 'wait', $timeoffset];
- busybot_cmd_bot_execute $bot, 0, ['cmd', 'barrier'];
+ busybot_cmd_bot_execute $bot, 0, ['cmd', 'wait', $timeoffset_preinit];
+ busybot_cmd_bot_execute $bot, 0, ['barrier'];
busybot_cmd_bot_execute $bot, 0, @{$bot->{init}}
if @{$bot->{init}};
- busybot_cmd_bot_execute $bot, 0, ['cmd', 'barrier'];
- $bot->{timer} = $bot->{busytimer} = 0;
+ busybot_cmd_bot_execute $bot, 0, ['barrier'];
+ for(1..$intermissions)
+ {
+ busybot_intermission_bot $bot;
+ }
busybot_cmd_bot_execute $bot, $time + $notetime, @$cmds;
}
else
@@ -327,9 +295,14 @@
return 1;
}
-my $busybots = botconfig_read $config;
-my @busybots_allocated;
-my %notechannelbots;
+sub busybots_reset()
+{
+ $busybots = Storable::dclone $busybots_orig;
+ @busybots_allocated = ();
+ %notechannelbots = ();
+ $transpose = 0;
+ $notetime = $timeoffset_postinit - $lowestnotestart;
+}
sub busybot_note_off($$$)
{
@@ -402,78 +375,181 @@
return 0;
}
-for(@preallocate)
+sub Preallocate(@)
{
- die "Cannot preallocate any more $_ bots"
- if $busybots->{$_}->{count} <= 0;
- my $bot = Storable::dclone $busybots->{$_};
- $bot->{id} = @busybots_allocated + 1;
- $bot->{classname} = $_;
- busybot_cmd_bot_execute $bot, 0, ['cmd', 'wait', $timeoffset];
- busybot_cmd_bot_execute $bot, 0, ['cmd', 'barrier'];
- busybot_cmd_bot_execute $bot, 0, @{$bot->{init}}
- if @{$bot->{init}};
- busybot_cmd_bot_execute $bot, 0, ['cmd', 'barrier'];
- $bot->{timer} = $bot->{busytimer} = 0;
- --$busybots->{$_}->{count};
- push @busybots_allocated, $bot;
+ my (@preallocate) = @_;
+ busybots_reset();
+ for(@preallocate)
+ {
+ die "Cannot preallocate any more $_ bots"
+ if $busybots->{$_}->{count} <= 0;
+ my $bot = Storable::dclone $busybots->{$_};
+ $bot->{id} = @busybots_allocated + 1;
+ $bot->{classname} = $_;
+ busybot_cmd_bot_execute $bot, 0, ['cmd', 'wait', $timeoffset_preinit];
+ busybot_cmd_bot_execute $bot, 0, ['barrier'];
+ busybot_cmd_bot_execute $bot, 0, @{$bot->{init}}
+ if @{$bot->{init}};
+ busybot_cmd_bot_execute $bot, 0, ['barrier'];
+ --$busybots->{$_}->{count};
+ push @busybots_allocated, $bot;
+ }
}
-my %midinotes = ();
-my $note_min = undef;
-my $note_max = undef;
-my $notes_stuck = 0;
-my $t = 0;
-for(@allmidievents)
+sub ConvertMIDI($$)
{
- $t = tick2sec $_->[1];
- my $track = $_->[3];
- if($_->[0] eq 'note_on')
+ my ($filename, $trans) = @_;
+ $transpose = $trans;
+
+ 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, [$tick, $_->[2] * 0.000001 / $ticksperquarter];
+ }
+ }
+ my $tick2sec = sub
{
- my $chan = $_->[4] + 1;
- $note_min = $_->[5]
- if not defined $note_min or $_->[5] < $note_min and $chan != 10;
- $note_max = $_->[5]
- if not defined $note_max or $_->[5] > $note_max and $chan != 10;
- if($midinotes{$chan}{$_->[5]})
+ my ($tick) = @_;
+ my $sec = 0;
+ my $curtempo = [0, 0.5 / $ticksperquarter];
+ for(@tempi)
{
- --$notes_stuck;
- busybot_note_off($t, $chan, $_->[5]);
+ 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 = $_;
}
- busybot_note_on($t, $chan, $_->[5]);
- ++$notes_stuck;
- $midinotes{$chan}{$_->[5]} = 1;
+ $sec += ($tick - $curtempo->[0]) * $curtempo->[1];
+ return $sec;
+ };
+
+ # 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) = @$_;
+ $command = 'note_off' if $command eq 'note_on' and $data[2] == 0;
+ $tick += $delta;
+ push @allmidievents, [$command, $tick, $sequence++, $track, @data];
+ }
}
- elsif($_->[0] eq 'note_off')
+ @allmidievents = sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] } @allmidievents;
+
+ my %midinotes = ();
+ my $note_min = undef;
+ my $note_max = undef;
+ my $notes_stuck = 0;
+ my $t = 0;
+ for(@allmidievents)
{
- my $chan = $_->[4] + 1;
- if($midinotes{$chan}{$_->[5]})
+ $t = $tick2sec->($_->[1]);
+ my $track = $_->[3];
+ if($_->[0] eq 'note_on')
{
- --$notes_stuck;
- busybot_note_off($t, $chan, $_->[5]);
+ my $chan = $_->[4] + 1;
+ $note_min = $_->[5]
+ if not defined $note_min or $_->[5] < $note_min and $chan != 10;
+ $note_max = $_->[5]
+ if not defined $note_max or $_->[5] > $note_max and $chan != 10;
+ if($midinotes{$chan}{$_->[5]})
+ {
+ --$notes_stuck;
+ busybot_note_off($t, $chan, $_->[5]);
+ }
+ busybot_note_on($t, $chan, $_->[5]);
+ ++$notes_stuck;
+ $midinotes{$chan}{$_->[5]} = 1;
}
- $midinotes{$chan}{$_->[5]} = 0;
+ elsif($_->[0] eq 'note_off')
+ {
+ my $chan = $_->[4] + 1;
+ if($midinotes{$chan}{$_->[5]})
+ {
+ --$notes_stuck;
+ busybot_note_off($t, $chan, $_->[5]);
+ }
+ $midinotes{$chan}{$_->[5]} = 0;
+ }
}
+
+ print STDERR "For file $filename:\n";
+ print STDERR " Range of notes: $note_min .. $note_max\n";
+ print STDERR " Safe transpose range: @{[$note_max - 19]} .. @{[$note_min + 13]}\n";
+ print STDERR " Unsafe transpose range: @{[$note_max - 27]} .. @{[$note_min + 18]}\n";
+ print STDERR " Stuck notes: $notes_stuck\n";
+
+ while(my ($k1, $v1) = each %midinotes)
+ {
+ while(my ($k2, $v2) = each %$v1)
+ {
+ busybot_note_off($t, $k1, $k2);
+ }
+ }
+
+ for(@busybots_allocated)
+ {
+ busybot_intermission_bot $_;
+ }
+ ++$intermissions;
}
-for(@busybots_allocated)
+sub Deallocate()
{
- busybot_cmd_bot_execute $_, 0, ['cmd', 'wait', $timeoffset3];
- busybot_cmd_bot_execute $_, 0, ['cmd', 'barrier'];
- if($_->{done})
+ print STDERR "Bots allocated:\n";
+ for(@busybots_allocated)
{
- busybot_cmd_bot_execute $_, 0, @{$_->{done}};
+ print STDERR "$_->{id} is a $_->{classname}\n";
}
- busybot_cmd_bot_execute $_, 0, ['cmd', 'barrier'];
- busybot_cmd_bot_execute $_, 0, ['cmd', 'wait', $timeoffset4];
+ for(@busybots_allocated)
+ {
+ busybot_cmd_bot_execute $_, 0, ['cmd', 'wait', $timeoffset_predone];
+ busybot_cmd_bot_execute $_, 0, ['barrier'];
+ if($_->{done})
+ {
+ busybot_cmd_bot_execute $_, 0, @{$_->{done}};
+ }
+ busybot_cmd_bot_execute $_, 0, ['cmd', 'wait', $timeoffset_postdone];
+ busybot_cmd_bot_execute $_, 0, ['barrier'];
+ }
}
-print STDERR "Range of notes: $note_min .. $note_max\n";
-print STDERR "Safe transpose range: @{[$note_max - 19]} .. @{[$note_min + 13]}\n";
-print STDERR "Unsafe transpose range: @{[$note_max - 27]} .. @{[$note_min + 18]}\n";
-print STDERR "Stuck notes: $notes_stuck\n";
-print STDERR "Bots allocated:\n";
-for(@busybots_allocated)
+my @preallocate = ();
+for(;;)
{
- print STDERR "$_->{id} is a $_->{classname}\n";
+ $commands = "";
+ Preallocate(@preallocate);
+ my @l = @midilist;
+ while(@l)
+ {
+ my $filename = shift @l;
+ my $transpose = shift @l;
+ ConvertMIDI($filename, $transpose);
+ }
+ Deallocate();
+ my @preallocate_new = map { $_->{classname} } @busybots_allocated;
+ last if @preallocate_new == @preallocate;
+ @preallocate = @preallocate_new;
}
+
+print "$precommands$commands";
More information about the nexuiz-commits
mailing list