]> git.xonotic.org Git - xonotic/xonotic.git/blobdiff - misc/tools/midi2cfg-ng.pl
Merge branch 'master' of git://nl.git.xonotic.org/xonotic/xonotic
[xonotic/xonotic.git] / misc / tools / midi2cfg-ng.pl
index ea1b1e6d167bcf82a6cc1354766490d0d7a86a7c..58b4097065280f6bdd0648be09e93502ac3eb494 100755 (executable)
@@ -342,6 +342,10 @@ sub busybot_cmd_bot_execute($$@)
                {
                        $commands .= sprintf "sv_cmd bot_cmd %d %s\n", $bot->{id}, join " ", @{$_}[1..@$_-1];
                }
+               elsif($_->[0] eq 'aim_random')
+               {
+                       $commands .= sprintf "sv_cmd bot_cmd %d aim \"%f 0 %f\"\n", $bot->{id}, $_->[1] + rand($_->[2] - $_->[1]), $_->[3];
+               }
                elsif($_->[0] eq 'barrier')
                {
                        $commands .= sprintf "sv_cmd bot_cmd %d barrier\n", $bot->{id};
@@ -473,10 +477,19 @@ sub busybot_note_on_bot($$$$$$$)
        }
        ++$bot->{seen}{$k0}{$k1};
 
+       if(($bot->{lastuse} // -666) >= $time - $time_forgetfulness && $channel == $bot->{lastchannel})
+       {
+               $bot->{lastchannelsequence} += 1;
+       }
+       else
+       {
+               $bot->{lastchannelsequence} = 1;
+       }
        $bot->{lastuse} = $time;
        $bot->{lastchannel} = $channel;
-       $bot->{lastprogram} = $program;
-       $bot->{lastnote} = $note;
+
+#      print STDERR "$time $bot->{id} $channel:$note\n"
+#              if $channel == 11;
 
        return 1;
 }
@@ -521,7 +534,7 @@ sub botsort($$$$@)
                }
                sort
                {
-                       $a->[1] <=> $b->[1]
+                       $b->[1] <=> $a->[1]
                        or
                        ($a->[0]->{lastuse} // -666) <=> ($b->[0]->{lastuse} // -666)
                        or
@@ -530,18 +543,18 @@ sub botsort($$$$@)
                map
                {
                        my $q = 0;
-                       if(($_->{lastuse} // -666) >= $time - $time_forgetfulness)
+                       if($channel != 10) # percussion just should do round robin
                        {
-                               if($channel == $_->{lastchannel})
+                               if(($_->{lastuse} // -666) >= $time - $time_forgetfulness)
                                {
-                                       ++$q;
-                                       if($program == $_->{lastprogram})
+                                       if($channel == $_->{lastchannel})
                                        {
-                                               ++$q;
-                                               if($note == $_->{lastnote})
-                                               {
-                                                       ++$q;
-                                               }
+                                               $q += $_->{lastchannelsequence};
+                                       }
+                                       else
+                                       {
+                                               # better leave this one alone
+                                               $q -= $_->{lastchannelsequence};
                                        }
                                }
                        }
@@ -787,48 +800,116 @@ sub ConvertMIDI($$)
                }
        }
 
+       # sort events
        @allmidievents = sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] } @allmidievents;
 
+       # find the first interesting event
+       my $shift = [grep { $_->[0] eq 'note_on' } @allmidievents]->[0][1];
+       die "No notes!"
+               unless defined $shift;
+
+       # shift times by first event, no boring waiting
+       $_->[0] = ($_->[0] < $shift ? 0 : $_->[0] - $shift) for @tempi;
+       $_->[1] = ($_->[1] < $shift ? 0 : $_->[1] - $shift) for @allmidievents;
+
+       # fix event list
+
        my %midinotes = ();
        my $notes_stuck = 0;
        my %notes_seen = ();
        my %programs = ();
        my $t = 0;
+       my %sustain = ();
+
+       my $note_on = sub
+       {
+               my ($ev) = @_;
+               my $chan = $ev->[4] + 1;
+               ++$notes_seen{$chan}{($programs{$chan} || 1)}{$ev->[5]};
+               if($midinotes{$chan}{$ev->[5]})
+               {
+                       --$notes_stuck;
+                       busybot_note_off($t - SYS_TICRATE - 0.001, $chan, $ev->[5]);
+               }
+               busybot_note_on($t, $chan, $programs{$chan} || 1, $ev->[5]);
+               ++$notes_stuck;
+               $midinotes{$chan}{$ev->[5]} = 1;
+       };
+
+       my $note_off = sub
+       {
+               my ($ev) = @_;
+               my $chan = $ev->[4] + 1;
+               if(exists $sustain{$chan})
+               {
+                       push @{$sustain{$chan}}, $ev;
+                       return;
+               }
+               if($midinotes{$chan}{$ev->[5]})
+               {
+                       --$notes_stuck;
+                       busybot_note_off($t - SYS_TICRATE - 0.001, $chan, $ev->[5]);
+               }
+               $midinotes{$chan}{$ev->[5]} = 0;
+       };
+
+       my $patch_change = sub
+       {
+               my ($ev) = @_;
+               my $chan = $ev->[4] + 1;
+               my $program = $ev->[5] + 1;
+               $programs{$chan} = $program;
+       };
+
+       my $sustain_change = sub
+       {
+               my ($ev) = @_;
+               my $chan = $ev->[4] + 1;
+               if($ev->[6] == 0)
+               {
+                       # release all currently not pressed notes
+                       my $s = $sustain{$chan};
+                       delete $sustain{$chan};
+                       for(@{($s || [])})
+                       {
+                               $note_off->($_);
+                       }
+               }
+               else
+               {
+                       # no more note-off
+                       $sustain{$chan} = [];
+               }
+       };
+
        for(@allmidievents)
        {
                $t = $tick2sec->($_->[1]);
-               my $track = $_->[3];
+               my $track = $_->[3];
                if($_->[0] eq 'note_on')
                {
-                       my $chan = $_->[4] + 1;
-                       ++$notes_seen{$chan}{($programs{$chan} || 1)}{$_->[5]};
-                       if($midinotes{$chan}{$_->[5]})
-                       {
-                               --$notes_stuck;
-                               busybot_note_off($t - SYS_TICRATE, $chan, $_->[5]);
-                       }
-                       busybot_note_on($t, $chan, $programs{$chan} || 1, $_->[5]);
-                       ++$notes_stuck;
-                       $midinotes{$chan}{$_->[5]} = 1;
+                       $note_on->($_);
                }
                elsif($_->[0] eq 'note_off')
                {
-                       my $chan = $_->[4] + 1;
-                       if($midinotes{$chan}{$_->[5]})
-                       {
-                               --$notes_stuck;
-                               busybot_note_off($t - SYS_TICRATE, $chan, $_->[5]);
-                       }
-                       $midinotes{$chan}{$_->[5]} = 0;
+                       $note_off->($_);
                }
                elsif($_->[0] eq 'patch_change')
                {
-                       my $chan = $_->[4] + 1;
-                       my $program = $_->[5] + 1;
-                       $programs{$chan} = $program;
+                       $patch_change->($_);
+               }
+               elsif($_->[0] eq 'control_change' && $_->[5] == 64) # sustain pedal
+               {
+                       $sustain_change->($_);
                }
        }
 
+       # fake events for releasing pedal
+       for(keys %sustain)
+       {
+               $sustain_change->(['control_change', $t, undef, undef, $_ - 1, 64, 0]);
+       }
+
        print STDERR "For file $filename:\n";
        print STDERR "  Stuck notes: $notes_stuck\n";
 
@@ -848,7 +929,7 @@ sub ConvertMIDI($$)
                                        my $votehigh = 0;
                                        my $votelow = 0;
                                        my $votegood = 0;
-                                       for(@busybots_allocated)
+                                       for(@busybots_allocated, grep { $_->{count} > 0 } values %$busybots)
                                        {
                                                next # I won't play on this channel
                                                        if defined $_->{channels} and not $_->{channels}->{$channel};
@@ -984,6 +1065,8 @@ for(;;)
                my @preallocate_new = map { $_->{classname} } @busybots_allocated;
                if(@preallocate_new == @preallocate)
                {
+                       print "sv_cmd bot_cmd reset\n";
+                       print "sv_cmd bot_cmd setbots @{[scalar @preallocate_new]}\n";
                        print "$precommands$commands";
                        exit 0;
                }