+ if(@epicfailbots)
+ {
+ # we cannot add a new bot to play this
+ # we could try finding a bot that could play this, and force him to stop the note!
+
+ my @candidates = (); # contains: [$bot, $score, $offtime]
+
+ # put in all currently busy bots that COULD play this, if they did a note-off first
+ for my $bot(@epicfailbots)
+ {
+ next
+ if $busybots->{$bot->{classname}}->{count} != 0;
+ next
+ unless $bot->{busy};
+ my ($busy_chan, $busy_note, $busy_cmds_off) = @{$bot->{busy}};
+ next
+ unless $busy_cmds_off;
+ my ($cmds, $cmds_off, $k0, $k1) = busybot_get_cmds_bot $bot, $channel, $note;
+ next
+ unless $cmds;
+ my ($mintime, $maxtime, $busytime) = busybot_cmd_bot_cmdinfo @$cmds;
+ my ($mintime_off, $maxtime_off, $busytime_off) = busybot_cmd_bot_cmdinfo @$busy_cmds_off;
+
+ my $noteofftime = busybot_cmd_bot_matchtime $bot, $time + $notetime + $mintime, $time + $notetime, @$busy_cmds_off;
+ next
+ if $noteofftime < $bot->{busytimer};
+ next
+ if $noteofftime + $mintime_off < $bot->{timer};
+
+ my $score = 0;
+ # prefer turning off long notes
+ $score += 100 * ($noteofftime - $bot->{timer});
+ # prefer turning off low notes
+ $score += 1 * (-$note);
+ # prefer turning off notes that already play on another channel
+ $score += 1000 * (grep { $_ != $busy_chan && $notechannelbots{$_}{$busy_note} && $notechannelbots{$_}{$busy_note}{busy} } keys %notechannelbots);
+
+ push @candidates, [$bot, $score, $noteofftime];
+ }
+
+ # we found one?
+
+ if(@candidates)
+ {
+ @candidates = sort { $a->[1] <=> $b->[1] } @candidates;
+ my ($bot, $score, $offtime) = @{(pop @candidates)};
+ my $oldchan = $bot->{busy}->[0];
+ my $oldnote = $bot->{busy}->[1];
+ busybot_note_off $offtime - $notetime, $oldchan, $oldnote;
+ my $canplay = busybot_note_on_bot $bot, $time, $channel, $program, $note, 0, 1;
+ die "Canplay but not?"
+ if $canplay <= 0;
+ warn "Made $channel:$note play by stopping $oldchan:$oldnote";
+ $notechannelbots{$channel}{$note} = $bot;
+ return 1;
+ }
+ }
+
+ die "noalloc\n"
+ if $needalloc;
+
+ if(@epicfailbots)