supernova: fix for small audio vector sizes
[supercollider.git] / HelpSource / Tutorials / Streams-Patterns-Events4.schelp
bloba5ad1e9bc8ac99bc36f7ca06961e1553a2a7d923
1 title:: Understanding Streams, Patterns and Events - Part 4
2 summary:: Environment & Event
3 related:: Tutorials/Streams-Patterns-Events1, Tutorials/Streams-Patterns-Events2, Tutorials/Streams-Patterns-Events3, Tutorials/Streams-Patterns-Events5, Tutorials/Streams-Patterns-Events6, Tutorials/Streams-Patterns-Events7
4 categories:: Streams-Patterns-Events>Understanding-Streams-Patterns-and-Events
6 The preceeding sections showed how to use Streams and Patterns to generate complex sequences of values for a single parameter at a time.
8 This section covers Environments and Events, which are used to build a symbolic event framework for patterns, allowing you to control all aspects of a composition using patterns.
10 section::Environment
12 An link::Classes/Environment:: is an link::Classes/IdentityDictionary:: mapping link::Classes/Symbol::s to values. There is always one current Environment which is stored in the code::currentEnvironment:: class variable of class link::Classes/Object::.
14 Symbol and value pairs may be put into the current Environment as follows:
16 code::
17 currentEnvironment.put(\myvariable, 999);
20 and retrieved from the current Environment as follows:
22 code::
23 currentEnvironment.at(\myvariable).postln;
26 The compiler provides a shorthand for the two constructs above.
28 code::
29 ~myvariable = 888;
32 is equivalent to:
34 code::
35 currentEnvironment.put(\myvariable, 888);
38 and:
40 code::
41 ~myvariable.postln;
44 is equivalent to:
46 code::
47 currentEnvironment.at(\myvariable).postln;
50 section::Making an Environment
52 Environment has a class method strong::make:: which can be used to create an link::Classes/Environment:: and fill it with values. What strong::make:: does is temporarily replace the current Environment with a new one, call your function where you fill the Environment with values, then it replaces the previous current Environment and returns you the new one.
54 code::
56 var a;
57 a = Environment.make({
58         ~a = 100;
59         ~b = 200;
60         ~c = 300;
61 });
62 a.postln;
66 section::Using an Environment
68 The instance method strong::use:: lets you temporarily replace the current link::Classes/Environment:: with one you have made. The strong::use:: method returns the result of your function instead of the Environment like strong::make:: does.
70 code::
72 var a;
73 a = Environment.make({
74         ~a = 10;
75         ~b = 200;
76         ~c = 3000;
77 });
78 a.use({
79         ~a + ~b + ~c
80 }).postln;
84 There is also a strong::use:: class method for when you want to make and use the result from an link::Classes/Environment:: directly.
86 code::
88 var a;
89 a = Environment.use({
90         ~a = 10;
91         ~b = 200;
92         ~c = 3000;
93         ~a + ~b + ~c
94 }).postln;
98 section::Calling Functions with arguments from the current Environment
100 It is possible to call a link::Classes/Function:: and have it look up any unspecified argument values from the current Environment. This is done with the strong::valueEnvir:: and strong::valueArrayEnvir:: methods. These methods will, for any unspecified argument value, look in the current Environment for a symbol with the same name as the argument. If the argument is not found then whatever the function defines as the default value for that argument is used.
102 code::
104 var f;
106 // define a function
107 f = { arg x, y, z; [x, y, z].postln; };
109 Environment.use({
110         ~x = 7;
111         ~y = 8;
112         ~z = 9;
114         f.valueEnvir(1, 2, 3);  // all values supplied
115         f.valueEnvir(1, 2);     // z is looked up in the current Environment
116         f.valueEnvir(1);        // y and z are looked up in the current Environment
117         f.valueEnvir;           // all arguments are looked up in the current Environment
118         f.valueEnvir(z: 1);     // x and y are looked up in the current Environment
123 Here is a somewhat contrived example of how the Environment might be used to manufacture SynthDefs. Even though the three functions below have the freq, amp and pan args declared in different orders it does not matter, because valueEnvir looks them up in the environment.
125 code::
127 var a, b, c, n;
129 n = 40;
130 a = { arg freq, amp, pan;
131         Pan2.ar(SinOsc.ar(freq), pan, amp);
133 b = { arg amp, pan, freq;
134         Pan2.ar(RLPF.ar(Saw.ar(freq), freq * 6, 0.1), pan, amp);
136 c = { arg pan, freq, amp;
137         Pan2.ar(Resonz.ar(GrayNoise.ar, freq * 2, 0.1), pan, amp * 2);
140 Task({
141         n.do({ arg i;
142                 SynthDef("Help-SPE4-EnvirDef-" ++ i.asString, {
143                         var out;
144                         Environment.use({
145                                         // set values in the environment
146                                 ~freq = exprand(80, 600);
147                                 ~amp = 0.1 + 0.3.rand;
148                                 ~pan = 1.0.rand2;
150                                         // call a randomly chosen instrument function
151                                         // with values from the environment
152                                 out = [a,b,c].choose.valueEnvir;
153                         });
154                         out = CombC.ar(out, 0.2, 0.2, 3, 1, out);
155                         out = out * EnvGen.kr(
156                                 Env.sine, doneAction: 2, timeScale: 1.0 + 6.0.rand, levelScale: 0.3
157                         );
158                         Out.ar( 0, out );
159                 }).send(s);
160                 0.02.wait;
161         });
162         loop({
163                 Synth( "Help-SPE4-EnvirDef-" ++ n.rand.asString );
164                 (0.5 + 2.0.rand).wait;
165         });
166 }).play;
170 section::Event
172 The class link::Classes/Event:: is a subclass of link::Classes/Environment::. Events are mappings of Symbols representing names of parameters for a musical event to their value. This lets you put any information you want into an event.
174 The class getter method strong::default:: retrieves the default prototype event which has been initialized with values for many useful parameters. It represents only one possible event model. You are free to create your own, however it would be good to understand the one provided first so that you can see what can be done.
176 A prototype event is a default event which will be transformed by the streams returned by patterns. Compositions produced by event patterns are created entirely from transformations of copies of a single protoEvent.
178 footnote::
179 It's all a part of the Big Note, but don't tell the pigs and ponies.
182 section::Value Patterns, Event Patterns and Pbind
184 The patterns discussed in parts 2 and 3 are known as "value patterns" because their streams return a single value for each call to strong::next::. Here we introduce "event patterns" which once turned into streams, return an link::Classes/Event:: for each call to strong::next::.
186 The class link::Classes/Pbind:: provides a bridge between value patterns and event patterns. It binds symbols in each event to values obtained from a pattern. Pbind takes arguments in pairs, the first of a pair being a link::Classes/Symbol:: and the second being a value link::Classes/Pattern::. Any object can act as a Pattern, so you can use constants as the pattern ( see code::\amp:: in the example below ).
188 The Pbind stream returns nil whenever the first one of its streams ends.
190 code::
191 Pbind( \freq, Pseq([440,880]) ).play
194 An event stream is created for a Pattern by sending it the code::asStream:: message. What Pbind does is to produce a stream which puts the values for its symbols into the event, possibly overwriting previous bindings to those symbols:
196 code::
197 t = Pbind( \freq, Pseq([440,880]) ).asStream;
198 t.next(Event.default);
199 t.next(Event.default);
200 t.next(Event.default);
203 When calling link::Classes/Pattern#-play:: an link::Classes/EventStreamPlayer:: is automatically generated which handles scheduling as well as passing the protoEvent into the event stream.
205 section::EventStreamPlayer
207 The class link::Classes/EventStreamPlayer:: is a subclass of link::Classes/PauseStream::. A PauseStream is just a wrapper for a stream allowing to play, stop, start it, etc...
209 EventStreamPlayers are initialized using the event stream returned by Pbind-asStream, as well as with a protoEvent. The EventStreamPlayer passes in a strong::protoEvent::, at each call to strong::next:: on the Pbind stream. The Pbind stream copies the event to pass down and back up the tree of pattern streams so that each stream can modify it.
211 An EventStreamPlayer is itself a stream which returns scalars (numbers) which are used by the clock to schedule its next invocation. At every call to EventStreamPlayer-next by the clock, the player gets its delta values by querying the Event after it has been returned by the Pbind stream traversal.
213 section::Changes in SC3
215 In SC2, you called asEventStream on an Pattern and you'd get a stream which actually returned events.
217 In SC3, if you want an event stream proper you call asStream on the Event Pattern. This will give you a stream of events which you can then use to initialize an EventStreamPlayer object. You don't however need to worry about that because it is usually done for you in Pattern's play method. Also changed is that you do not pass in your protoEvent through the asStream method. It is passed in for you by the EventStreamPlayer at each call to next on the stream.
219 Here you can see what the stream returned from a Pbind looks like.
221 code::
223 var pattern, stream;
225         // bind Symbol xyz to values obtained from a pattern
226 pattern = Pbind(
227         \xyz, Pseq([1, 2, 3])
230         // create a stream of events for the Pbind pattern.
231 stream = pattern.asStream;
233         // event Streams require a prototype event as input.
234         // this example uses an empty Event as a prototype
235 4.do({ stream.next(Event.new).postln; });
239 Here is an example with more bindings.
241 code::
243 var pattern, stream;
245 pattern = Pbind(
246         \abc, Prand([6, 7, 8, 9], inf ),
247         \xyz, Pseq([1, 2, 3], 2 ),
248         \uuu, 999 // a constant represents an infinite sequence of itself
251 stream = pattern.asStream;
253 7.do({ stream.next(Event.new).postln; });
257 The ListPatterns discussed in part 3 can be put around Event Streams to create sequences of Event Streams.
259 code::
261 var pattern, stream;
262 pattern =
263         Pseq([
264                 Pbind( \abc, Pseq([1, 2, 3])),
265                 Pbind( \def, Pseq([4, 5, 6])),
266                 Pbind( \xyz, Pseq([7, 8, 9]))
267         ]);
268 stream = pattern.asStream;
269 10.do({ stream.next(Event.new).postln; });
273 var pattern, stream;
274 pattern =
275         Prand([
276                 Pbind( \abc, Pseq([1, 2, 3])),
277                 Pbind( \def, Pseq([4, 5, 6])),
278                 Pbind( \xyz, Pseq([7, 8, 9]))
279         ], 3);
280 stream = pattern.asStream;
281 10.do({ stream.next(Event.new).postln; });
285 To go to the next file:
286 link::Tutorials/Streams-Patterns-Events5::