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.
