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
|
title:: Understanding Streams, Patterns and Events - Part 2
summary:: Patterns Introduction
related:: Tutorials/Streams-Patterns-Events1, Tutorials/Streams-Patterns-Events3, Tutorials/Streams-Patterns-Events4, Tutorials/Streams-Patterns-Events5, Tutorials/Streams-Patterns-Events6, Tutorials/Streams-Patterns-Events7
categories:: Tutorials>Streams-Patterns-Events
section::Patterns
Often one wants to be able to create multiple streams from a single stream specification. Patterns are just a way to make multiple Streams from a single specification, like a cookie cutter. A pattern can be any object that responds to the code::asStream:: message by creating a link::Classes/Stream::. Once again there is a default implementation in class link::Classes/Object:: of asStream that simply returns the receiver as its own stream. Thus any object is by default a pattern that returns itself as a stream when sent the asStream message.
code::
(
a = 7.asStream;
a.postln;
a.next.postln;
)
::
section::Pattern and its subclasses
There is a class named link::Classes/Pattern:: that provides more functionality for the concept of a pattern.
A link::Classes/Pfunc:: is a Pattern that returns a link::Classes/FuncStream::. The same function arguments are supplied as are supplied to FuncStream.
code::
(
var a, b;
a = Pfunc.new({ #[1, 2, 3, 4].choose });
b = a.asStream; // make a stream from the pattern
5.do({ b.next.postln; }); // print 5 values from the stream
)
::
A link::Classes/Prout:: is a Pattern that returns a link::Classes/Routine::. The same function argument is supplied as is supplied to Routine.
code::
(
var a, b, c;
a = Prout.new({
3.do({ arg i; 3.rand.yield; })
});
// make two streams from the pattern
b = a.asStream;
c = a.asStream;
4.do({ b.next.postln; }); // print 4 values from first stream
4.do({ c.next.postln; }); // print 4 values from second stream
)
::
A link::Classes/Pseries:: is a Pattern that generates an arithmetic series.
code::
(
var a, b;
a = Pseries.new(10, 3, 8); // stream starts at 10, steps by 3 and has length 8
b = a.asStream;
9.do({ b.next.postln; }); // print 9 values from stream
)
::
link::Classes/Pgeom:: is a Pattern that generates a geometric series.
code::
(
var a, b;
a = Pgeom.new(10, 3, 8); // stream starts at 10, steps by factor of 3 and has length 8
b = a.asStream;
9.do({ b.next.postln; }); // print 9 values from stream
)
::
section::Math operations on Patterns
Patterns also respond to math operators by returning patterns that respond to code::asStream:: with appropriately modified streams.
Applying a unary operator to a pattern
code::
(
var a, b, c;
a = Pseries.new(0,1,10); // a is a pattern whose stream counts from 0 to 9
b = a.squared; // pattern b is a square of the pattern a
c = b.asStream;
12.do({ c.next.postln; });
)
::
Using a binary operator on a pattern
code::
(
var a, b, c;
a = Pseries.new(0,1,10); // a is a pattern whose stream counts from 0 to 9
b = a + 100; // add a constant value to pattern a
c = b.asStream;
12.do({ c.next.postln; });
)
::
section::Filtering operations on patterns
Patterns also respond to the messages code::collect::, code::select::, and code::reject:: by returning a new link::Classes/Pattern::.
The code::collect:: message returns a Pattern whose link::Classes/Stream:: is modified by a function in the same way as the collect message sent to a Collection returns a modified Collection.
code::
(
var a, b, c;
// a is a pattern whose stream counts from 0 to 9
a = Pseries.new(0,1,10);
// b is a pattern whose stream adds 100 to even values
b = a.collect({ arg item; if (item.even, { item + 100 },{ item }); });
c = b.asStream;
6.do({ c.next.postln; });
)
::
The code::select:: message creates a pattern whose stream passes only items that return true from a user supplied function.
code::
(
var a, b, c;
// a is a pattern whose stream counts from 0 to 9
a = Pseries.new(0,1,10);
// b is a pattern whose stream only returns the odd values
b = a.select({ arg item; item.odd; });
c = b.asStream;
6.do({ c.next.postln; });
)
::
The code::reject:: message creates a pattern whose stream passes only items that return false from a user supplied function.
code::
(
var a, b, c;
// a is a pattern whose stream counts from 0 to 9
a = Pseries.new(0,1,10);
// b is a pattern whose stream that only returns the non-odd values
b = a.reject({ arg item; item.odd; });
c = b.asStream;
6.do({ c.next.postln; });
)
::
section::Making Music with Patterns
Here is a variation of the example given in part 1 that uses a link::Classes/Pattern:: to create two instances of the random melody stream.
code::
(
s = Server.local;
SynthDef(\help_SPE2, { arg i_out=0, sustain=1, freq;
var out;
out = RLPF.ar(
LFSaw.ar( freq ),
LFNoise1.kr(1, 36, 110).midicps,
0.1
) * EnvGen.kr( Env.perc, levelScale: 0.3,
timeScale: sustain, doneAction: Done.freeSelf );
//out = [out, DelayN.ar(out, 0.04, 0.04) ];
4.do({ out = AllpassN.ar(out, 0.05, [0.05.rand, 0.05.rand], 4) });
Out.ar( i_out, out );
}).send(s);
)
(
// streams as a sequence of pitches
var pattern, streams, dur, durDiff;
dur = 1/7;
durDiff = 3;
pattern = Prout.new({
loop({
if (0.5.coin, {
#[ 24,31,36,43,48,55 ].do({ arg fifth; fifth.yield });
});
rrand(2,5).do({
// varying arpeggio
60.yield;
#[63,65].choose.yield;
67.yield;
#[70,72,74].choose.yield;
});
// random high melody
rrand(3,9).do({ #[74,75,77,79,81].choose.yield });
});
});
streams = [
(pattern - Pfunc.new({ #[12, 7, 7, 0].choose })).midicps.asStream,
pattern.midicps.asStream
];
Routine({
loop({
Synth( \help_SPE2, [ \freq, streams.at(0).next, \sustain, dur * durDiff ] );
durDiff.do({
Synth( \help_SPE2, [ \freq, streams.at(1).next, \sustain, dur ] );
dur.wait;
});
})
}).play
)
::
To go to the next file:
link::Tutorials/Streams-Patterns-Events3::
|