-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcrucial_tutorial.scd
322 lines (264 loc) · 9.58 KB
/
crucial_tutorial.scd
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
// intro to CrucialLibrary for SC Server
// _version: 101211, written 031209
// _tested on sc3.3, sc3.4
// note: to make it work with supercollider versions newer than 3.4,
//one need to install the cruciallib quark. the library is no longer
//included with the standard sc distribution.
//--
//this library is made by crucial (a.k.a. felix/timeblind). it's huge and
//this tutorial will only scratch a bit on the surface.
//check [CRUCIAL-LIBRARY] plus all helpfiles for more info.
//the two main concepts of this library are instruments and patches,
//here called [Instr] and [Patch]. an Instr is defined once and
//automatically loaded into the global Library. an Instr can be
//accessed from anywhere and is most often used in combo with
//Patch. Patch logically plays and combines instruments.
//at startup and after recompile the Library is usually pretty empty.
Library.postTree;
//anything can be stored in Library, but from here on we will
//concentrate on Instr. the following line will create and save an
//Instr in Library at address \test.
Instr(\test, {BrownNoise.ar(0.1)});
//again dump content of Library. it should list our test instrument
//under Instr.
Library.postTree;
//to play the Instr at address \test, look it up in the Library using
//the .at method and then .play.
s.boot;
a= Instr.at(\test).play;
a.stop
//this line will overwrite our Instr with another UGen graph.
Instr(\test, {WhiteNoise.ar(0.1)});
a= Instr.at(\test).play;
a.stop
//so the Library is sort of a global repository for Instr. the Instr
//address can also be multi level like in the following example.
//note the brackets.
Library.clear;
Instr([\testNoises, \brown], {BrownNoise.ar(0.1)});
Instr([\testNoises, \pink], {PinkNoise.ar(0.1)});
Instr([\testNoises, \white, \mono], {WhiteNoise.ar(0.1)});
Instr([\testNoises, \white, \stereo], {WhiteNoise.ar([0.1, 0.1])});
Library.postTree;
//multi level addressed Instr are accessed in this way...
a= Instr.at([\testNoises, \pink]).play;
a.stop
a= Instr.at([\testNoises, \white, \stereo]).play
a.stop
a= Instr.at([\testNoises, \white, \mono]).play
a.stop
//--
//when calling an Instr object it first searches the Library. if no
//matching name is found, it tries to load a file with the same name
//as the Instr address from the current Instr.dir folder. this is
//Document.dir++"Instr/" by default, which usually means a folder
//called Instr inside your main supercollider application directory.
//you can of course override this classvar as you like by pointing it
//to another folder.
Library.clear;
Instr.dir= "~/Documents/SuperCollider/myInstrFolder";
//now put a rtf, txt or scd file called "nameless" containing a valid
//Instr into the directory specified above. if nothing is found
//Instr.at(\nameless) returns nil.
a= Instr.at([\nameless, \nameless]).play //(try twice - breaks the first time)
a.stop
//--
//to make more interesting Instr you will need arguments. here is
//an extended version of the testNoise Instr with two arguments.
Instr(\testNoise, {|freq= 1000, mul= 0.5| LPF.ar(WhiteNoise.ar(mul), freq)});
//relying on argument defaults will set noise amplitude to 0.5 and
//low-pass filter's frequency to 1000
a= Instr.at(\testNoise).play;
a.stop
//(btw, as you may have noted there is no need for Out or In when
//using Instr. CrucialLibrary is smart and takes care of it for you.
//this also makes porting old SC2 code fairly easy.)
//there are a few different ways of supplying arguments. version 1:
a= {Instr.at(\testNoise).ar(250, 1)}.play;
a.free
//supplying arguments version 2:
a= {Instr.ar(\testNoise, [6000, 0.2])}.play;
a.free
//it is also possible to modulate inlets with other ugens!
a= {Instr.at(\testNoise).ar(FSinOsc.kr(1, 0, 500, 1000), 0.4)}.play;
a.free
//so as you see Instr also works within functions like {}.play and
//SynthDef. but then you do need an Out etc.
(
SynthDef(\testNoiseDef, {
Out.ar(0, Instr.at(\testNoise).ar(650, 1));
}).add
)
a= Synth(\testNoiseDef)
a.free
//anyway, now we can play many instances of the same Instr - all
//with their individual settings - at the same time.
(
a= {
Mix.ar([
Instr.ar(\testNoise, [FSinOsc.kr(1.2, 0, 100, 500), 0.25]),
Instr.ar(\testNoise, [9000, LFPulse.kr(2, 0, 0.2, 0.1)]),
Instr.ar(\testNoise, [150])
]);
}.play
)
a.free
//--
//Patch takes an Instr as an argument and plays it. normally you
//don't play Instr directly like we have above. create a Patch object
//and supply an Instr name argument instead.
Instr(\testSaw, {Saw.ar(100, 0.1)}); //create an Instr
a= Patch(\testSaw).play; //play the Instr
a.stop
//and with arguments... note the array.
Instr(\testSaw, {|freq, mul| Saw.ar(freq, mul)});
a= Patch(\testSaw, [200, 0.1]).play;
a.stop
//as shortcut and for testing, soundfunctions can also be directly
//written in a Patch like this... but that will actually build an Instr
//with a random name.
a= Patch({|freq, mul| Saw.ar(freq, mul)}, [150, 0.1]).play;
a.stop
//--
//the following lines creates two Instr, one effect and one sound
//source, and then patches them together.
Instr(\testNoise, {WhiteNoise.ar(0.2)});
Instr(\sweepfilter, {|audio| LPF.ar(audio, LFTri.kr(0.3, 0, 300, 800))});
a= Patch(\sweepfilter, [Patch(\testNoise)]).play
a.stop
//this will create one noisy Instr and two simple effects
(
Instr(\testNoise2, {|mul= 1.0| BrownNoise.ar(mul)});
Instr([\efx, \lowpass], {|audio, freq= 1000| LPF.ar(audio, freq)});
Instr([\efx, \delay], {|audio, delaytime= 1|
audio+CombN.ar(audio, 2, delaytime, 2)});
)
//let us first play the above running a repeating burst of noise
//through a lowpass effect. cutoff frequency is controlled with the
//mouse.
(
var source, cutoff;
source= Patch(\testNoise2, [Patch({LFPulse.kr(2, 0, 0.1, 0.3)})]);
cutoff= Patch({MouseX.kr(60, 20000, 'exponential')});
a= Patch([\efx, \lowpass], [source, cutoff]).play
)
a.stop
//secondly we add the delay Instr
(
var source, cutoff;
source= Patch(\testNoise2, [Patch({LFPulse.kr(2, 0, 0.1, 0.3)})]);
cutoff= Patch({MouseX.kr(60, 20000, 'exponential')});
a= Patch([\efx, \delay], [
Patch([\efx, \lowpass], [source, cutoff]),
0.4 //delaytime in seconds
]).play
)
a.stop
//last let us run the above example through another instance of the
//delay with a very short delaytime (0.01). i.e. same delay Instr
//used twice but with different settings.
(
var source, cutoff;
source= Patch(\testNoise2, [Patch({LFPulse.kr(2, 0, 0.1, 0.3)})]);
cutoff= Patch({MouseX.kr(60, 20000, 'exponential')});
a= Patch([\efx, \delay], [
Patch([\efx, \delay], [
Patch([\efx, \lowpass], [source, cutoff]),
0.4 //delaytime in seconds
]),
0.01 //delaytime in seconds
]).play
)
a.stop
//--
//multiple channels are easy to deal with when using Instr/Patch.
//here the argument Patch with two Mouse objects will expand the
//SinOsc Patch into two.
(
a= Patch({|freq= 400| SinOsc.ar(freq, 0, 0.1)}, [
Patch({[
MouseX.kr(60, 20000, 'exponential'),
MouseY.kr(60, 20000, 'exponential')
]})
]).play
)
a.stop
//and a stereo effect with a mono Patch argument will work in the
//same way.
(
a= Patch({|audio| audio*LFNoise0.kr([3, 2], 0.5, 0.5)}, [
Patch({SinOsc.ar(350, 0, 0.3)}) //mono sound source
]).play
)
a.stop
//also Crucial's NumChannels and Mono classes are sometimes
//useful. here mixing down from 7 to 2 channels.
(
var n= 7;
a= Patch({|audio|
NumChannels.ar(
audio*LFNoise0.kr(
Array.fill(n, {3.0.rrand(9.0).round(1.667)}),
0.4,
0.3
).max(0.0),
2
)
}, [
Patch({SinOsc.ar(Array.series(n, 90, 90), 0, 0.1)})
]).play
)
a.stop
//--
//then there is PlayerMixer for mixing patches
(
Instr(\testSine, {|freq= 1000, mul= 0.1| SinOsc.ar(freq, 0, mul)});
a= PlayerMixer([
Patch(\testSine, [400, 0.1]),
Patch(\testSine, [600, 0.08]),
Patch(\testSine, [1000, 0.06])
]);
)
a.play
a.stop
//--
//PlayerPool is another useful class. it lets you switch between
//patches.
(
Instr([\moreTestNoises, \brown], {BrownNoise.ar(0.1)});
Instr([\moreTestNoises, \pink], {PinkNoise.ar(0.1)});
Instr([\moreTestNoises, \white], {WhiteNoise.ar(0.1)});
a= PlayerPool([
Patch([\moreTestNoises, \brown]),
Patch([\moreTestNoises, \pink]),
Patch([\moreTestNoises, \white])
]);
)
a.play;
a.select(1); //pink
a.select(2); //white
a.select(0); //brown
a.choose; //select at random
a.releaseVoice; //fadeout
a.autostart_(true); //start right away
a.autostart_(false); //or not (default)
a.play;
a.select(0);
//get some info
a.selected;
a.selectedItem.instr;
a.maxIndex;
//PlayerPool also can be quantized with the .round message.
a.round_(4.0); //now on every 4/4 bar
a.select(1); //wait. will shift eventually.
a.select(2);
a.stop
//--
//and almost everything in this library can easily be gui:fied
a.gui; //playerpool from above
Instr([\testNoises, \brown]).gui;
Patch([\testNoises, \brown]).gui;
//and this lists a few useful tools:
Crucial.menu;
Library.postTree;
Library.clear;