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

Commit 7317351

Browse files
comments, don't play incomplete events
1 parent 02aa9bd commit 7317351

2 files changed

Lines changed: 71 additions & 46 deletions

File tree

examples/notochord/tidalcycles/notochord.tidal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ p "choosepitch"
99

1010
hush
1111

12-
p "chooseinst"
12+
p "chooseinst"
1313
$ ncinst "-1"--"7 [-1]@7"
1414
<| ncpitch (run 8 + 48)
1515
# ncvel (range 30 120 $ sine)

examples/notochord/tidalcycles/tidal-notochord.scd

Lines changed: 70 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ MIDIClient.init;
1212
~m2 = MIDIOut.newByName("IAC Driver", "Bus 2").latency_(0);
1313
~m3 = MIDIOut.newByName("IAC Driver", "Bus 3").latency_(0);
1414
~prog2portchan = { arg prog;
15+
\inst.postln;
16+
prog.postln;
17+
prog.class.postln;
18+
(prog-1 /8).asInteger.postln;
19+
(prog-1 %8).asInteger.postln;
1520
case
1621
{prog==0}{"can't convert start token".postln}
1722
{prog<=128}{
@@ -64,23 +69,14 @@ MIDIClient.init;
6469
var port = port_chan[\port];
6570
var chan = port_chan[\chan];
6671
(vel>0).if{
67-
port.noteOn(chan, pitch, vel.max(1));
72+
port.noteOn(chan, pitch, vel);
6873
}{
6974
port.noteOff(chan, pitch);
7075
}
71-
}
76+
};
7277
)
7378

74-
OSCdef.trace(false);
75-
76-
77-
// ok so how to actually 'schedule' things?
78-
// SystemClock one-offs should do?
79-
// schedule notochord-processing of each event for time of
80-
// oLatency before occurence
81-
// also schedule the actual event to occur
82-
// and set up a handle for the OSC return handler to
83-
// fill in any predicted fields
79+
// OSCdef.trace(false);
8480

8581
(
8682
~oLatency = 0.1; // must match value at tidal boot
@@ -96,47 +92,41 @@ OSCdef(\from_tidal, {
9692
var args = Dictionary.newFrom(msg[1..]);
9793
// `time` is the start time
9894
// args[\delta] is the duration
99-
\from_tidal.postln;
95+
\tidal_feed.postln;
10096
time.postln;
10197
// [time - Process.elapsedTime].postln;
10298
args.postln;
10399

104-
// note-on events should arrive from tidal in the order they happen
105-
// but note-offs do not, since they are implicit in duration of notes
106-
// the only guarantee is nothing needs to happen sooner than tidal's
107-
// oLatency parameter
108-
// so we can schedule all note-on and note-offs as soon as they arrive
109-
// (without all sub-events filled in, possibly)
110-
111-
// anthing scheduled sooner than ncLatency (e.g. 100ms)
112-
// is 'frozen' and ready to (query_)feed notochord.
113-
114-
// schedule note-on
115-
~schedule_event.(
116-
time, args[\ncinst], args[\ncpitch], args[\ncvel]
117-
);
118-
// schedule note-off
119-
~schedule_event.(
120-
time+args[\delta], args[\ncinst], args[\ncpitch], 0
121-
);
122-
123-
// pop those off in order of occurence, and call feed or query_feed
124-
// in the case of query_feed, pass in some handle which tells the
125-
// return OSCdef where to put the result in the scheduler
100+
((args[\ncreset]?0) > 0).if{
101+
\reset.postln;
102+
SystemClock.schedAbs(time-~ncLatency, {
103+
~python.sendMsg("/notochord/reset");
104+
~release_all.(0);
105+
});
106+
}{
126107

127-
// finally pop completed events as they cross the current time,
108+
// note-on events should arrive from tidal in the order they happen
109+
// but note-offs do not, since they are implicit in duration of notes
110+
// the only guarantee is nothing needs to happen sooner than tidal's
111+
// oLatency parameter
112+
// so we can schedule all note-on and note-offs as soon as they arrive
113+
// (without all sub-events filled in, possibly)
128114

115+
// anthing scheduled sooner than ncLatency (e.g. 100ms)
116+
// is 'frozen' and ready to (query_)feed notochord.
129117

130-
//when instrument, pitch or velocity is negative or nil,
131-
//query notochord
118+
~schedule_events.(
119+
time, args[\delta], args[\ncinst], args[\ncpitch], args[\ncvel]
120+
);
121+
}
132122

133123
}, "/notochord/tidal_feed");
134124

135125
// create event handle,
136126
// schedule processing by notochord,
137127
// and schedule triggering the event
138-
~schedule_event = {
139-
arg time, inst, pitch, vel;
128+
~schedule_events = {
129+
arg time, delta, inst, pitch, vel;
140130

141131
var handle = ~event_idx.asSymbol;
142132
var event = (inst:inst?(-1), pitch:pitch?(-1), vel:vel?(-1));
@@ -153,7 +143,7 @@ OSCdef(\from_tidal, {
153143
(event[\time]<0).if{"warning: dt < 0".postln};
154144

155145
// if any parts not determined
156-
(event.collect(_<0).values.reduce('||')).if{
146+
~any_missing.(event).if{
157147
// query_feed
158148
// include handle to event for writing the result
159149
~python.sendMsg(
@@ -168,22 +158,52 @@ OSCdef(\from_tidal, {
168158
}
169159
});
170160

171-
// schedule event
161+
// schedule note-on
172162
SystemClock.schedAbs(time, {
173163
// send to the synthesizer (MIDI bus or hacked dirth synth?)
174-
\playing.postln; event.postln;
164+
\note_on.postln; event.postln;
165+
~any_missing.(event).if{
166+
"incomplete note-on".postln;
167+
}{
168+
~midi_send.(event[\inst], event[\pitch], event[\vel]);
169+
}
170+
});
171+
172+
// schedule note-off: fully determined once note-on is, since timing
173+
// comes from tidal. may revisit if allowing notochord to do micro-timing
174+
// in the future
175+
SystemClock.schedAbs(time+delta, {
176+
// send to the synthesizer (MIDI bus or hacked dirth synth?)
177+
\note_off.postln; event.postln;
178+
~any_missing.(event).if{
179+
"incomplete note-off".postln;
180+
}{
181+
~midi_send.(event[\inst], event[\pitch], 0);
182+
}
175183
});
176184

177185
};
186+
// check if any sub-events not predicted yet
187+
~any_missing = {arg event;
188+
event.collect(_<0).values.reduce('||')
189+
};
178190

179191
// convert an event (constructed in schedule_event from data received from tidal)
180192
// to query keyword args for notochord
181193
~event_to_query = {
182194
arg event;
183195
var query = List[];
196+
// if instrument is given
184197
(event[\inst]>=0).if{query.add(\fix_instrument); query.add(event[\inst])};
198+
// if pitch is given
185199
(event[\pitch]>=0).if{query.add(\fix_pitch); query.add(event[\pitch])};
186-
(event[\vel]>=0).if{query.add(\fix_vel); query.add(event[\vel])};
200+
// if velocity is given
201+
(event[\vel]>=0).if{
202+
query.add(\fix_vel); query.add(event[\vel])
203+
}{
204+
// only predicting note-ons
205+
query.add(\min_vel); query.add(1)
206+
};
187207
query.add(\fix_time); query.add(event[\time]);
188208
query
189209
};
@@ -202,7 +222,6 @@ OSCdef(\from_python, {
202222

203223
~events.removeAt(\handle);
204224

205-
206225
// TODO: spit a warning if it trying to update
207226
// an event which should have happened already)
208227
// (thisThread.seconds > ...).if{
@@ -212,3 +231,9 @@ OSCdef(\from_python, {
212231
}, "notochord/query_return");
213232

214233
)
234+
235+
236+
(
237+
~python.sendMsg("/notochord/reset");
238+
~release_all.(0);
239+
)

0 commit comments

Comments
 (0)