SCDoc: Use proper static string constants instead of comparing string literals.
[supercollider.git] / HelpSource / Tutorials / Streams-Patterns-Events7.schelp
blob124ad7ab993b000b3ee428b03266c7314df16dc9
1 title:: Understanding Streams, Patterns and Events - Part 7
2 summary:: Practical Considerations
3 related:: Tutorials/Streams-Patterns-Events1, Tutorials/Streams-Patterns-Events2, Tutorials/Streams-Patterns-Events3, Tutorials/Streams-Patterns-Events4, Tutorials/Streams-Patterns-Events5, Tutorials/Streams-Patterns-Events6
4 categories:: Streams-Patterns-Events>Understanding-Streams-Patterns-and-Events
6 section::Practical Considerations
8 subsection::Using your own ~instrument
10 code::
12 SynthDef(\help_SPE7_BerlinB, { arg i_out=0, freq = 80, amp = 0.2, pan=0;
13         var out, a, b;
14         amp = Decay2.kr(Impulse.kr(0), 0.05, 8, amp);
15         out = RLPF.ar(
16                 LFPulse.ar(freq, 0, SinOsc.kr(0.12,[0,0.5pi],0.48,0.5), amp),
17                 freq * SinOsc.kr(0.21,0,4,8),
18                 0.07
19         );
20         #a, b = out;
21         DetectSilence.ar(a, 0.0001, doneAction: 2);
22         Out.ar(i_out, Mix.ar(PanAz.ar(4, [a, b], [pan, pan+1])));
23 }).add;
25 SynthDef(\help_SPE7_CFString1, { arg i_out, freq = 360, gate = 1, pan, amp=0.1;
26         var out, eg, fc, osc, a, b, w;
27         fc = LinExp.kr(LFNoise1.kr(Rand(0.25,0.4)), -1,1,500,2000);
28         osc = Mix.fill(8, { LFSaw.ar(freq * [Rand(0.99,1.01),Rand(0.99,1.01)], 0, amp) }).distort * 0.2;
29         eg = EnvGen.kr(Env.asr(1,1,1), gate, doneAction:2);
30         out = eg * RLPF.ar(osc, fc, 0.1);
31         #a, b = out;
32         Out.ar(i_out, Mix.ar(PanAz.ar(4, [a, b], [pan, pan+0.3])));
33 }).add;
37 link::Classes/Pattern#-play:: creates an link::Classes/EventStreamPlayer:: for you and also supplies a default protoEvent. If you were using your own event model you would just pass in your own protoEvent to the play method.
39 code::
41 Pbind(
42         \instrument, Prand([\help_SPE7_BerlinB, \help_SPE7_CFString1],inf),
43         \degree, Pseq([0,1,2,4,6,3,4,8],inf),
44         \dur, 0.8,
45         \octave, 3,
46         \amp, 0.03
47 ).play; // this returns an EventStreamPlayer
51 subsection::Defining your own message bindings
53 The default event prototype uses a code::msgFunc:: to determine which bindings to pass to the server. Synthdefs that have been stored in a link::Classes/SynthDescLib:: ("synth description library") construct the code::msgFunc:: automatically. The default event looks up the instrument name in a SynthDescLib of your choosing (using the code::\synthLib:: key). Normally only the global SynthDescLib is used; if code::\synthLib:: is empty, the global library is the default.
55 You should not send or load synthdefs that you plan to use with patterns. Instead, store them in a SynthDescLib.
57 code::
58 // saves .scsyndef file on disk (like .load), and adds description to the global library
59 SynthDef(...).store;
61 // adds description to the global library; no file is saved (like .send)
62 SynthDef(...).add;
65 If you don't do this, nondefault bindings will be ignored. In that case, you can provide a custom code::msgFunc:: manually. Here's an example:
67 code::
69 SynthDef(\help_SPE4_CFString2, { arg i_out, freq = 360, gate = 1, pan, amp=0.1, dorkarg=1;
70         var out, eg, fc, osc, a, b, w;
71         fc = LinExp.kr(LFNoise1.kr(Rand(0.25,0.4)), -1,1,500,2000);
72         osc = Mix.fill(8, { LFSaw.ar(freq * [Rand(0.99,1.01),Rand(0.99,1.01)], 0, amp * dorkarg ) }).distort * 0.2;
73         eg = EnvGen.kr(Env.asr(1,1,1), gate, doneAction:2);
74         out = eg * RLPF.ar(osc, fc, 0.1);
75         #a, b = out;
76         Out.ar(i_out, Mix.ar(PanAz.ar(4, [a, b], [pan, pan+0.3])));
77 }).send(s);     // change .send(s) to .add
81 As you can see I have added code::dorkarg:: to the arglist of the SynthDef from earlier.
83 code::
85 Pbind(
86         \instrument, \help_SPE4_CFString2,
87         \degree, Pseq([0,1,2,4,6,3,4,8],inf),
88         \dur, 0.4,
89         \octave, 3,
90         \amp, 0.03,
91         \dorkarg, Pseq([1,0,1],inf) // silence every second note - doesn't work
92 ).play;
96 code::dorkarg:: is ignored because the SynthDef was not properly code::.add::'d and consequently, the event prototype doesn't know that code::dorkarg:: is important.
98 You could also supply a code::\msgFunc:: that includes code::dorkarg:: :
100 code::
102 Pbind(
103         \instrument, \help_SPE4_CFString2,
104         \degree, Pseq([0,1,2,4,6,3,4,8],inf),
105         \dur, 0.4,
106         \octave, 3,
107         \amp, 0.03,
108         \dorkarg, Pseq([1,0,1],inf), // silence every second note - now works
109         \msgFunc, { arg out = 0, freq = 440, amp = 0.1, pan = 0, vol = 1,
110                         dorkarg = 1;
111                 [\out, out, \freq, freq, \amp, amp, \pan, pan, \vol, vol,
112                         \dorkarg, dorkarg];
113         }
114 ).play;
118 But this is quite clumsy. It is strongly recommended to get into the habit of using code::.add:: for all SynthDefs intended for use with Patterns.
120 The other option you have if you will be using unspecified bindings, is of course to define an event with the appropriate code::msgFunc:: as default. Have a look at Event's source, it's easy, and it's cleaner than passing in the code::msgFunc:: every time.
122 subsection::Manipulating an EventStreamPlayer in Realtime
124 code::
126 p = Pbind(
127         \degree, Pwhite(0,12),
128         \dur, 0.2,
129         \instrument, \help_SPE4_CFString2
131 // e is an EventStreamPlayer
132 e = p.play;
136 // you can change the stream at any point in time
137 e.stream = Pbind(
138         \degree, Pseq([0,1,2,4,6,3,4,8],inf),
139         \dur, Prand([0.2,0.4,0.8],inf),
140         \amp, 0.05,
141         \octave, 5,
142         \instrument, \help_SPE7_BerlinB, // you can also use a symbol
143         \ctranspose, 0
144 ).asStream;
148 e.stream = Pbind(
149         [\degree, \dur], Pseq(
150                 [
151                         Pseq([[0,0.1],[2,0.1],[3,0.1],[4,0.1],[5,0.8]],2),
152                         Ptuple([Pxrand([6,7,8,9],4), 0.4]),
153                         Ptuple([Pseq([9,8,7,6,5,4,3,2]), 0.2])
154                 ], inf
155         ),
156         \amp, 0.05,
157         \octave, 5,
158         \instrument, \Help_SPE7_CFString1
159 ).asStream;
163 The following methods are possible because an link::Classes/EventStreamPlayer:: is a link::Classes/PauseStream:: :
165 code::
166 e.mute;         // keeps playing, but replaces notes with rests
168 e.unmute;
170 e.reset;        // reset the stream.
172 e.pause;        // will resume where paused.
174 e.resume;
176 e.stop;         // will reset before resume.
178 e.resume;