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

Commit 9f38576

Browse files
examples, docstrings, comments
1 parent bc773e9 commit 9f38576

4 files changed

Lines changed: 53 additions & 65 deletions

File tree

examples/notepredictor/autopitch.scd

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
// in this example the Linnstrument displays an interface to perform pitches
2+
// by their likelihood under the NotePredictor model instead of by MIDI number
3+
4+
// the grid in the upper left gives control of pitches from
5+
// the single most likely (cyan) to least likely (pink).
6+
7+
// the white pad samples pitches stochastically from the model.
8+
// the lone yellow pad resets the model.
9+
10+
// model predictions are conditioned on performed timing and velocity.
11+
112
(
213
~use_linn = true; // use linnstrument
314
~gui = false; // use keyboard GUI
@@ -93,7 +104,7 @@ b.sendMsg("/predictor/predict",
93104
(
94105
~gate = 1;
95106

96-
~reset = {
107+
~model_reset = {
97108
~last_pitch = nil;
98109
~last_dt = nil;
99110
~last_vel = nil;
@@ -105,7 +116,7 @@ b.sendMsg("/predictor/predict",
105116

106117
};
107118

108-
~reset.();
119+
~model_reset.();
109120

110121
// footswitch
111122
MIDIdef.program(\switch, {
@@ -178,7 +189,7 @@ OSCdef(\return, {
178189
}, "/prediction", nil);
179190
)
180191

181-
~reset.()
192+
~model_reset.()
182193
// send a note manually if you don't have a midi controller
183194
MIDIdef.all[\input].func.(64, 16) //velocity, "pitch"
184195

Lines changed: 30 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// in this example, the most likely next pitches (according to NotePredictor)
2+
// are drawn on the Linnstrument as you play
3+
14
(
25
~use_linn = true; // use linnstrument
36
~gui = false; // use keyboard GUI
@@ -19,7 +22,7 @@ Server.default.options.outDevice_("Built-in Output");
1922
// release the previous note
2023
~synth!?(_.release(0.1));
2124

22-
// attack the current note with the old pitch
25+
// attack the current note
2326
~synth = Synth(\pluck, [\freq, freq, \vel, amp]);
2427

2528
//
@@ -46,40 +49,11 @@ s.waitForBoot{
4649
};
4750
)
4851

49-
~linn_reset.()
50-
51-
52-
// ~linn.setNoteOnAction({}); ~linn.setNoteOffAction({});
53-
54-
55-
// measure round-trip latency
56-
(
57-
OSCdef(\return, {
58-
arg msg, time, addr, recvPort;
59-
(Process.elapsedTime - t).postln;
60-
}, '/prediction', nil);
61-
t = Process.elapsedTime;
62-
b.sendMsg("/predictor/predict",
63-
\pitch, 60+12.rand, \time, 0, \vel, 0,
64-
\index_pitch, 0,
65-
\sweep_time, true,
66-
// \fix_time, 0,
67-
// \fix_vel, 0
68-
);
69-
)
70-
71-
72-
// NetAddr.localAddr // retrieve the current IP and port
73-
// thisProcess.openPorts; // list all open ports
74-
75-
// model chooses pitches
7652
(
7753
// set the delay for more precise timing
7854
~delay = 0.2;
7955

80-
~gate = 1;
81-
82-
~reset = {
56+
~model_reset = {
8357
t = Process.elapsedTime;
8458
b.sendMsg("/predictor/reset");
8559
// ~synth!?{~synth.free};
@@ -90,33 +64,18 @@ b.sendMsg("/predictor/predict",
9064
\pitch_topk, 5);
9165

9266
};
93-
~reset.();
67+
~model_reset.();
9468
~linn_reset.();
9569

96-
// footswitch
97-
MIDIdef.program(\switch, {
98-
arg num, chan, src;
99-
num.switch
100-
{1}{~gate = 0}
101-
{2}{~gate = 1}
102-
{3}{
103-
~gate = 0;
104-
SystemClock.clear;
105-
b.sendMsg("/predictor/reset");
106-
y.release;
107-
SystemClock.clear;
108-
};
109-
~gate.postln;
110-
});
111-
11270
// OSC return from python
11371
OSCdef(\return, {
11472
arg msg, time, addr, recvPort;
11573
var pitches, dts;
11674
var last_pitch = nil;
11775
var colormap = [8,3,10,9,1];
11876
var color = 0;
119-
// whhyyyy are OSC arrays not handled by supercollider
77+
78+
// OSC arrays are not handled automatically by supercollider
12079
var stack = List[List[]];
12180
msg.do{arg item;
12281
case
@@ -125,6 +84,7 @@ OSCdef(\return, {
12584
{true}{stack.last.add(item)};
12685
};
12786
msg = stack[0];
87+
12888
pitches = msg[1];
12989
dts = msg[2];
13090

@@ -141,9 +101,27 @@ OSCdef(\return, {
141101
}, "/prediction", nil);
142102
)
143103

144-
~reset.()
104+
105+
106+
// ======
107+
// additional useful blocks
108+
109+
~model_reset.()
145110
// send a note manually if you don't have a midi controller
146111
MIDIdef.all[\input].func.(64, 16) //velocity, "pitch"
147112

148-
// load another model
149-
// b.sendMsg("/predictor/load", "/path/to/checkpoint");
113+
// measure round-trip latency
114+
(
115+
OSCdef(\return, {
116+
arg msg, time, addr, recvPort;
117+
(Process.elapsedTime - t).postln;
118+
}, '/prediction', nil);
119+
t = Process.elapsedTime;
120+
b.sendMsg("/predictor/predict",
121+
\pitch, 60+12.rand, \time, 0, \vel, 0,
122+
\index_pitch, 0,
123+
\sweep_time, true,
124+
// \fix_time, 0,
125+
// \fix_vel, 0
126+
);
127+
)

examples/notepredictor/midi-duet.scd

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// in this example the model's predictions are fed back to it so it plays itself.
2+
// the player can add notes as well and start/stop/reset the model with a footswitch.
3+
14
(
25
~gui = false;
36
MIDIIn.connectAll;
@@ -36,9 +39,6 @@ b.sendMsg("/predictor/predict", \pitch, 60+12.rand, \time, 0, \vel, 0);
3639
// set the delay for more precise timing
3740
~delay = 0.015;
3841

39-
// NetAddr.localAddr // retrieve the current IP and port
40-
// thisProcess.openPorts; // list all open ports
41-
4242
// duet with the model
4343
// feeds the model's predictions back to it as well as player input
4444
(

notepredictor/notepredictor/model.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,9 @@ def predict(self,
321321
time: float. elapsed time since previous note.
322322
vel: float. (possibly dequantized) MIDI velocity from 0-127 inclusive.
323323
fix_*: same as above, but to fix a value for the predicted note
324-
index_pitch: Optional[int]. if not None, determinisitically take the nth
324+
pitch_topk: Optional[int]. if not None, instead of sampling pitch, stack
325+
the top k most likely pitches along the batch dimension
326+
index_pitch: Optional[int]. if not None, deterministically take the nth
325327
most likely pitch instead of sampling.
326328
allow_start: if False, zero probability for sampling the start token
327329
allow_end: if False, zero probaility for sampling the end token
@@ -372,7 +374,7 @@ def predict(self,
372374

373375
# permute h_tgt, embs, modalities
374376
# if any modalities are determined, embed them
375-
# sort constrained modailities before unconstrained
377+
# sort constrained modalities before unconstrained
376378
# TODO: option to skip modalities
377379
det_idx, cons_idx, uncons_idx = [], [], []
378380
for i,(item, embed) in enumerate(zip(fix, self.embeddings)):
@@ -414,21 +416,18 @@ def predict(self,
414416
context.append(embed(pred))
415417
det_idx.append(i)
416418

417-
418419
pred_pitch = predicted[iperm[0]]
419420
pred_time = predicted[iperm[1]]
420421
pred_vel = predicted[iperm[2]]
421422

422-
print(pred_time.shape)
423-
print(pred_pitch.shape)
424-
print(pred_vel.shape)
425-
426423
if sweep_time or pitch_topk:
424+
# return lists of predictions
427425
pred_pitch = [x.item() for x in pred_pitch]
428426
pred_time = [x.item() for x in pred_time]
429427
pred_vel = [x.item() for x in pred_vel]
430428
print(pred_time, pred_pitch, pred_vel)
431429
else:
430+
# return single predictions
432431
pred_pitch = pred_pitch.item()
433432
pred_time = pred_time.item()
434433
pred_vel = pred_vel.item()

0 commit comments

Comments
 (0)