/usr/share/SuperCollider/HelpSource/Classes/Stream.schelp is in supercollider-common 1:3.8.0~repack-2.
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 | class:: Stream
summary:: Stream is the base class for classes that define streams
related:: Classes/Routine, Classes/FuncStream, Classes/EventStreamPlayer
categories:: Streams-Patterns-Events
description::
Stream is an abstract class that is not used directly. The following attempts to document some aspects of the use of Streams for music generation.
subsection::Overview
A Stream represents a sequence of values that are obtained incrementally by repeated strong::next:: messages. A Stream can be restarted with a strong::reset:: message. (Not all streams actually implement reset semantics.)
The class link::Classes/Object:: defines strong::next:: to return the object itself. Thus every object can be viewed as a stream and most simply stream themselves.
In SuperCollider, Streams are primarily used for handling text and for generating music.
subsection::FuncStream(nextFunction, resetFunction)
A link::Classes/Function:: defines a stream consisting of the Function itself, a link::Classes/FuncStream:: defines a stream that consists of emphasis::evaluations:: of its nextFunction.
code::
// Example 1: a Function vs. a FuncStream
(
f = { 33.rand };
x = FuncStream(f);
10.do({ [f.next, x.next].postln });
)
::
code::
// Example 2: the reset function
(
f = { 33.rand };
x = FuncStream(f, {thisThread.randSeed_(345)});
x.reset;
10.do({ [f.next, x.next].postln });
x.reset;
10.do({ [f.next, x.next].postln });
)
::
subsection::Routine(nextFunction, stacksize)
In a link::Classes/FuncStream::, the nextFunction runs through to completion for each element of the stream. In a link::Classes/Routine::, the nextFunction returns values with strong::yield:: and resumes execution (when it receives a strong::next:: message) at the expression following the yield. This allows a sequence of expressions in the function definition to represent a sequence of distinct events, like a musical score.
code::
// example
(
x = Routine({
1.yield;
2.yield;
3.yield;
});
4.do({ x.next.postln });
)
::
Once the nextFunction completes execution, the Routine simply yields nil repeatedly. Control structures (such as strong::do:: or strong::while::) can be used within the nextFunction in a manner analogous to repeat marks in a score.
code::
// example
(
x = Routine({
4.do({
[1,2,3,4].do({ arg i; i.yield; });
});
});
17.do({ x.next.postln });
)
::
subsection::Playing streams
Because streams respond like functions to the value message, they can be used as a scheduling task.
code::
// compare:
// a function, returning 0.5
(
SystemClock.sched(0.0,
{ "***".postln; 0.5 }
);
)
// a stream, returning 0.5 and 0.1
(
SystemClock.sched(0.0,
Routine({ loop {
"***".postln; 0.5.yield;
"_*_".postln; 0.1.yield;
} });
);
)
// this is the reason why 'wait' works the same (for numbers) like 'yield'
(
SystemClock.sched(0.0,
Routine({ loop {
"***".postln; 0.5.wait;
"_*_".postln; 0.1.wait;
} });
);
)
::
Streams that return strong::numbers:: can be played directly with the strong::play:: message.
code::
// play at the next beat, with offset 0.4
(
Routine({ loop {
"***".postln; 0.5.wait;
"_*_".postln; 0.1.wait;
} }).play(quant:[1, 0.4]);
)
::
Streams that return strong::Events:: need to be wrapped in an link::Classes/EventStreamPlayer::. The Event's strong::delta:: (can also be set by strong::dur::) is used as a scheduling beats value:
code::
// play at the next beat, with offset 0.4
(
Routine({ loop {
"///".postln; (delta:0.5).yield;
"_/_".postln; (delta: 0.1).wait;
} }).asEventStreamPlayer.play;
)
::
subsection::Iteration
The method link::#-do:: effectively 'plays' a stream by iterating all of its contents.
And the following messages create a stream by filtering another stream in some way: link::#-collect::, link::#-reject::, link::#-select::, link::#-dot::, link::#-interlace::, link::#-appendStream::, link::#-embedInStream::, link::#-trace::.
subsection::Composite Streams
Routines can be strong::embedded:: in each other, using link::#-embedInStream:: :
code::
// example
(
x = Routine({
2.do({
[1,2,3,4].do({ arg i; i.yield; });
});
});
y = Routine({
100.yield;
30.yield;
x.embedInStream;
440.yield;
1910.yield;
});
17.do({ y.next.postln });
)
::
Routines can be strong::concatenated:: just like Streams:
code::
(
x = Routine({
2.do({
[1,2,3,4].do({ arg i; i.yield; });
});
});
y = Routine({
100.yield;
30.yield;
});
z = x ++ y;
17.do({ z.next.postln });
)
::
Routines can be strong::combined:: with the composition operator <>
code::
(
x = Routine({ arg inval;
2.do({
[1,2,3,4].do({ arg i;
if(inval.isNil) { nil.alwaysYield };
inval = (i * inval).yield;
});
});
});
y = Routine({
100.yield;
30.yield;
4.do { 1.0.rand.yield };
});
z = x <> y;
17.do({ z.value.postln }); // call .value here, as this is a function.
)
::
Composite Streams can be defined as combinations of Streams using the unary and binary messages.
subsection::Unary messages
Streams support most of the unary messages defined in link::Classes/AbstractFunction:: :
code::
(
a = Routine({ 20.do({ 33.rand.yield }) });
b = Routine({ [-100,00,300,400].do({ arg v; v.yield}) });
c = b.neg; // define a composite stream
// enumerate and perform all of the unary messages:
[
\neg, \reciprocal, \bitNot, \abs, \asFloat, \asInteger, \ceil,
\floor, \frac, \sign, \squared, \cubed, \sqrt, \exp, \midicps,
\cpsmidi, \midiratio, \ratiomidi, \ampdb, \dbamp, \octcps,
\cpsoct, \log, \log2, \log10, \sin, \cos, \tan, \asin, \acos, \atan,
\sinh, \cosh, \tanh, \rand, \rand2, \linrand, \bilinrand, \sum3rand,
\distort, \softclip, \coin, \even, \odd, \isPositive, \isNegative,
\isStrictlyPositive
]
.do({ arg msg;
postf("\n msg: % \n", msg);
b.reset.perform(msg).do({arg v; v.post; " ".post;});
});
nil;
)
::
subsection::Binary messages
Streams support the following binary messages defined in link::Classes/AbstractFunction:: :
code::
(
a = Routine({ 20.do({ 33.rand.yield }) });
b = Routine({ [-100,00,300,400].do({ arg v; v.yield}) });
[
'+' , '-' , '*', '/', \div, '%', '**', \min, \max, '<', '<=', '>', '>=', '&', '|',
\bitXor, \lcm, \gcd, \round, \trunc, \atan2,
\hypot, '>>', '+>>', \ring1, \ring2, \ring3, \ring4,
\difsqr, \sumsqr, \sqrdif, \absdif, \amclip,
\scaleneg, \clip2, \excess, '<!', \rrand, \exprand
]
.do({ arg msg;
postf("\n msg: % \n", msg);
b.reset.perform(msg).do({ arg v; v.post; " ".post; });
});
nil;
)
::
InstanceMethods::
method::play
Streams that return strong::numbers:: can be played directly with the strong::play:: message. Streams that return strong::events:: need to be wrapped in an link::Classes/EventStreamPlayer::. See link::#-asEventStreamPlayer::.
argument::clock
a clock. link::Classes/TempoClock:: by default.
argument::quant
either a number strong::n:: (quantize to strong::n:: beats), or an array strong::[n, m]:: (quantize to n beats, with offset m).
method::do
iterate until a nil is encountered.
warning::
Applying do to an endless stream will lock up the interpreter!
::
method::collect
iterate indefinitely.
method::reject
return only those elements for which function.value(element) is false.
method::select
return only those elements for which function.value(element) is true.
method::dot
return function.value(this.next, stream.next) for each element.
method::interlace
iterate all of stream for each element of this. Combine the values using function.
method::appendStream
append stream after this returns nil. The same like ++
method::embedInStream
iterate all of this from within whatever Stream definition it is called.
method::trace
print out the results of a stream while returning the original values.
argument::key
when streaming events, post only this key.
argument::printStream
printOn this stream (default: link::Classes/Post::).
argument::prefix
string added to the printout to separate different streams.
|