There's a very useful helpfile set for Streams Patterns and Events, which is available by looking for the helpfile for Streams.
We know what a pattern is, after looking at Pseq and he other Pthings. But what is a stream? "A stream represents a lazy sequence of values," says the helpfile "Understanding Streams, Patterns and Events - Part 1," which you should go read. Streams respond to the message next. Here's an example:
(
var stream;
stream = Pseq([1, 2, 3], 1).asStream;
3.do({
stream.next.postln;
})
)
Any kind of pattern can be converted to a stream by sending it the message asStream. This can be more useful than you might think. For example, if you have two threads stepping through the same data:
(
var stream, task1, task2;
stream = Pseq(["Mary", "had", "a", "little", "lamb", "whose", "fleece"], 1).asStream;
task1 = Task({
inf.do({
"task1: ".post;
stream.next.postln;
1.wait;
});
});
task2 = Task({
inf.do({
"task2: ".post;
stream.next.postln;
1.51.wait;
});
});
task1.play;
task2.play
)
The two tasks can strep through a shared list. However, note that the stream starts returning nil when it runs out of other data to return. You have to test for that:
(
var stream, task;
stream = Pseq(["Mary", "had", "a", "little", "lamb", "whose", "fleece"], 1).asStream;
task = { |id, wait|
var next;
Task({
next = stream.next;
{next.notNil}.while({
("task" ++ id ++ ": " ++ next). postln;
wait.wait;
next = stream.next;
});
});
};
task.value(1, 1).play;
task.value(2, 1.51).play
)
You can also do math on streams:
(
var stream, squared;
stream = Pseq([1, 2, 3], 1).asStream;
squared = stream.squared;
3.do({
squared.next.postln;
})
)
And you can do binary math operations on two streams:
(
var stream1, stream2, sum;
stream1 = Pseq([1, 2, 3], 1).asStream;
stream2 = Pseq([4, 5, 6], 1).asStream;
sum = stream1 + stream2;
3.do({
sum.next.postln;
})
)
You can use streams with Pbinds, but you have to wrap them in Prout or Pfunc:
(
var notes, pbind;
notes = Pseq([ 1/1, 3/2, 4/3, 9/8, 16/9, 5/4, 8/5 ].pyramid(1), 2).asStream;
notes = notes * 440;
pbind = { |dur = 0.5|
Pbind(
\dur, dur,
\freq, Pfunc({notes.next})
)
};
Ppar([pbind.value(0.5), pbind.value(0.751)]).play;
)
Note that when notes.next returns nil, the Pbind quits playing.
Summary
- Streams can be create from patterns. The respond to the message next.
- When streams run out of values, they start to return nil.
- Multiple tasks can access the same stream.
- You can do math on streams.
- Streams can be used in Pbinds, provided a function or a routine calls next
No comments:
Post a Comment