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