/* More on Classes - methods, getters, setters */
// We have seen how new objects can be created, but many classes also have methods
// associated with them that contain functions that can operate on an Objects data:
e = Env([0, 1, 0], [1, 2], \sin);
e.plot
// looking at the classdef for Env, we can see there is an 'at' method that will
// calculate values from Envelopes at a given time
e.at(0.2);
e = Env([440, 880, 220], [10, 2], \exp);
e.plot;
e[2]
// Inside a Class definition, the '^' indicates what is returned from a method
f = e.delay(2);
f.postln; // post the 'value' of the object
f.postcs; // post a compile string representation of the object
// If the var is prepended with a '<', that means we can access the data stored
// in the var from the language (this is a getter).
f.times;
f.levels;
// if a var has a 'setter' character - '>' - you can also directly alter the value
// of that variable.
f.times_([1, 10, 2]);
f.times;
f.postcs;
/* SynthDefs */
/* Celia says - "UGens belong in SynthDefs" */

s.boot;
a = SynthDef(\mysynth, {arg freq = 300, dur = 1, amp = 1;
var src, env;
src = SinOsc.ar(freq, 0, 1);
env = EnvGen.kr(
Env([0, 1, 0], [0.5, 0.5], \sin),
timeScale: dur,
levelScale: amp,
doneAction: 2);
Out.ar(0, src * env);
});
a.load(s); // once loaded, it is available to your server for usage. You only
// need to reload if you change something.
Server-Command-Reference
// \s_new, \synthdefid, nodeId, addaction, target, .... args
s.sendMsg(\s_new, \mysynth, 1000, 0, 1);
s.sendMsg(\s_new, \mysynth, 1001, 0, 1, \freq, 1000, \amp, 0.1, \dur, 40);
// use n_free to stop the synth
s.sendMsg(\n_free, 1000);
// use the Server object to give you a nodeID
s.sendMsg(\s_new, \mysynth, s.nextNodeID, 0, 1, \freq, 2000, \amp, 0.2);
// Using s.nextNodeID makes multiple note creation much easier to do:
(
f = Array.fill(30, {220.rrand(1760)});
f.do({arg myfreq; s.sendMsg(\s_new, \mysynth, s.nextNodeID, 0, 1, \freq, myfreq,
\amp, f.size.reciprocal)});
)
f = Array.fill(300, {1760.rrand(7040)});
f.do({arg me; s.sendMsg(\s_new, \mysynth, s.nextNodeID, 0, 1, \freq, me,
\amp, f.size.reciprocal)});
// Object style
f = Array.fill(300, {1760.rrand(7040)});
f.do({arg me; Synth(\mysynth, [\freq, me, \amp, f.size.reciprocal])});
/* Order-of-Execution - groups, nodes and targets */
s.queryAllNodes;
// First, a couple of synthdefs that will not shut off until you tell them
// to (gated Envs):
(
SynthDef(\noise, {arg gate = 1, amp = 0.2, outbus = 0;
var src, env;
src = PinkNoise.ar(amp);
env = EnvGen.kr(
Env([0, 1, 0], [1, 1], \sin, 1),
gate,
doneAction: 2);
Out.ar(outbus, src * env);
}).load(s); // create and load the SynthDef in one step
SynthDef(\filtandsin, {arg gate = 1, sinamp = 0.2, filtamp = 1, sinfreq = 440, filtfreq = 880,
inbus = 0, outbus = 0;
var sin, filt, src, env;
src = In.ar(inbus);
sin = SinOsc.ar(sinfreq, 0, sinamp);
filt = BPF.ar(src, filtfreq, 0.01, filtamp);
env = EnvGen.kr(
Env([0, 1, 0], [1, 1], \sin, 1),
gate,
doneAction: 2);
Out.ar(outbus, (sin + filt) * env);
}).load(s);
)
// a noise gen: I need to refer to this synth later, so I save the nodeID in a var:
s.sendMsg(\s_new, \noise, a = s.nextNodeID, 0, 1);
s.sendMsg(\n_set, a, \amp, 0.1);
s.sendMsg(\n_set, a, \outbus, 0);
// see which nodes are running?
s.queryAllNodes;
// use the gate arg to shut off the env, and the note
s.sendMsg(\n_set, a, \gate, 0);
s.options.numOutputBusChannels;
s.options.numInputBusChannels;
s.options.numAudioBusChannels;
b = s.audioBusAllocator.alloc(1);
s.sendMsg(\s_new, \noise, a = s.nextNodeID, 0, 1, \outbus, b);
s.queryAllNodes; // see where this is executed in the Node chain
s.sendMsg(\s_new, \filtandsin, c = s.nextNodeID, 0, 1, \inbus, b, \sinamp, 0.1,
\filtamp, 100);
s.queryAllNodes;
s.sendMsg(\n_set, c, \sinamp, 0.01);
s.sendMsg(\n_set, c, \gate, 0);
// here, to hear the filtered noise, we need to make sure the second synth is
// executed AFTER the first add to the TAIL of group 1
s.sendMsg(\s_new, \filtandsin, c = s.nextNodeID, 1, 1, \inbus, b, \sinamp, 0.1,
\filtamp, 100);
s.queryAllNodes;
s.sendMsg(\n_set, c, \gate, 0);
// or more specifically, after node a
s.sendMsg(\s_new, \filtandsin, c = s.nextNodeID, 3, a, \inbus, b, \sinamp, 0.1,
\filtamp, 100);
s.queryAllNodes;
s.sendMsg(\n_set, c, \gate, 0);
s.sendMsg(\n_set, a, \gate, 0);
// groups are another way to control a large number of synth instances at one time.
// If we take our earlier \mysynth SynthDef and alter it to sound indefinitely, we
// can see an example of this:
(
SynthDef(\mysynth, {arg gate = 1, freq = 300, amp = 1;
var src, env;
src = SinOsc.ar(freq, 0, 1);
env = EnvGen.kr(
Env([0, 1, 0], [0.5, 0.5], \sin, 1), // add a releaseNode
gate,
levelScale: amp,
doneAction: 2);
Out.ar(0, src * env);
}).load(s);
)
// create an array of freqs:
f = Array.fill(10, {1760.rrand(7040)});
// create a new group at the head of 1
s.sendMsg(\g_new, g = s.nextNodeID, 0, 1);
// now, create your synths inside that group 'g'
f.do({arg me; s.sendMsg(\s_new, \mysynth, s.nextNodeID, 0, g, \freq, me,
\amp, f.size.reciprocal)});
s.queryAllNodes;
// you can now message all the synths in group g!
s.sendMsg(\n_set, g, \gate, 0);
/* Audio Busses - In.ar - AudioIn.ar */
// By default, the Server sets up a certain number of output busses and input busses
// for use with your hardware:
s.options.numOutputBusChannels; // these are numbered 0 - 7 on my system
s.options.numInputBusChannels; // ... and 8 - 15
// However, it also creates a number of virtual busses for you to route sound with:
s.options.numAudioBusChannels;
// earlier, to route the noise, we used the Server's audioBusAllocator to set aside
// one of these busses to route the PinkNoise through
// We used the In UGen to access that sound... In can also be used to access sound
// from the hardware
s.audioBusAllocator.alloc(1);
SynthDef(\livefilt, {arg gate = 1, inbus, amp = 1;
var in, filt, env, pan;
in = In.ar(inbus);
env = EnvGen.kr(
Env([0, 1, 0], [0.5, 0.5], \sin, 1), // add a releaseNode
gate,
levelScale: amp,
doneAction: 2);
// LFNoise2 is a cubic interpolated noise... outputs from -1 to 1 by default.
// Use mul and add args to change the range
filt = BPF.ar(in, LFNoise2.ar(0.5, 400, 1000), 0.01) * amp;
// pan the sound in the stereo field... use the env in the level field
pan = Pan2.ar(filt, LFNoise1.ar(1), env);
Out.ar(0, pan);
}).load(s);
// I have 8 output channels (0 - 7), so audio bus 8 is my first input channel
s.sendMsg(\s_new, \livefilt, a = s.nextNodeID, 0, 1, \inbus, 8 + 6, \amp, 10);
s.sendMsg(\n_set, a, \gate, 0);
// while my computer has 8 outs and ins, not all do... using the ServerOptions info
// is safer. s.options.numOutputBusChannels ALSO gives you the first input bus
// number!
s.sendMsg(\s_new, \livefilt, a = s.nextNodeID, 0, 1, \inbus, s.options.numOutputBusChannels, \amp, 10);
s.sendMsg(\n_set, a, \gate, 0);
// create a large number of these filts in a single group
s.sendMsg(\g_new, g = s.nextNodeID, 0, 1);
(
10.do({
s.sendMsg(\s_new, \livefilt, s.nextNodeID, 0, g,
\inbus, s.options.numOutputBusChannels, \amp, 2)
});
);
s.sendMsg(\n_set, g, \gate, 0);
// One of the methods of UGen is the range function... for UGens that normally
// output values between -1 and 1 you can rescale its output by using UGen.range(hi,
// low)... so, the previous freq arg for the BPF
filt = BPF.ar(in, LFNoise2.ar(0.5, 400, 1000), 0.01) * amp;
// which output values between 600 and 1400 could also be stated as
filt = BPF.ar(in, LFNoise2.ar(0.5).range(600, 1400), 0.01) * amp;
SynthDef(\livefilt, {arg gate = 1, inbus, hi = 1000, low = 200, rq = 0.01, amp = 1;
var in, filt, env, pan;
in = In.ar(inbus);
env = EnvGen.kr(
Env([0, 1, 0], [0.5, 0.5], \sin, 1),
gate,
levelScale: amp,
doneAction: 2);
filt = BPF.ar(in, LFNoise2.ar(0.5).range(hi, low), rq) * amp;
pan = Pan2.ar(filt, LFNoise1.ar(0.2), env);
Out.ar(0, pan);
}).load(s);
s.sendMsg(\g_new, g = s.nextNodeID, 0, 1);
(
100.do({
var freqbase;
freqbase = 400.rrand(1200);
s.sendMsg(\s_new, \livefilt, s.nextNodeID, 0, g,
\inbus, s.options.numOutputBusChannels, \amp, 0.4, \low, freqbase,
\high, freqbase * 4, \rq, 0.01);
});
);
// change the rq of the filter
s.sendMsg(\n_set, g, \rq, 0.001);
// change the amp
s.sendMsg(\n_set, g, \amp, 10);
// free them
s.sendMsg(\n_set, g, \gate, 0);
/* For tonight
Look at
[UGens]
[Server-Command-Reference]
[Tour_of_UGens]
[Randomness]
*/