This file is indexed.

/usr/share/SuperCollider/HelpSource/Classes/Routine.schelp is in supercollider-common 1:3.6.3~repack-5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
class::Routine
categories::Core>Kernel
summary:: Functions that can return in the middle and then resume where they left off
related:: Classes/Stream

description::
Routines are functions that can return in the middle and then resume where
they left off when called again. Routines can be used to implement co-routines
as found in Scheme and some other languages.
Routines are useful for writing things that behave like Streams.
Routines inherit behaviour for math operations and filtering from Stream.

classMethods::

method::new

Creates a Routine instance with the given function.

discussion::
The stackSize and random seed may be overridden if desired.

code::
a = Routine.new({ 1.yield; 2.yield; });
a.next.postln;
a.next.postln;
a.next.postln;
::

instanceMethods::

method::next

The Routine function is either started if it has not been called yet, or it is
resumed from where it left off. The argument inval is passed as the argument
to the Routine function if it is being started, or as the result of the code::yield::
method if it is being resumed from a yield.

returns:: The value that the Routine yields.

discussion::
There are basically 2 conditions for a Routine: one is when the routine starts. The other case is
that the routine continues after it has yielded.

When the routine starts (by calling the above methods), you are passing in a first inval.
This inval is accessible as the routine function argument:

code::
Routine { arg inval;
	inval.postln;
}.value("hello routine");
::

When there is a yield in the routine, the next time you call next (or synonym), the routine continues
from there, and you get a chance to pass in a value from the outside. To access that value within the
continuing routine, you have to assign the result of the yield call to a variable. Typically the name inval (or inevent) is reused, instead of declaring a variable like "valuePassedInbyYield":

code::
(
r = Routine { arg inval;
	inval.postln;
	inval = 123.yield;
	inval.postln;
}
)

r.value("hello routine");
r.value("goodbye world");
::

Typically a routine uses a multiple yield, in which the inval is reassigned repeatedly:

code::
(
r = Routine { arg inval;
	inval.postln;
	5.do { arg i;
		inval = (i + 10).yield;
		inval.postln;
	}
}
)
(
5.do {
	r.value("hello routine").postln;
}
)
::

method::value

same as code::next::

method::resume

same as code::next::

method::reset

Causes the Routine to start from the beginning next time it is called.
A Routine cannot reset itself except by calling the code::yieldAndReset:: method.

See also code::yield, yieldAndReset, alwaysYield:: in class link::Classes/Object::

If a Routine's function returns then it will always yield nil until reset.

method::play

In the SuperCollider application, a Routine can be played using a link::Classes/Clock::, as can any link::Classes/Stream::.
every time the Routine yields, it should do so with a float, the clock will interpret that, usually
pausing for that many seconds, and then resume the routine, passing it the clock's current time.

argument::clock
a Clock, TempoClock by default

argument::quant
see the link::Classes/Quant:: helpfile

discussion::
using link::Classes/Object#idle#Object:idle:: within a routine, return values until this time is over. Time is measured relative to the thread's clock.
code::
// for 6 seconds, return 200, then continue
(
r = Routine {
		199.yield;
		189.yield;
		200.idle(6);
		199.yield;
		189.yield;
};

fork {
	loop {
		r.value.postln;
		1.wait;
	}
}
);

// the value can also be a stream or a function
(
r = Routine {
		199.yield;
		189.yield;
		Routine { 100.do { |i| i.yield } }.idle(6);
		199.yield;
		189.yield;
};

fork {
	loop {
		r.value.postln;
		1.wait;
	}
}
);
::

subsection::Accessible instance variables

Routine inherits from link::Classes/Thread::, which allows access to some of its state:

code::
(
r = Routine { arg inval;
	loop {
		// thisThread refers to the routine.
		postf("beats: % seconds: % time: % \n",
			thisThread.beats, thisThread.seconds, Main.elapsedTime
		);
		1.0.yield;

	}
}.play;
)

r.stop;
r.beats;
r.seconds;
r.clock;
::

method::beats

returns:: The elapsed beats (logical time) of the routine. The beats do not proceed when the routine is not playing.

method::seconds

returns:: The elapsed seconds (logical time) of the routine. The seconds do not proceed when the routine is not playing, it is the converted beat value.

method::clock

returns:: The thread's clock. If it has not played, it is the SystemClock.

examples::

code::
(
var r, outval;
r = Routine.new({ arg inval;
	("->inval was " ++ inval).postln;
	inval = 1.yield;
	("->inval was " ++ inval).postln;
	inval = 2.yield;
	("->inval was " ++ inval).postln;
	inval = 99.yield;
});

outval = r.next('a');
("<-outval was " ++ outval).postln;
outval = r.next('b');
("<-outval was " ++ outval).postln;
r.reset; "reset".postln;
outval = r.next('c');
("<-outval was " ++ outval).postln;
outval = r.next('d');
("<-outval was " ++ outval).postln;
outval = r.next('e');
("<-outval was " ++ outval).postln;
outval = r.next('f');
("<-outval was " ++ outval).postln;
)
::

code::
// wait

(
var r;
r = Routine {
	10.do({ arg a;
		a.postln;
		// Often you might see Wait being used to pause a routine
		// This waits for one second between each number
		1.wait;
	});
	// Wait half second before saying we're done
	0.5.wait;
	"done".postln;
}.play;
)
::

code::
// waitUntil

(
var r;
r = Routine {
	var times = { rrand(1.0, 10.0) }.dup(10) + thisThread.beats;
	times = times.sort;
	times.do({ arg a;
		waitUntil(a);
		a.postln;
	});
	// Wait half second before saying we're done
	0.5.wait;
	"done".postln;
}.play;
)
::

code::
// Using Routine to set button states on the fly.
(
var update, w, b;
w = SCWindow.new("State Window", Rect(150,SCWindow.screenBounds.height-140,380,60));

// a convenient way to set the button label
update = {
	|but, string| but.states = [[string.asString, Color.black, Color.red]];
	but.refresh;
};

b = SCButton(w, Rect(10,10,360,40));
b.font_(Font("Impact", 24));

update.value(b, "there is only one state");

// if an action should do something different each time it is called, a routine is the
// right thing to use. This is better than creating variables outside and setting them
// from the action function to keep state from one action to the next

b.action_(Routine { |butt|
	rrand(15, 45).do { |i|
		update.value(butt, "%. there is still only 1 state".format(i + 2));
		0.yield; // stop here
	};
	w.close;
});

w.front;
)
::

code::
// drawing in a window dynamcially with Pen
(
var w, much = 0.02, string, synth;

w = Window.new("swing", Rect(100, 100, 300, 500)).front;
w.view.background_(Color.new255(153, 255, 102).vary);

string = "swing ".dup(24).join;

w.drawFunc = Routine {
	var i = 0;
	var size = 40;
	var func = { |i, j| sin(i * 0.07 + (j * 0.0023) + 1.5pi) * much + 1 };
	var scale;
	Pen.font = Font("Helvetica-Bold", 40);
	loop {
		i = i + 1;
		string.do {	|char, j|

			scale = func.value(i, j).dup(6);

			Pen.fillColor = Color.new255(0, 120, 120).vary;
			Pen.matrix = scale * #[1, 0, 0, 1, 1, 0];
			Pen.stringAtPoint(char.asString,
				((size * (j % 9)) - 10) @ (size * (j div: 9))
			);
		};
		0.yield // stop here, return something unimportant
	}
};

fork { while { w.isClosed.not } { defer { w.refresh }; 0.04.wait; } };

w.front;

)
::