44// TODO: steerable generation. gui for ranges, temperatures;
55// MIDI controller for pitch set
66
7+ // TODO: keep track of pending model predictions so there are no races
8+ // whenever a note is played, feed it to the model
9+ // count the number of pending predictions
10+ // if a note is played while there are pending predictions, cancel them
11+ // ideally, would signal python to interrupt computation
12+ // less complicated: just ignore the results when they come in
13+ // there are pending predictions and pending notes:
14+ // pending predictions need to be ignored when they come in
15+ // pending notes need to be unscheduled
16+
17+ // TODO: pitch blacklist option
18+ // use case: forbid model from releasing a note held by the player
19+
720(
821~gui = false ;
922MIDIIn .connectAll;
@@ -49,6 +62,9 @@ b.sendMsg("/predictor/predict",
4962// duet with the model
5063// feeds the model's predictions back to it as well as player input
5164(
65+ ~pending_predictions = 0 ;
66+ ~synths = nil !128 ;
67+ ~player_held = false !128 ;
5268~step = 0 ;
5369~gate = 1 ;
5470t = nil ;
@@ -66,23 +82,56 @@ MIDIdef.program(\switch, {
6682 ~gate = 0 ;
6783 SystemClock .clear;
6884 b.sendMsg("/predictor/reset" );
69- y. release;
85+ ~synths .do( _ . release( 1.0 )) ;
7086 SystemClock .clear;
7187 ~step = 0 ;
7288 };
7389 ~gate .postln;
7490});
7591
76-
7792// MIDI from controller
78- MIDIdef .noteOn( \input , {
93+ MIDIdef .noteOff( \input_off , {
7994 arg val, num, chan, src;
8095 var t2 = Process .elapsedTime;
8196 var dt = t2-(t?(t2-~delay )); //time since last note
8297
8398 // cancel any pending predictions
8499 SystemClock .clear;
100+ ~pending_predictions .postln;
101+ //get a new prediction in light of current note
102+ b.sendMsg("/predictor/predict" ,
103+ \pitch , num, \time , dt, \vel , 0 ,
104+ \allow_start , false , \allow_end , false ,
105+ \pitch_temp , 0.5 , \rhythm_temp , 0.5 , \timing_temp , 0.1 ,
106+ \min_time , ~delay , \max_time , 5
107+ // \fix_time, ~delay
108+ );
109+ ~pending_predictions = ~pending_predictions +1 ;
110+
111+ // release the previous note
112+ ~synths [num]!?(_ .release(0.05 ));
113+ ~synths [num] = nil ;
114+
115+ // post the current note
116+ [\player , dt, num, 0 ].postln;
117+
118+ // mark time of current note
119+ t = t2;
120+ ~player_t = t;
85121
122+ ~step = ~step + 1 ;
123+
124+ ~player_held [num] = false ;
125+
126+ });
127+ MIDIdef .noteOn(\input_on , {
128+ arg val, num, chan, src;
129+ var t2 = Process .elapsedTime;
130+ var dt = t2-(t?(t2-~delay )); //time since last note
131+
132+ // cancel any pending predictions
133+ SystemClock .clear;
134+ ~pending_predictions .postln;
86135 //get a new prediction in light of current note
87136 b.sendMsg("/predictor/predict" ,
88137 \pitch , num, \time , dt, \vel , val,
@@ -91,12 +140,14 @@ MIDIdef.noteOn(\input, {
91140 \min_time , ~delay , \max_time , 5
92141 // \fix_time, ~delay
93142 );
143+ ~pending_predictions = ~pending_predictions +1 ;
144+
94145
95146 // release the previous note
96- y .release(0.05 );
147+ ~synths [num]!?( _ .release(0.05 ) );
97148
98149 // play the current note
99- y = Synth (\pluck , [\freq , num.midicps, \vel , val/127 ]);//.release(1);
150+ ~synths [num] = Synth (\pluck , [\freq , num.midicps, \vel , val/127 ]);//.release(1);
100151
101152 // post the current note
102153 [\player , dt, num, val].postln;
@@ -107,6 +158,8 @@ MIDIdef.noteOn(\input, {
107158
108159 ~step = ~step + 1 ;
109160 // ~step = 0;
161+
162+ ~player_held [num] = true ;
110163});
111164
112165// OSC return from python
@@ -115,15 +168,21 @@ OSCdef(\return, {
115168 var num = msg[1 ]; // MIDI number of predicted note
116169 var dt = msg[2 ]; // time to predicted note
117170 var val = msg[3 ]; // velocity 0-127
171+ var step = msg[4 ];
118172
119173 // time-to-next note gets 'censored' by the model
120174 // when over a threshold, in this case 10 seconds,
121175 // meaning it just predicts 10s rather than any longer time
122176 var censor = dt>=10.0 ;
123177
178+ ~pending_predictions = ~pending_predictions -1 ;
179+ [\step , step].postln;
180+
181+
124182 censor.if{
125183 // if the predicted time is > 10 seconds, don't schedule it, just stop.
126- \censor .postln; y.release(3.0 )
184+ \censor .postln;
185+ // ~synths[num]!?(_.release(3.0));
127186 }{
128187 // schedule the predicted note
129188 SystemClock .sched(dt-~delay , {
@@ -135,7 +194,7 @@ OSCdef(\return, {
135194 // in this case don't schedule a note, and reset the model
136195 // b.sendMsg("/predictor/reset");
137196 //release the last note
138- y. release(1.0 );
197+ ~synths .do( _ . release(1.0 ) );
139198 // unset time so next note will have dt=0
140199 // t = nil;
141200 // \reset.postln
@@ -145,28 +204,27 @@ OSCdef(\return, {
145204 // (there shouldn't be any, but might
146205 // be if there was a lot of fast MIDI input)
147206 SystemClock .clear;
207+ ~pending_predictions .postln;
148208 // feed model its own prediction as input
149209 b.sendMsg("/predictor/predict" ,
150210 \pitch , num, \time , dt_actual, \vel , val,
151211 \allow_start , false , \allow_end , true ,
152212 \pitch_temp , 0.7 , \rhythm_temp , 0.7 , \timing_temp , 0.1 ,
153213 \min_time , ~delay *2 , \max_time , 5 ,
154- \min_vel , 10
214+ // \min_vel, 10
155215 // \fix_time, ((~step+1)%3==0).if{0.6}{0} // triads
156216 // \fix_time, (~step%8)*0.1 // specific rhythm
157217
158218 );
159- // release the previous note
160- (dt<3e-2 ).if{
161- // if the time delay is very small, slow release for chord
162- y.release(1.0 )
219+ ~pending_predictions = ~pending_predictions +1 ;
220+
221+ // play the current note
222+ ~synths [num]!?(_ .release(0.05 ));
223+ (val > 0 ).if{
224+ ~synths [num] = Synth (\pluck , [\freq , num.midicps, \vel , val/127 ])
163225 }{
164- // otherwise release fast to play a melody
165- y.release(0.05 )
226+ ~synths [num] = nil
166227 };
167- // play the current note
168- y = Synth (\pluck , [
169- \freq , num.midicps, \vel , val/127 ]);//.release(1);
170228 // post the current note
171229 [\model , dt, num, val].postln;
172230 // mark the actual time of current note
@@ -186,11 +244,10 @@ OSCdef(\return, {
186244}, "/prediction" , nil );
187245)
188246
189-
190247(
191248// send a note manually if you don't have a MIDI controller:
192249SystemClock .clear;
193- y. release(0.2 );
250+ ~synths .do( _ . release(1.0 ) );
194251b.sendMsg("/predictor/reset" );
195252{MIDIdef .all[\input ].func.value(99 , 60 )}.defer(0.5 );
196253SystemClock .clear;
0 commit comments