File: Streams-Patterns-Events7.schelp

package info (click to toggle)
supercollider 1%3A3.13.0%2Brepack-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 80,292 kB
  • sloc: cpp: 476,363; lisp: 84,680; ansic: 77,685; sh: 25,509; python: 7,909; makefile: 3,440; perl: 1,964; javascript: 974; xml: 826; java: 677; yacc: 314; lex: 175; objc: 152; ruby: 136
file content (179 lines) | stat: -rw-r--r-- 5,660 bytes parent folder | download | duplicates (2)
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
title:: Understanding Streams, Patterns and Events - Part 7
summary:: Practical Considerations
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
categories:: Tutorials>Streams-Patterns-Events

section::Practical Considerations

subsection::Using your own instrument

code::
(
SynthDef(\help_SPE7_BerlinB, { arg i_out=0, freq = 80, amp = 0.2, pan=0;
	var out, a, b;
	amp = Decay2.kr(Impulse.kr(0), 0.05, 8, amp);
	out = RLPF.ar(
		LFPulse.ar(freq, 0, SinOsc.kr(0.12,[0,0.5pi],0.48,0.5), amp),
		freq * SinOsc.kr(0.21,0,4,8),
		0.07
	);
	#a, b = out;
	DetectSilence.ar(a, 0.0001, doneAction: Done.freeSelf);
	Out.ar(i_out, Mix.ar(PanAz.ar(4, [a, b], [pan, pan+1])));
}).add;

SynthDef(\help_SPE7_CFString1, { arg i_out, freq = 360, gate = 1, pan, amp=0.1;
	var out, eg, fc, osc, a, b, w;
	fc = LinExp.kr(LFNoise1.kr(Rand(0.25,0.4)), -1,1,500,2000);
	osc = Mix.fill(8, { LFSaw.ar(freq * [Rand(0.99,1.01),Rand(0.99,1.01)], 0, amp) }).distort * 0.2;
	eg = EnvGen.kr(Env.asr(1,1,1), gate, doneAction: Done.freeSelf);
	out = eg * RLPF.ar(osc, fc, 0.1);
	#a, b = out;
	Out.ar(i_out, Mix.ar(PanAz.ar(4, [a, b], [pan, pan+0.3])));
}).add;
)
::

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.

code::
(
Pbind(
	\instrument, Prand([\help_SPE7_BerlinB, \help_SPE7_CFString1],inf),
	\degree, Pseq([0,1,2,4,6,3,4,8],inf),
	\dur, 0.8,
	\octave, 3,
	\amp, 0.03
).play; // this returns an EventStreamPlayer
)
::

subsection::Defining your own message bindings

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.

You should not send or load synthdefs that you plan to use with patterns. Instead, store them in a SynthDescLib.

code::
// saves .scsyndef file on disk (like .load), and adds description to the global library
SynthDef(...).store;

// adds description to the global library; no file is saved (like .send)
SynthDef(...).add;
::

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:

code::
(
SynthDef(\help_SPE4_CFString2, { arg i_out, freq = 360, gate = 1, pan, amp=0.1, dorkarg=1;
	var out, eg, fc, osc, a, b, w;
	fc = LinExp.kr(LFNoise1.kr(Rand(0.25,0.4)), -1,1,500,2000);
	osc = Mix.fill(8, { LFSaw.ar(freq * [Rand(0.99,1.01),Rand(0.99,1.01)], 0, amp * dorkarg ) }).distort * 0.2;
	eg = EnvGen.kr(Env.asr(1,1,1), gate, doneAction: Done.freeSelf);
	out = eg * RLPF.ar(osc, fc, 0.1);
	#a, b = out;
	Out.ar(i_out, Mix.ar(PanAz.ar(4, [a, b], [pan, pan+0.3])));
}).send(s);	// change .send(s) to .add
)
::

As you can see I have added code::dorkarg:: to the arglist of the SynthDef from earlier.

code::
(
Pbind(
	\instrument, \help_SPE4_CFString2,
	\degree, Pseq([0,1,2,4,6,3,4,8],inf),
	\dur, 0.4,
	\octave, 3,
	\amp, 0.03,
	\dorkarg, Pseq([1,0,1],inf) // silence every second note - doesn't work
).play;
)
::

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.

You could also supply a code::\msgFunc:: that includes code::dorkarg:: :

code::
(
Pbind(
	\instrument, \help_SPE4_CFString2,
	\degree, Pseq([0,1,2,4,6,3,4,8],inf),
	\dur, 0.4,
	\octave, 3,
	\amp, 0.03,
	\dorkarg, Pseq([1,0,1],inf), // silence every second note - now works
	\msgFunc, { arg out = 0, freq = 440, amp = 0.1, pan = 0, vol = 1,
			dorkarg = 1;
		[\out, out, \freq, freq, \amp, amp, \pan, pan, \vol, vol,
			\dorkarg, dorkarg];
	}
).play;
)
::

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.

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.

subsection::Manipulating an EventStreamPlayer in Realtime

code::
(
p = Pbind(
	\degree, Pwhite(0,12),
	\dur, 0.2,
	\instrument, \help_SPE4_CFString2
);
// e is an EventStreamPlayer
e = p.play;
)

(
// you can change the stream at any point in time
e.stream = Pbind(
	\degree, Pseq([0,1,2,4,6,3,4,8],inf),
	\dur, Prand([0.2,0.4,0.8],inf),
	\amp, 0.05,
	\octave, 5,
	\instrument, \help_SPE7_BerlinB, // you can also use a symbol
	\ctranspose, 0
).asStream;
)

(
e.stream = Pbind(
	[\degree, \dur], Pseq(
		[
			Pseq([[0,0.1],[2,0.1],[3,0.1],[4,0.1],[5,0.8]],2),
			Ptuple([Pxrand([6,7,8,9],4), 0.4]),
			Ptuple([Pseq([9,8,7,6,5,4,3,2]), 0.2])
		], inf
	),
	\amp, 0.05,
	\octave, 5,
	\instrument, \help_SPE7_CFString1
).asStream;
)
::

The following methods are possible because an link::Classes/EventStreamPlayer:: is a link::Classes/PauseStream:: :

code::
e.mute;		// keeps playing, but replaces notes with rests

e.unmute;

e.reset;	// reset the stream.

e.pause;	// will resume where paused.

e.resume;

e.stop;		// will reset before resume.

e.resume;
::