Skip to content
This repository was archived by the owner on Nov 23, 2023. It is now read-only.

Commit 788452f

Browse files
update generate.scd for noteoff
1 parent 4293a49 commit 788452f

File tree

3 files changed

+82
-20
lines changed

3 files changed

+82
-20
lines changed

examples/notepredictor/generate.scd

Lines changed: 76 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@
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;
922
MIDIIn.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;
5470
t = 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:
192249
SystemClock.clear;
193-
y.release(0.2);
250+
~synths.do(_.release(1.0));
194251
b.sendMsg("/predictor/reset");
195252
{MIDIdef.all[\input].func.value(99, 60)}.defer(0.5);
196253
SystemClock.clear;

examples/notepredictor/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def _(address, **kw):
3939
print('no model loaded')
4040
else:
4141
r = predictor.predict(**kw)
42-
return '/prediction', r['pitch'], r['time'], r['velocity']
42+
return '/prediction', r['pitch'], r['time'], r['velocity'], r['step']
4343

4444
elif cmd=="reset":
4545
if predictor is None:

notepredictor/notepredictor/model.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ def __init__(self,
201201
# persistent RNN state for inference
202202
for n,t in zip(self.cell_state_names(), self.initial_state):
203203
self.register_buffer(n, t.clone())
204+
self.step = 0
204205

205206
def cell_state_names(self):
206207
return tuple(f'cell_state_{i}' for i in range(len(self.initial_state)))
@@ -515,7 +516,10 @@ def predict(self,
515516
pred_pitch = pred_pitch.item()
516517
pred_time = pred_time.item()
517518
pred_vel = pred_vel.item()
519+
520+
self.step += 1
518521
return {
522+
'step': self.step,
519523
'pitch': pred_pitch,
520524
'time': pred_time,
521525
'velocity': pred_vel,
@@ -531,6 +535,7 @@ def reset(self, start=True):
531535
start: if True, send a start token through the model with dt=0
532536
but discard the prediction
533537
"""
538+
self.step = 0
534539
for n,t in zip(self.cell_state_names(), self.initial_state):
535540
getattr(self, n)[:] = t.detach()
536541
if start:

0 commit comments

Comments
 (0)