; max window size for error recovery @global $err_horizon := 2 ; variable assigned by max (message setvar) containing the pitch of the current midi note @global $pitch_in := 0 // tests if the pitch $p belongs to the pitches recorded in tab $pitches at the ranks [$i, $i+$hor] @fun_def @mem($pitches, $p, $i, $hor) { @local $j := $i+1 @local $res := -1 @local $lownote := 0 loop { if ($j < $pitches.size()) { $lownote := $pitches[$j].abs().min() if (($p == $lownote) || (($p * 100) == $lownote)) { if ($res < 0) { $res := $j - $i + 1 } } } $j += 1 } during[$hor #] return $res } @proc_def ::midi_follower($end_position) { @local $i ; index of the next expected pitch @local $tab_pitch ; pitch table of the score @local $last_beat_pos, $err_state, $printdebug $printdebug := false $err_state := false if ($printdebug) { print "MF>>> start midi follower at beat " $RNOW } $last_beat_pos := $BEAT_POS $i := ($RNOW == 0 ? 0 : 1) // stop audio following (just in case) antescofo::suivi 0 $tab_pitch := @make_pitch_tab($RNOW, $end_position) if ($printdebug) { print "MF>>> premier element est: " ($tab_pitch[$i, 0]) } whenever($pitch_in) { ; print "MF> I received" ($pitch_in ) ($tab_pitch[$i, 0]) "$i" $i "tableau" (@flatten($tab_pitch)) @local $lownote := $tab_pitch[$i].abs().min() if (($pitch_in == $lownote) || ($pitch_in * 100 == $lownote)) { antescofo::nextevent $err_state := false if ($printdebug) { print "MF>>> next event" $RNOW } } else { if ($printdebug) { print "MF>>> " $pitch_in "is not the expected pitch which is " ($tab_pitch[$i].abs().min()) } if (!$err_state) { $err_state := true } else { @local $j, $rtempo $j := @mem($tab_pitch, $pitch_in, $i, $err_horizon) $rtempo := $RT_TEMPO if (0 < $j) { ; we fast forward $j times loop 0.01 s { if (true || $printdebug) { print "MF>>> catch-up" $j "on error" } antescofo::nextevent antescofo::tempo $rtempo } during [$j #] $err_state := false } } } } while($i < @size($tab_pitch)) ; we record the change on $i on a $BEAT_POS event ; because it allows to use next_event from "outside" as well whenever($BEAT_POS == $BEAT_POS) { if ($last_beat_pos == $BEAT_POS && $RNOW!= 0) { if ($printdebug) { print "MF>>> then" } } else { if ($printdebug) { print "MF>>> else" last_beat_pos $last_beat_pos $BEAT_POS } $i := $i+1 } if ($printdebug) { print "MF>>> $BEAT_POS" $BEAT_POS i $i } $last_beat_pos := $BEAT_POS } while($i < @size($tab_pitch)) group @tight { ; at the end, we switch to audio following ($end_position - $RNOW) antescofo::suivi 1 if ($printdebug) { print "MF>>> suivi on" $RNOW } abort ::midi_follower } } ///////////////////////////////////////////////////////////////////////////////// // TEST /* { $cpt := 0 $notes := [60, [71, 61], 63, 75, [36+1, 44], 38, 59, 40] 1 loop 1 { if ($notes[$cpt].is_tab()) { @local $i := $cpt, $j := 0 loop 0.01 { ; print emit ($notes[$i, $j]) at $NOW cpt $i index $j $pitch_in := $notes[$i, $j] $j += 1 } during [$notes[$i].size()#] } else { $pitch_in := $notes[$cpt] } ; print TIC $pitch_in $cpt += 1 } during[$notes.size()] } ; ------------------------------------------------------------ whenever ($LAST_EVENT_LABEL) { print event $LAST_EVENT_LABEL $NOW } ::midi_follower($end_partition) NOTE 60 1.0 bar1 print START with bar1 chord (61 71) 1.0 bar2 ; NOTE 61 1.0 bar2 print rattrapage de bar2 $NOW NOTE 63 1.0 bar3 NOTE 75 1.0 bar4 CHORD (36 44) 1.0 bar5 NOTE 38 1.0 bar6 NOTE 59 1 bar7 NOTE 40 1 bar8 NOTE 0 1 end_partition print DONE DONE */