[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