You are on page 1of 2325

the SuperCollider \Help "Book

"

// typeset from the help files

The Beaver brought paper, portfolio, pens, And ink in an unfailing supplies: While strange creepy creatures came out of their dens And watched them with wondering eyes. (L. Carroll, The Hunting of the Snark, Fit the Fifth, The Beaver’s Lesson)

This book is a collection of all the SuperCollider help files available in the standard distribution. It has been typeset with CONTEXT, a TEX-based typesetting system for document preparation which allows high-quality automated typesetting with native PDF output. The CONTEXT code has been generated by TheCollidingChampollion, a Python module which analyses and translates the SuperCollider html help files. As TheCollidingChampollion is in its first version, it is still very experimental: in particular, syntax colorizing presents some bugs and some features are lacking (e.g. sometimes colors are misplaced and indentation is missing). The situation partly depends also on sources: the html files reproduces all the errors of the rtf files from which they are generated, and these are reproduced again in the CONTEXT files. More, the original rtf documentation lacks structure and an explicit markup would be needed to achieve better results (the best example is Thread help file). The book tries to reproduce the original hierarchy of the Help folder. As depth in the Help subfolders is changing, the book structure is a bit messy. A general criterium is that if files are at the same level of folders they are all listed before the folders. Note that: 1. in each document the original path is indicated in the header 2. each document has a unique ID Other Meta-data and stylistic improvements are on the ToDo list. Japanese tutorial is missing. This work has been possible thanks to three open-source projects. • • • SuperCollider: http://supercollider.sourceforge.net/ CONTEXT: http://www.pragma-ADE.com/ Python: http://www.python.org

Please report bugs, suggestions, cries & whispers to: andrea.valle@unito.it Compiled on January 16, 2007. Andrea Valle http://www.semiotiche.it/andrea/

1

1 2 3 4

3vs2 BinaryOps Collections Control

5 27 69 174 238 239 276 300 301 313 316 327 362 406 409 415 421 422 423 424 438 459 477 479 517 534 543 608 740

5 Core 5.1 Kernel 5.2 Miscellanea 6 Crucial 6.1 Constraints 6.2 Control 6.3 Editors 6.4 Gui 6.5 Instr 6.6 Introspection 6.7 Miscellanea 6.8 Patching 6.9 Players 1 Miscellanea 2 SFP 6.10 Sample 6.11 Scheduling 6.12 Sequencers 6.13 ServerTools 6.14 UncoupledUsefulThings 7 8 9 Files Geometry Getting-Started

10 GUI 11 Help-scripts

2

12 JITLib 12.1 Environments 12.2 Extras 12.3 Miscellanea 12.4 Networking 12.5 Nodeproxy 12.6 Patterns 12.7 Tutorials 12.8 Ugens 13 Language 14 Linux 15 Mark_Polishook_tutorial 15.1 Debugging 15.2 First_steps 15.3 Miscellanea 15.4 Synthesis 16 Math 17 Miscellanea 18 Networking 19 OSX 19.1 Miscellanea 19.2 Objc 20 Other_Topics 21 Quarks 22 Scheduling 23 ServerArchitecture 24 Streams

755 756 765 773 783 802 834 889 970 974 1059 1066 1067 1079 1090 1093 1159 1197 1300 1303 1304 1316 1321 1364 1369 1385 1500

3

25 UGens 25.1 Analysis 25.2 Chaos 25.3 Control 25.4 Controls 25.5 Delays 25.6 Envelopes 25.7 FFT 25.8 Filters 25.9 InfoUGens 25.10 InOut 25.11 Miscellanea 25.12 Noise 25.13 Oscillators 25.14 Panners 25.15 PhysicalModels 25.16 SynthControl 25.17 Triggers 26 UnaryOps

1728 1729 1741 1771 1811 1824 1862 1881 1944 2003 2015 2047 2117 2166 2227 2246 2254 2258 2289

4

1 3vs2

5

Where: Help→3vs2→Backwards-Compatibility

ID: 1

Backwards Compatibility
There are a number of classes and methods that have been added to allow for backwards compatibility with SC2 code. The most notable of these is Synth.play, which is basically a wrapper for Function.play.
{ SinOsc.ar(440, 0, 0.5) }.play; // creates an arbitrarily named SynthDef and a Synth to play it Synth.play({ SinOsc.ar(440, 0, 0.5) }); // in SC3 just a wrapper for Function.play with fewer args

Both of these will create synth nodes on the default server. Note that neither requires the use of an Out.ar ugen; they simply output to the first audio bus. One can however add an Out to Function.play in order to specify.
Synth.play({ Out.ar(1, SinOsc.ar(440, 0, 0.5)) });

In general, one should be aware of this distinction when using this code. When copying such code for reuse with other SC3 classes (for example in a reusable SynthDef), it will usually be necessary to add an Out.ar. Although useful for quick testing these methods are generally inferior to SynthDef.play, as the latter is more direct, requires no modifications for general reuse, has greater general flexibility and has slightly less overhead. (Although this is insignificant in most cases, it could be relevant when large numbers of defs or nodes are being created.) Like SynthDef.play, Function.play returns a Synth object which can then be messaged, etc. However, since Function.play creates an arbitrarily named SynthDef, one cannot reuse the resulting def, at least not without reading its name from the post window, or getting it from the Synth object.
//The following examples are functionally equivalent x = { arg freq = 440; Out.ar(1, SinOsc.ar(freq, 0, 0.5)) }.play(fadeTime: x.set(\freq, 880); // you can set arguments // get the arbitrary defname from x 0);

y = Synth.new(x.defName); x.free; y.free;

x = SynthDef("backcompat-sine", { arg freq = 440; Out.ar(1, SinOsc.ar(freq, 0, 0.5)) }).play; x.set(\freq, 880); y = Synth.new("backcompat-sine");

6

Where: Help→3vs2→Backwards-Compatibility

x.free; y.free;

Function.play is in general superior to both its SC2 equivalent and Synth.play. It has a number of significant features such as the ability to specify the output bus and fade times as arguments. See the Function helpfile for a more in-depth discussion. A number of other classes and methods have also been added to improve compatibility. These are listed below. In general there are equivalent or better ways of doing the same things in SC3. Synth *play use Function.play or SynthDef.play GetFileDialog use CocoaDialog GetStringDialog Synth *stop use Server.freeAll Synth *isPlaying Server.numSynths (this will include non-running nodes) Mix *ar *arFill use Mix *new and *fill SimpleNumber.rgb Rawarray.write

7

Where: Help→3vs2→ClientVsServer

ID: 2

Client versus Server Operations
Unlike in SC2 where language and synthesis were unified in a single application, SC3 divides its operations between a language application (the SuperCollider app on which you double-clicked to startup SC) and a synthesis-server application (a UNIX commandline application called scsynth, which is started when you press the boot button on the ’local’ server window that is created by default at startup, or when you boot a Server from code). The two applications communicate between each other through UDP or TCP using a subset of CNMAT’s Open Sound Control. This is a radical departure from the previous architecture (a more detailed discussion of this and other matters can be found in the file sc3 intro 2 in the Examples folder) and yields several important advantages: The server can be controlled by programs other than the language app. The language app can crash and synthesis will not stop. The server can crash and the language will not. The language and server apps can be running on different machines, even in different parts of the world. This allows for efficient ’division of labour’ and network interactivity. There is one notable drawback: The messaging process introduces a small amount of latency. This should not be confused with audio latency which can be quite low. It only means that there is a small, usually insignificant delay between the one side sending a message and the other receiving it and acting upon it. (This can be minimized by using the ’internal’ server. See Server for more detail.) What is crucial to understand is the distinct functions of each side. The server app is a lean and efficient program dedicated to audio functions. It knows nothing about SC code, objects, OOP, or anything else to do with the SC language. It has (at least for the moment) little programmatic ability. When one creates a Synth object in the language app, that object is only the clientside representation of a node on the server. The language app provides you with convienent OOP functionality to keep track of and manipulate things on the server. All of this functionality is possible to do ’by hand’ using the sendMsg method of Server, and other similar messages. For instance:
s = Server.default;

8

Where: Help→3vs2→ClientVsServer

s.boot;

// this n = s.nextNodeID; s.sendMsg("/s_new", "default", n); // use the SynthDef "default" s.sendMsg("/n_free", n);

// is equivalent to x = Synth("default"); // create a synth on the default server (s) and allocate an ID for it x.free; // free the synth, its ID and resources

The latter method gives you certain functionality. It gets a node ID for you automatically, it allows you to control the Synth in syntactically elegant and efficient ways (see the Synth and Node helpfiles), and to access all the advantages of object oriented programming while doing so. Encapsulating the complexities and bookeeping greatly reduces the chance of bugs in your own code. It also has a small amount of overhead. It requires clientside CPU cycles and memory to create and manipulate an object. Normally this is not significant, but there may be times when you would prefer to use the less elegant, and less expensive first method, for instance when creating large numbers of grains which will simply play and then deallocate themselves. Thus it is possible to create synth nodes on the server without actually creating Synth objects, providing you are willing to do the required housekeeping yourself. The same is true of group nodes, buffers, and buses. A more detailed discussion of these concepts can be found in the NodeMessaging helpfile. In conclusion, the crucial thing to remember is the distinction between things like nodes, busses, buffers, and servers and the objects that represent them in the language app (i.e. instances of Node, Bus, Buffer, and Server). Keeping these conceptually distinct will help avoid much confusion.

9

Where: Help→3vs2→SC3vsSC2

ID: 3

SuperCollider 3 versus SuperCollider 2
There are a number of ways in which SuperCollider 3 (or SCServer) is very different from SC2. A discussion of this is organised in the following documents: ClientVsServer - Separate language and synthesis apps. SynthDefsVsSynths - The use of precompiled SynthDefs as opposed to always compiling on the fly. Spawning - The lack of the Spawn and TSpawn ugens and their various convienence classes. Sync-Async - The problem of simultaneous synchronous and asynchronous execution. Backwards-Compatibility - A discussion some classes and methods which have been added to improve compatibility with SC2 code, and their limitations. (Select the bold text and type cmd-shift-? to open the corresponding file.) Note that these documents are not intended to be exhaustive tutorials, just an introduction to some of the differences. Close examination of the helpfiles of relevant classes should help to fill in the details. These files may be of some use to beginners as well.

10

Where: Help→3vs2→Spawning

ID: 4

"Spawning" and "TSpawning"
In SC2, Spawn and TSpawn were two of the most powerful and commonly used UGens. In SC3 the idea of a top level Synth in which everything is spawned is no longer valid. Synthesis is always running (at least as long as a server is) and new Synths can be created on the fly. This arrangement results in even greater flexibility than in SC2, but requires a slightly different approach. In SC3 one can create Synths at any time simply by executing blocks of code.
// do this ( x = SynthDef("Help-SynthDef", { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).play; // SynthDef-play returns a Synth object. )

// then do this ( SynthDef("help-Rand", { arg out=0; Out.ar(out, FSinOsc.ar( Rand(200.0, 400.0), 0, Line.kr(0.2, 0, 1, doneAction:2)) ) }).play(s); ) // frees itself // frequency between 200 and 400 Hz

x.free;

Clocks, such as SystemClock, provide a way to schedule things at arbitrary points in the future. This is similar to Synth.sched in SC2.
( SystemClock.sched(2.0,{ "2.0 seconds later".postln; // this could be any code, including Synth creation

11

Where: Help→3vs2→Spawning

nil // this means don’t repeat }); )

In SC3 time-based sequences of events can be implemented using Routines. A Routine which yields a number can be scheduled using a clock:
( var w, r; w = SCWindow("trem", Rect(512, 256, 360, 130)); w.front; r = Routine({ arg time; 60.do({ arg i; 0.05.yield; // wait for 0.05 seconds { w.bounds = w.bounds.moveBy(10.rand2, 10.rand2); w.alpha = cos(i*0.1pi)*0.5+0.5; }.defer; }); 1.yield; // wait for 1 second before closing w w.close; }); SystemClock.play(r); )

Note that this implementation avoids one of the stranger aspects of the SC2 approach: The need to start a Synth to schedule time-based behavior, even if no audio is involved. Both SystemClock and AppClock (a less accurate version which can call Cocoa primitives) have only class methods. Thus one does not create instances of them. If you need to have an individual clock to manipulate (for instance to manipulate the tempi of different sequences of events) you can use TempoClock. A simple SC2 Spawn example is shown below, followed by its translation into SC3 style code.
// This will not execute in SC3 (

Synth.play({

12

Where: Help→3vs2→Spawning

Spawn.ar({ EnvGen.ar(Env.perc) * SinOsc.ar(440,0,0.1) }, 1, // one channels 1) // new event every second }))

// The same example in SC3 (will execute)

s = Server.default; s.boot; ( SynthDef("help-EnvGen",{ argout=0; Out.ar(out, EnvGen.kr(Env.perc,1.0,doneAction: * SinOsc.ar(440,0,0.1) ) }).send(s); ) 2)

( r = Routine.new({ { Synth.new("help-EnvGen"); 1.yield; }.loop }); // loop every one second SystemClock.play(r); )

Note that the above example uses a precompiled SynthDef. This results in a lower CPU spike when Synths are created than SC2-style Spawning. It is possible to create SynthDefs on the fly, if this is necessary, but a great deal of variation can be achieved with arguments, or with ugens such as Rand and TRand. See the helpfile SynthDefsVsSynths for more detail.
// SynthDefs on the fly

s = Server.default; s.boot; ( t = TempoClock.new; r = Routine.new({ 10.do({ // could be done with an argument instead of a new def, but proves the point

13

Where: Help→3vs2→Spawning

SynthDef("help-EnvGen" ++ i,{ arg out=0; Out.ar(out, EnvGen.kr(Env.perc,1.0,doneAction: 2)

* SinOsc.ar(100 + (100 * t.elapsedBeats),0,0.1) ) }).play(s); 1.yield; }); }).play(t); // Note the alternative syntax: ) Routine.play(aClock)

Note the alternative syntax for playing a Routine. aClock.play(aRoutine) and aRoutine.play(aClock) are functionally equivalent. The two make different things more or less convienent, like sending messages to the Routine or Clock. (See the play helpfile for a more detailed discussion.) For instance:
( // this, that and the other r = Routine.new({var i = 0; { ("this: q = Routine.new({var i = 0; { ("that: " ++ i).postln; i = i + 1; 1.yield; }.loop }); " ++ i).postln; i = i + 1; 1.yield; }.loop }); " ++ i).postln; i = i + 1; 1.yield; }.loop });

t = Routine.new({var i = 0; { ("the other: )

SystemClock.play(r); SystemClock.play(q); SystemClock.play(t);

// start this // start that // start the other

r.stop; q.reset;

// stop this but not that or the other // reset that while playing

c = TempoClock.new; // make a TempoClock r.reset; c.play(r); c.tempo = 16; // have to reset this because it’s stopped // play this in the new clock; starts from the beginning // increase the tempo of this

SystemClock.clear;

// clear EVERYTHING scheduled in the SystemClock; so that and the other

// but not this

c.clear; c.play(r);

// clear everything scheduled in c, i.e.

this

// since it wasn’t stopped, we don’t have to reset this

14

Where: Help→3vs2→Spawning

// and it picks up where it left off

c.stop

// stop c, destroy its scheduler, and release its OS thread

For convenience pauseable scheduling can be implemented with a Task. Task.new takes two arguments, a function and a clock, and creates it’s own Routine. If you don’t specify a clock, it will create a TempoClock for you. Since you don’t have to explicitly create a Clock or Routine, use of Task can result in code that is a little more compact.
( t = Task.new({ inf.do({ arg i; i.postln; 0.5.wait }); }); )

t.start; t.stop; t.start; t.reset; t.stop; t.resume;

// Start it // Stop it // Start again from the beginning // Reset on the fly // Stop again // Restart from where you left off This works since the

t.clock.tempo = 0.25; // Get the Task’s clock and change the tempo. // default is a TempoClock. t.pause; // Same as t.stop

TSpawn’s functionality can be replicated with SendTrig and OSCresponder or OSCresponderNode. See their individual helpfiles for details on their arguments and functionality.
s = Server.default; s.boot;

( // this Synth will send a trigger to the client app SynthDef("help-SendTrig",{ SendTrig.kr(

15

Where: Help→3vs2→Spawning

Dust.kr(1.0), // trigger could be anything, e.g. 0,0.9 ); }).send(s); )

Amplitude.kr(AudioIn.ar(1) > 0.5)

( // this recieves the trigger on the client side and ’Spawns’ a new Synth on the server OSCresponder(s.addr,’/tr’,{ SynthDef("help-EnvGen",{ arg out=0; Out.ar(out, EnvGen.kr(Env.perc,1.0,doneAction: * SinOsc.ar(440,0,0.1) ) }).play(s); }).add; 2)

// Start ’spawning’ Synth("help-SendTrig"); )

16

Where: Help→3vs2→Sync-Async

ID: 5

Synchronous and Asynchronous Execution
Using a program such as SuperCollider introduces a number of issues regarding timing and order of execution. Realtime audio synthesis requires that samples are calculated and played back at a certain rate and on a certain schedule, in order to avoid dropouts, glitches, etc. Other tasks, such as loading a sample into memory, might take arbitrary amounts of time, and may not be needed within a definite timeframe. This is the difference between synchronous and asynchronous tasks. Problems can arise when synchronous tasks are dependent upon the completion of asynchronous ones. For instance trying to play a sample that may or may not have been completely loaded yet. In SC2 this was relatively simple to handle. One scheduled synchronous tasks during synthesis, i.e. within the scope of a Synth.play. Asynchronous tasks were executed in order, outside of synthesis. Thus one would first create buffers, load samples into them, and then start synthesis and play them back. The interpreter made sure that each step was only done when the necessary previous step had been completed. In SC3 the separation of language and synth apps creates a problem: How does one side know that the other has completed necessary tasks, or in other words, how does the left hand know if the right is finished? The flexibility gained by the new architecture introduces another layer of complexity, and an additional demand on the user. A simple way to deal with this is to execute code in blocks. In the following code, for instance, each block or line of code is dependent upon the previous one being completed.
// Execute these one at a time

// Boot the local Server ( s = Server.local; s.boot; )

// Compile a SynthDef and write it to disk ( SynthDef("Help-SynthDef",

17

Where: Help→3vs2→Sync-Async

{ arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).writeDefFile; )

// Load it into the server s.loadSynthDef("Help-SynthDef");

// Create a Synth with it x = Synth.new("Help-SynthDef", s);

// Free the node on the server x.free;

// Allow the client-side Synth object to be garbage collected x = nil;

In the previous example it was necessary to use interpreter variables (the variables a-z, which are declared at compile time) in order to refer to previously created objects in later blocks or lines of code. If one had declared a variable within a block of code (i.e.var mySynth;) than it would have only persisted within that scope. (See the helpfile Scope for more detail.) This style of working, executing lines or blocks of code one at a time, can be very dynamic and flexible, and can be quite useful in a performance situation, especially when improvising. But it does raise the issues of scope and persistence. Another way around this that allows for more descriptive variable names is to use environment variables (i.e. names that begin with , so mysynth; see the Environment helpfile for details). However, in both methods you become responsible for making sure that objects and nodes do not persist when you no longer need them.
( SynthDef("Help-SynthDef", { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).send(s); )

// make a Synth and assign it to an environment variable mysynth = Synth.new("Help-SynthDef", s);

18

Where: Help→3vs2→Sync-Async

// free the synth mysynth.free;

// but you’ve still got a Synth object mysynth.postln;

// so remove it from the Environment so that the Synth will be garbage collected currentEnvironment.removeAt(\mysynth);

But what if you want to have one block of code which contains a number of synchronous and asynchronous tasks. The following will cause an error, as the SynthDef that the server needs has not yet been received.
// Doing this all at once produces the error "FAILURE /s_new SynthDef not found" ( var name; name = "Rand-SynthDef"++ 400.0.rand; // use a random name to ensure it’s not already loaded SynthDef(name, { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).send(s);

Synth.new(name, s); )

A crude solution would be to schedule the dependant code for execution after a seemingly sufficient delay using a clock.
// This one works since the def gets to the server app first ( var name; name = "Rand-SynthDef" ++ 400.0.rand; SynthDef(name, { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).send(s);

SystemClock.sched(0.05, {Synth.new(name, s);}); // create a Synth after 0.05 seconds )

19

Where: Help→3vs2→Sync-Async

Although this works, it’s not very elegant or efficient. What would be better would be to have the next thing execute immediately upon the previous thing’s completion. To explore this, we’ll look at an example which is already implemented. You may have realized that first example above was needlessly complex. SynthDef-play will do all of this compilation, sending, and Synth creation in one stroke of the enter key.
// All at once ( SynthDef("Help-SynthDef", { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).play(s); )

Let’s take a look at the method definition for SynthDef-play and see what it does.
play { arg target,args,addAction=\addToTail; var synth, msg; target = target.asTarget;

synth = Synth.basicNew(name,target.server); // create a Synth, but not a synth node msg = synth.newMsg(target, addAction, args);// make a message that will add a synth node this.send(target.server, msg); // ** send the def, and the message as a completion message ^synth // return the Synth object }

This might seem a little complicated if you’re not used to mucking about in class definitions, but the important part is the second argument to this.send(target.server, msg);. This argument is a completion message, it is a message that the server will execute when the send action is complete. In this case it says create a synth node on the server which corresponds to the Synth object I’ve already created, when and only when the def has been sent to the server app. (See the helpfile Server-Command-Reference for details on messaging.) Many methods in SC have the option to include completion messages. Here we can use SynthDef-send to accomplish the same thing as SynthDef-play:

20

Where: Help→3vs2→Sync-Async

// Compile, send, and start playing ( SynthDef("Help-SynthDef", { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).send(s, ["s_new", "Help-SynthDef", x = s.nextNodeID]); // this is ’messaging’ style, see below ) s.sendMsg("n_free", x);

The completion message needs to be an OSC message, but it can also be some code which when evaluated returns one:
// Interpret some code to return a completion message. The .value is needed.

// This and the preceding example are essentially the same as SynthDef.play ( SynthDef("Help-SynthDef", { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).send(s, {x = Synth.basicNew("Help-SynthDef"); x.newMsg; }.value); // ’object’ style ) x.free;

If you prefer to work in ’messaging’ style, this is pretty simple. If you prefer to work in ’object’ style, you can use the commands like newMsg, setMsg, etc. with objects to create appropriate server messages. The two proceeding examples show the difference. See the NodeMessaging helpfile for more detail. In the case of Buffer objects a function can be used as a completion message. It will be evaluated and passed the Buffer object as an argument. This will happen after the Buffer object is created, but before the message is sent to the server. It can also return a valid OSC message for the server to execute upon completion.
( SynthDef("help-Buffer",{ arg out=0,bufnum; Out.ar( out, PlayBuf.ar(1,bufnum,BufRateScale.kr(bufnum)) ) }).load(s);

21

Where: Help→3vs2→Sync-Async

y = Synth.basicNew("help-Buffer"); // not sent yet b = Buffer.read(s,"sounds/a11wlk01.wav", completionMessage: { arg buffer;

// synth add its s_new msg to follow // after the buffer read completes y.newMsg(s,\addToTail,[\bufnum,buffer.bufnum]) }); // .value NOT needed, unlike in the previous example

)

// when done... y.free; b.free;

The main purpose of completion messages is to provide OSC messages for the server to execute immediately upon completion. In the case of Buffer there is essentially no difference between the following:
( b = Buffer.alloc(s, 44100, completionMessage: ) // this is equivalent to the above ( b = Buffer.alloc; ("bufnum:" + b.bufnum).postln; ) { arg buffer; ("bufnum:" + buffer.bufnum).postln; });

One can also evaluate a function in response to a ’done’ message, or indeed any other one, using an OSCresponder or an OSCresponderNode. The main difference between the two is that the former allows only a single responder per command, where as the latter allows multiple responders. See their respective helpfiles for details.
( SynthDef("help-SendTrig",{ SendTrig.kr(Dust.kr(1.0), 0, 0.9); }).send(s);

// register to receive this message a = OSCresponderNode(s.addr, ’/done’, { arg time, responder, msg;

22

Where: Help→3vs2→Sync-Async

("This is the done message for the SynthDef.send:" + [time, responder, msg]).postln; }).add.removeWhenDone; // remove me automatically when done b = OSCresponderNode(s.addr, ’/tr’, { arg time, responder, msg; [time, responder, msg].postln; }).add; c = OSCresponderNode(s.addr, ’/tr’, { arg time, responder, msg; "this is another call".postln; }).add; )

x = Synth.new("help-SendTrig"); b.remove; c.remove; x.free;

23

Where: Help→3vs2→SynthDefsVsSynths

ID: 6

SynthDefs versus Synths
In SC2 Synth.play was the standard way to compile a ugenGraphFunc and play it. Each time you executed Synth.play, or Spawned a new event, that function was compiled anew. SC3 on the other hand, makes use of what are called SynthDefs. A SynthDef takes a ugenGraphFunc and compiles it to a kind of bytecode (sort of like Java bytecode) which can be understood by the server app. The server reads the SynthDef and creates a synth node based upon it. SynthDefs can be precompiled and saved to disk. Any def saved in the synthdefs/ directory (or in any directory set in the environment variable SC_SYNTHDEF_PATH) will be loaded into memory by a local Server when it is booted. If the def being used in a new Synth is already compiled and loaded, there is much less of a CPU spike when creating a new Synth than there was in SC2. SynthDefs can also be compiled and loaded into the Server without writing them to disk. This can be done while performing. The downside of this is that precompiled SynthDefs lack some of the programmatic flexibility that was one of SC2’s great strengths. Much of this flexibility is gained back however, through the ability to set and change arguments (which you build into your ugenGraphFunc), and through new ugens such as Rand and TRand. When maximum flexibility is required, it is still possible to compile and send SynthDefs ’on the fly’, albeit with SC2-like CPU spikes and a small amount of messaging latency. It is important to understand that creating and sending SynthDefs is asynchronous. This means that it is impossible to determine precisely how long it will take to compile and send a SynthDef, and thus when it will be available for creating new Synths. A simple way around this is to execute code in blocks, selecting them one at a time. More complicated is to use completion messages. SynthDef.play takes care of this for you, and returns a Synth object which you can then manipulate. See the example below. Another important distinction is between Synth in SC2 and Synth in SC3. The latter is a client-side object which represents a synth node on the server. Although it has some of the same methods, it does not function in the same way. There is no top level Synth in SC3, within which all scheduling and creation of other Synths occurs. There are only Synth objects which represent synth nodes on the server. These can be created at any

24

Where: Help→3vs2→SynthDefsVsSynths

time, within any scope.

Examples
( s = Server.local; s.boot; )

// Compile a SynthDef and write it to disk ( SynthDef("Help-SynthDef", { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).writeDefFile; )

// Compile, write, and load it to the server ( SynthDef("Help-SynthDef", { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).load(s); )

// Load it to the server without writing to disk ( SynthDef("Help-SynthDef", { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).send(s); )

// Create a Synth with it x = Synth.new("Help-SynthDef", s); x.free;

// Shorthand method to compile and write a SynthDef, and then play it in a Synth when done. // Look familiar? (

25

Where: Help→3vs2→SynthDefsVsSynths

x = SynthDef("Help-SynthDef", { arg out=0; Out.ar(out, PinkNoise.ar(0.1)) }).play(s); ) // The above only starts the new Synth after the def has been sent to the server. // Note that SynthDef.play returns a Synth object!

x.set(\out, 1); // change one of the arguments x.free;

// SynthDef with a parameter that will be randomly determined each time a new Synth is created // (try it several times to hear the differences)

( SynthDef("help-RandFreq", { argout=0; Out.ar(out, FSinOsc.ar( Rand(200.0, 400.0), // frequency between 200 and 400 Hz 0, Line.kr(0.2, 0, 1, doneAction:2)) ) }).play(s); )

26

2 BinaryOps

27

Where: Help→BinaryOps→Absdif

ID: 7

absdif

absolute value of the difference

BinaryOperator absdif(a, b) a absdif: b a.absdif(b) Return the value of abs(a - b). Finding the magnitude of the difference of two values is a common operation.
// creates a rhythm ( { var mul; mul = 0.2 absdif: FSinOsc.ar(2, 0, 0.5);

FSinOsc.ar(440, 0, mul); }.play;)

28

Where: Help→BinaryOps→Addition

ID: 8

+

addition

BinaryOperator a+b
{ FSinOsc.ar(800, 0, 0.1) + PinkNoise.ar(0.1) }.play;

// DC offset; add:

0.1 would be more efficient

{ FSinOsc.ar + 0.1 }.play

29

Where: Help→BinaryOps→Amclip

ID: 9

amclip two quadrant multiply
BinaryOperator amclip(a, b) a amclip: b a.amclip(b) 0 when b <= 0, a*b when b > 0
{ WhiteNoise.ar.amclip(FSinOsc.kr(1,0.2)) }.play; // makes a sine envelope

30

Where: Help→BinaryOps→Atan2

ID: 10

atan2 arctangent
BinaryOperator atan2(y, x) y atan2: x y.atan2(x) Returns the arctangent of y/x. See also hypot. OK, now we can add a pan to the hypot doppler examples by using atan2 to find the azimuth, or direction angle, of the sound source. Assume speakers at +/- 45 degrees and clip the direction to between those.
( { var x, y, distance, velocity, pitchRatio, amplitude, azimuth, panValue; // object travels 200 meters in 6 secs (=120kph) passing 10 meters // from the listener x = 10; y = LFSaw.kr(1/6, 0, 100); distance = hypot(x, y); velocity = Slope.kr(distance); pitchRatio = (344 - velocity) / 344; amplitude = 10 / distance.squared; azimuth = atan2(y, x); // azimuth in radians panValue = (azimuth / 0.5pi).clip2(1); Pan2.ar(FSinOsc.ar(1000 * pitchRatio), panValue, amplitude) }.play) // speed of sound is 344 meters/sec

( { var x, y, distance, velocity, pitchRatio, amplitude, motorSound, azimuth, panValue; // object travels 200 meters in 6 secs (=120kph) passing 10 meters

31

Where: Help→BinaryOps→Atan2

// from the listener x = 10; y = LFSaw.kr(1/6, 0, 100); distance = hypot(x, y); amplitude = 40 / distance.squared; motorSound = RLPF.ar(FSinOsc.ar(200, LFPulse.ar(31.3, 0, 0.4)), 400, 0.3); azimuth = atan2(y, x); // azimuth in radians panValue = (azimuth / 0.5pi).clip2(1); // make a value for Pan2 from azimuth Pan2.ar(DelayL.ar(motorSound, 110/344, distance/344), panValue, amplitude) }.play)

32

Where: Help→BinaryOps→BinaryOpUGen

ID: 11

BinaryOpUGen
superclass: UGen BinaryOpUGens are created as the result of a binary operator applied to a UGen.
(SinOsc.ar(200) * ClipNoise.ar).dump; (SinOsc.ar(200).thresh(0.5)).dump;

The use of the binary operators * and thresh above each instantiate a BinaryOpUGen. Do not confuse the operators themselves (which are methods) with the resulting BinaryOpUGen, which is an object. When applied to other classes they may not return new objects, and can behave in a more straightforward manner. See for example SimpleNumber. There are helpfiles for each the different operators, listed below. The operators >, >=, <, and <= are particularly useful for triggering. They should not be confused with their use in conditionals. Compare
(1 > 0).if({"1 is greater than 0".postln}); // > returns a boolean

with
( // trigger an envelope { var trig; trig = SinOsc.ar(1) > 0.1; Out.ar(0, EnvGen.kr(Env.perc, trig, doneAction: * SinOsc.ar(440,0,0.1) ) }.play(s);) // > outputs 0 or 1 0)

See the individual helpfiles for more detail. The following operators have their own helpfiles:

33

Where: Help→BinaryOps→BinaryOpUGen

+ - * / ** absdif amclip atan2 clip2 difsqr excess fold2 hypot hypotApx max min ring1 ring2 ring3 ring4 round scaleneg sqrdif sqrsum sumsqr thresh trunc wrap2

34

Where: Help→BinaryOps→Clip2

ID: 12

clip2

bilateral clipping

BinaryOperator clip2(a, b) a clip2: b a.clip2(b) clips input wave a to +/- b
Server.internal.boot;

{ FSinOsc.ar(400).clip2(0.2) }.scope; // clipping distortion

{ FSinOsc.ar(1000).clip2(Line.kr(0,1,8)) }.scope;

35

Where: Help→BinaryOps→Difsqr

ID: 13

difsqr

difference of squares

BinaryOperator difsqr(a, b) a difsqr: b a.difsqr(b) Return the value of (a*a) - (b*b). This is more efficient than using separate unit generators for each operation.
{ (FSinOsc.ar(800) difsqr: FSinOsc.ar(XLine.kr(200,500,5))) * 0.125 }.play;

same as :
( { var a, b; a = FSinOsc.ar(800); b = FSinOsc.ar(XLine.kr(200,500,5)); ((a * a) - (b * b)) * 0.125 }.play)

36

Where: Help→BinaryOps→Division

ID: 14

/

division

BinaryOperator a/b Division can be tricky with signals because of division by zero.
{ PinkNoise.ar(0.1) / FSinOsc.kr(10, 0.5, 0.75) }.play;

37

Where: Help→BinaryOps→Excess

ID: 15

excess

clipping residual

BinaryOperator excess(a, b) a excess: b a.excess(b) Returns the difference of the original signal and its clipped form: (a - clip2(a,b)).
{ FSinOsc.ar(1000).excess(Line.kr(0,1,8)) }.play;

38

Where: Help→BinaryOps→Exponentiation

ID: 16

**

exponentiation

BinaryOperator a ** b When the signal is negative this function extends the usual definition of exponentiation and returns neg(neg(a) ** b). This allows exponentiation of negative signal values by noninteger exponents.
( { var a; a = FSinOsc.ar(100); [a, a**10] }.play )

39

Where: Help→BinaryOps→Fold2

ID: 17

fold2

bilateral folding

BinaryOperator fold2(a, b) a fold2: b a.fold2(b) folds input wave a to +/- b
{ FSinOsc.ar(1000).fold2(Line.kr(0,1,8)) }.scope;

40

Where: Help→BinaryOps→Greaterorequalthan

ID: 18

>=

greater than or equal

BinaryOperator a >= b Result is 1 if a >= b, otherwise it is 0. This can be useful for triggering purposes, among other things:
s = Server.local; s.boot;

( // trigger an envelope { var trig; trig = SinOsc.ar(1) >= 0; Out.ar(0, EnvGen.kr(Env.perc, trig, doneAction: * SinOsc.ar(440,0,0.1) ) }.play(s);) 0)

( // trigger a synth SynthDef("help-EnvGen",{ argout=0; Out.ar(out, EnvGen.kr(Env.perc,1.0,doneAction: * SinOsc.ar(440,0,0.1) ) }).send(s); 2)

// This synth has no output.

It only checks amplitude of input and looks for a transition from < 0.2

// to > 0.2

SynthDef("help->= trig", { SendTrig.kr(Amplitude.kr(AudioIn.ar(1)) >= 0.2); }).play(s);

41

Where: Help→BinaryOps→Greaterorequalthan

// responder to trigger synth OSCresponderNode(s.addr,’/tr’,{ "triggered".postln; Synth.new("help-EnvGen") }).add; )

42

Where: Help→BinaryOps→Greaterthan

ID: 19

>

greater than

BinaryOperator a>b Result is 1 if a > b, otherwise it is 0. This can be useful for triggering purposes, among other things:
s = Server.local; s.boot;

( // trigger an envelope { var trig; trig = SinOsc.ar(1) > 0; Out.ar(0, EnvGen.kr(Env.perc, trig, doneAction: * SinOsc.ar(440,0,0.1) ) }.play(s);) 0)

( // trigger a synth SynthDef("help-EnvGen",{ argout=0; Out.ar(out, EnvGen.kr(Env.perc,1.0,doneAction: * SinOsc.ar(440,0,0.1) ) }).send(s); 2)

// This synth has no output.

It only checks amplitude of input and looks for a transition from < 0.2

// to > 0.2

SynthDef("help-> trig", { SendTrig.kr(Amplitude.kr(AudioIn.ar(1)) > 0.2); }).play(s);

43

Where: Help→BinaryOps→Greaterthan

// responder to trigger synth OSCresponderNode(s.addr,’/tr’,{ "triggered".postln; Synth.new("help-EnvGen") }).add; )

44

Where: Help→BinaryOps→Hypot

ID: 20

hypot hypotenuse
BinaryOperator hypot(x, y) x hypot: y x.hypot(y) Returns the square root of the sum of the squares of a and b. Or equivalently, the distance from the origin to the point (x, y). See also atan2. In this example, hypot is used to calculate a doppler shift pitch and amplitude based on distance.
( { var x, y, distance, velocity, pitchRatio, amplitude; // object travels 200 meters in 6 secs (=120kph) passing 10 meters // from the listener x = 10; y = LFSaw.kr(1/6, 0, 100); distance = hypot(x, y); velocity = Slope.kr(distance); pitchRatio = (344 - velocity) / 344; amplitude = 10 / distance.squared; FSinOsc.ar(1000 * pitchRatio, 0, amplitude) }.play) // speed of sound is 344 meters/sec

The next example uses the distance to modulate a delay line.
( { var x, y, distance, velocity, pitchRatio, amplitude, motorSound; // object travels 200 meters in 6 secs (=120kph) passing 10 meters // from the listener x = 10;

45

0. DelayL.ar(31. 100).ar(200. 110/344. motorSound = RLPF.4)).3.Where: Help→BinaryOps→Hypot y = LFSaw. 0. 0. LFPulse. 400. distance/344. y).3).squared.ar(motorSound. amplitude) }. 0.kr(1/6.ar(FSinOsc. amplitude = 40 / distance. distance = hypot(x.play) 46 . 0.

Where: Help→BinaryOps→Hypotapx ID: 21 hypotApx hypotenuse approximation BinaryOperator hypotApx(x. abs(y))) hypotApx is used to implement Complex method magnitudeApx.((sqrt(2) . This should not be used for simulating a doppler shift because it is discontinuous. 47 . The formula used is : abs(x) + abs(y) . See also hypot. Use hypot.hypotApx(y) Returns an approximation of the square root of the sum of the squares of x and y.1) * min(abs(x). y) x hypotApx: y x. atan2.

trig = SinOsc.kr(Amplitude. 2) // This synth has no output.0. EnvGen.kr(Env.2). otherwise it is 0. trig. 48 .) 0) ( // trigger a synth SynthDef("help-EnvGen". Out.kr(AudioIn.local. ( // trigger an envelope { var trig.Where: Help→BinaryOps→Lessorequalthan ID: 22 <= less than or equal BinaryOperator a <= b Result is 1 if a <= b.ar(440. Out.play(s).perc.ar(out. { SendTrig. among other things: s = Server.2 // to < 0. This can be useful for triggering purposes.ar(1)) <= 0.perc.ar(1) <= 0.2 SynthDef("help-<= trig".{ argout=0.0.kr(Env.send(s).0.ar(0. EnvGen. doneAction: * SinOsc.play(s).0.0.1. s. It only checks amplitude of input and looks for a transition from > 0.doneAction: * SinOsc.1) ) }.1) ) }). }).boot.ar(440.

’/tr’. ) 49 .addr.new("help-EnvGen") }).postln.add.{ "triggered". Synth.Where: Help→BinaryOps→Lessorequalthan // responder to trigger synth OSCresponderNode(s.

2 SynthDef("help-< trig". It only checks amplitude of input and looks for a transition from > 0.play(s).kr(AudioIn.ar(1)) <= 0.ar(440. }).ar(0.1. { SendTrig.play(s).1) ) }). trig.perc. ( // trigger an envelope { var trig.0.Where: Help→BinaryOps→Lessthan ID: 23 < less than BinaryOperator a<b Result is 1 if a < b. Out.ar(out. Out.{ argout=0. This can be useful for triggering purposes.kr(Amplitude.boot.kr(Env.kr(Env.0.1) ) }.2 // to < 0.local. otherwise it is 0. s. doneAction: * SinOsc.0.ar(440.perc.doneAction: * SinOsc.0. 2) // This synth has no output. EnvGen.send(s).ar(1) < 0. EnvGen. 50 .) 0) ( // trigger a synth SynthDef("help-EnvGen".2).0. trig = SinOsc. among other things: s = Server.

postln.’/tr’. ) 51 .new("help-EnvGen") }). Synth.{ "triggered".Where: Help→BinaryOps→Lessthan // responder to trigger synth OSCresponderNode(s.add.addr.

z max: FSinOsc.max(b) ( { var z.ar(500).ar(0. b) a max: b a. }. z = FSinOsc.play) // modulates and envelopes z 52 .Where: Help→BinaryOps→Max ID: 24 max maximum BinaryOperator max(a.1).

min(b) ( { var z. b) a min: b a.ar(500).1).play) // distorts and envelopes z 53 . z = FSinOsc.Where: Help→BinaryOps→Min ID: 25 min minimum BinaryOperator min(a. z min: FSinOsc. }.ar(0.

4) % 1 }.Where: Help→BinaryOps→Modulo ID: 26 % modulo BinaryOperator a%b Outputs a modulo b. { FSinOsc.play // results in a sawtooth wave 54 .ar(100.

0.play. 200.kr(100.Where: Help→BinaryOps→Multiplication ID: 27 * multiplication BinaryOperator a*b // Same as mul: 0. { FSinOsc. 55 .kr(10) * PinkNoise. // This is ring modulation.ar(440) * 0.5 }. 0.ar(XLine.5) }. 10). // This creates a beating effect (subaudio rate). 1001.play.5) * SyncSaw.ar(0. { SinOsc.5) }.ar(100. 0.5 { SinOsc.play.

ar(XLine. b = FSinOsc.500. a = FSinOsc. (a * b) * 0.125 }. { (FSinOsc. ring1.ar(800) ring1: FSinOsc.Where: Help→BinaryOps→Ring1 ID: 28 ring1 ring modulation plus first source BinaryOperator Return the value of ((a*b) + a). same as : ( { var a.ar(800).125 }. ring3.ar(800).5))) * 0.5)). ring2.ar(XLine.500. a = FSinOsc. b.ar(XLine.kr(200.play) 56 . b = FSinOsc. This is more efficient than using separate unit generators for the multiply and add. b. ring4.play) normal ring modulation: ( { var a. See also *.play.125 }.kr(200.kr(200. ((a * b) + a) * 0.500.5)).

ring3.kr(200.125 }. { (FSinOsc. b. See also *. a = FSinOsc. same as : ( { var a.Where: Help→BinaryOps→Ring2 ID: 29 ring2 ring modulation plus both sources BinaryOperator Return the value of ((a*b) + a + b).ar(800).5))) * 0.500. ring4. This is more efficient than using separate unit generators for the multiply and adds.500.kr(200. ring2.5)).ar(800) ring2: FSinOsc.play) 57 . b = FSinOsc. ((a * b) + a + b) * 0.125 }.ar(XLine.ar(XLine.play. ring1.

5)).Where: Help→BinaryOps→Ring3 ID: 30 ring3 ring modulation variant BinaryOperator Return the value of (a*a *b). ring2. (a * a * b) * 0. ring3. same as : ( { var a.ar(800).125 }.500.play. }.ar(800) ring3: FSinOsc.125. b = FSinOsc. This is more efficient than using separate unit generators for each multiply.ar(XLine. ring1.kr(200. { (FSinOsc. a = FSinOsc. ring4.play) 58 .5))) * 0.kr(200.500. See also *.ar(XLine. b.

kr(200.(a*b*b)).5)).kr(200.500.ar(XLine.125 }. b. ring3.ar(800) ring4: FSinOsc. same as : ( { var a.ar(800).play. a = FSinOsc. This is more efficient than using separate unit generators for each operation. ring4. ring1. { (FSinOsc.ar(XLine. ring2.play) 59 .125 }. See also *.(a * b * b)) * 0.500. ((a * a * b) .5))) * 0. b = FSinOsc.Where: Help→BinaryOps→Ring4 ID: 31 ring4 ring modulation variant BinaryOperator Return the value of ((a*a *b) .

60 .Where: Help→BinaryOps→Round ID: 32 round rounding BinaryOperator round(a.round(b) Rounds a to the nearest multiple of b. b) a round: b a.

scaleneg(b) a*b when a < 0.play.4)) }. b) a scaleneg: b a. { FSinOsc.scaleneg(Line.ar(1.ar(500). 61 . otherwise a.Where: Help→BinaryOps→Scaleneg ID: 33 scaleneg scale negative part of input wave BinaryOperator scaleneg(a.-1.

ar(XLine.ar(800) sqrdif: FSinOsc. { (FSinOsc.5))) * 0. c.ar(XLine. c = a . b.Where: Help→BinaryOps→Sqrdif ID: 34 sqrdif square of the difference BinaryOperator Return the value of (a .500.500.kr(200. b = FSinOsc.ar(800).5)).b.125 }.play) 62 . same as : ( { var a.play. a = FSinOsc. (c * c) * 0. This is more efficient than using separate unit generators for each operation.125 }.kr(200.b)**2.

125 }. { (FSinOsc. b.5))) * 0.ar(800). same as : ( { var a.ar(800) sqrsum: FSinOsc. a = FSinOsc. (c * c) * 0. c.ar(XLine.play.kr(200.Where: Help→BinaryOps→Sqrsum ID: 35 sqrsum square of the sum BinaryOperator Return the value of (a + b)**2.ar(XLine.5)).500.play) 63 . c = a + b. b = FSinOsc. This is more efficient than using separate unit generators for each operation.kr(200.125 }.500.

z = FSinOsc.z // results in silence }. ( { var z.0.ar(800.play) 64 . z .25).Where: Help→BinaryOps→Subtraction ID: 36 - subtraction BinaryOp a-b Subtracts the output of a ugen from something else.

Where: Help→BinaryOps→Sumsqr

ID: 37

sumsqr

sum of squares

BinaryOperator Return the value of (a*a) + (b*b). This is more efficient than using separate unit generators for each operation.
{ (FSinOsc.ar(800) sumsqr: FSinOsc.ar(XLine.kr(200,500,5))) * 0.125 }.play;

same as :
( { var a, b; a = FSinOsc.ar(800); b = FSinOsc.ar(XLine.kr(200,500,5)); ((a * a) + (b * b)) * 0.125 }.play)

65

Where: Help→BinaryOps→Thresh

ID: 38

thresh

signal thresholding

BinaryOperator thresh(a, b) a thresh: b a.thresh(b)

0 when a < b, otherwise a.
{ LFNoise0.ar(50, 0.5) thresh: 0.45 }.play // a low-rent gate

66

Where: Help→BinaryOps→Trunc

ID: 39

trunc truncation
BinaryOperator trunc(a, b) a trunc: b a.trunc(b) Truncate a to a multiple of b.

67

Where: Help→BinaryOps→Wrap2

ID: 40

wrap2

bilateral wrapping

BinaryOperator wrap2(a, b) a wrap2: b a.wrap2(b) wraps input wave to +/- b
{ FSinOsc.ar(1000).wrap2(Line.kr(0,1.01,8)) }.scope;

68

3 Collections

69

Where: Help→Collections→Array

ID: 41

Array
Superclass: ArrayedCollection Arrays are ArrayedCollections whose slots may contain any object. Arrays have a fixed maximum size beyond which they cannot grow. For expandable arrays, use the List class. An array can be created with a fixed maxiumum capacity:
z = Array.new(size);

Which will return an array of size 0, but the capability to add up to 32 objects.
z = z.add(obj);

z now has a size of 1. For Arrays, the ’add’ method may or may not return the same Array object. It will add the argument to the receiver if there is space, otherwise it returns a new Array object with the argument added. Thus the proper usage of ’add’ with an Array is to always assign the result as follows:
z = z.add(obj);

This allows an efficient use of resources, only growing the array when it needs to. The List class manages the Array for you, and in many cases in more suitable. An array can be created with all slots filled with nils:
z = Array.newClear(size);

Elements can be put into an existing slot:
a.put(2,obj);

And accessed :

70

Where: Help→Collections→Array

a.at(2); // these are equivalent a[2];

See [ArrayedCollection] for the principal methods: at put clipAt, wrapAt etc. Literal Arrays can be created at compile time, and are very efficient. See [Literals] for information.

Class Methods
*with(... args) Create a new Array whose slots are filled with the given arguments. This is the same as the method in ArrayedCollection, but is reimplemented here to be more efficient.
Array.with(7, ’eight’, 9).postln;

Instance Methods
reverse Returns a new Array whose elements are reversed. The receiver is unchanged.
[1, 2, 3].reverse.postln;

( x = [1, 2, 3]; z = x.reverse; x.postln; z.postln; )

scramble Returns a new Array whose elements have been scrambled. The receiver is unchanged.

71

Where: Help→Collections→Array

[1, 2, 3, 4, 5, 6].scramble.postln;

mirror Return a new Array which is the receiver made into a palindrome. The receiver is unchanged.
[1, 2, 3, 4].mirror.postln;

mirror1 Return a new Array which is the receiver made into a palindrome with the last element removed. This is useful if the list will be repeated cyclically, the first element will not get played twice. The receiver is unchanged.
[1, 2, 3, 4].mirror1.postln;

mirror2 Return a new Array which is the receiver concatenated with a reversal of itself. The center element is duplicated. The receiver is unchanged.
[1, 2, 3, 4].mirror2.postln;

stutter(n) Return a new Array whose elements are repeated n times. The receiver is unchanged.
[1, 2, 3].stutter(2).postln;

rotate(n) Return a new Array whose elements are in rotated order. Negative n values rotate left, postive n values rotate right. The receiver is unchanged.
[1, 2, 3, 4, 5].rotate(1).postln;

72

Where: Help→Collections→Array

[1, 2, 3, 4, 5].rotate(-1).postln;

[1, 2, 3, 4, 5].rotate(3).postln;

pyramid Return a new Array whose elements have been reordered via one of 10 "counting" algorithms. The algorithms are numbered 1 through 10. Run the examples to see the algorithms.
[1, 2, 3, 4].pyramid(1).postln;

( 10.do({ arg i; [1, 2, 3, 4].pyramid(i + 1).asCompileString.postln; }); )

lace(length) Returns a new Array whose elements are interlaced sequences of the elements of the receiver’s subcollections, up to size length. The receiver is unchanged.
( x = [ [1, 2, 3], 6, List["foo", ’bar’]]; y = x.lace(12); x.postln; y.postln; )

permute(nthPermutation) Returns a new Array whose elements are the nthPermutation of the elements of the receiver. The receiver is unchanged.
( x = [ 1, 2, 3]; 6.do({| i| x.permute(i).postln;}); )

73

Where: Help→Collections→Array

wrapExtend(length) Returns a new Array whose elements are repeated sequences of the receiver, up to size length. The receiver is unchanged.
( x = [ 1, 2, 3, "foo", ’bar’ ]; y = x.wrapExtend(9); x.postln; y.postln; )

foldExtend(length) Same as lace but the sequences fold back on the list elements.
( x = [ 1, 2, "foo"]; y = x.foldExtend(9); x.postln; y.postln; )

slide(windowLength, stepSize) Return a new Array whose elements are repeated subsequences from the receiver. Easier to demonstrate than explain.
[1, 2, 3, 4, 5, 6].slide(3, 1).asCompileString.postln;

[1, 2, 3, 4, 5, 6].slide(3, 2).asCompileString.postln;

[1, 2, 3, 4, 5, 6].slide(4, 1).asCompileString.postln;

containsSeqColl Returns true if the receiver Array contains any instance of SequenceableCollection

74

Where: Help→Collections→Array

[1, 2, 3, 4].containsSeqColl.postln

[1, 2, [3], 4].containsSeqColl.postln

multiChannelExpand Used by UGens to perform multi channel expansion. source Some UGens return Arrays of OutputProxy when instantiated. This method allows you to get at the source UGen.
( z = Pan2.ar; z.postln; z.source.postln; )

fork(join, clock, quant, stackSize) Used within Routines and assumes an array of functions, from which subroutines are created. The subroutines are played while the outer Routine carries on. The join parameter expresses after how many subroutines complete the outer Routine is allowed to go on. By default this happens after all subroutines have completed.

// an array of routine functions: ( a = [ { 1.wait; \done_one.postln }, { 0.5.wait; \done_two.postln }, { 0.2.wait; \done_three.postln } ]; )

// join after 0

75

Where: Help→Collections→Array

( Routine{ "join = 0.".postcln; a.fork(0); \doneAll.postln; }.play; ) // join after 1 ( Routine{ "join = 1.".postcln; a.fork(1); \doneAll.postln; }.play; ) // join after all ( Routine{ "join = a.size (default).".postcln; a.fork; \doneAll.postln; }.play; )

atIdentityHash(argKey) This method is used by IdentitySet to search for a key among its members. atIdentityHashInPairs(argKey) This method is used by IdentityDictionary to search for a key among its members. asShortString Returns a short string representing the Array that only shows how many elements it contains asString Returns a string representing the Array. May not be compileable due to ellision (...) of excessive arguments.

76

Where: Help→Collections→Array

asCompileString Returns a string that will compile to return an Array equal to the receiver. isValidUGenInput Returns true. Arrays are valid UGen inputs.

77

Where: Help→Collections→ArrayedCollection

ID: 42

ArrayedCollection
Superclass: SequenceableCollection ArrayedCollection is an abstract class, a subclass of SequenceableCollections whose elements are held in a vector of slots. Instances of ArrayedCollection have a fixed maximum size beyond which they may not grow. Its principal subclasses are Array (for holding objects), and RawArray, from which Int8Array, FloatArray,Signal etc. inherit.

Class Methods
*with(... args) Create a new ArrayedCollection whose slots are filled with the given arguments.
Array.with(7, ’eight’, 9).postln;

*series(size, start, step) Fill an ArrayedCollection with an arithmetic series.
Array.series(5, 10, 2).postln;

*geom(size, start, grow) Fill an ArrayedCollection with a geometric series.
Array.geom(5, 1, 3).postln;

Instance Methods
at(index)

78

Where: Help→Collections→ArrayedCollection

Return the item at index. clipAt(index) Same as at, but values for index greater than the size of the ArrayedCollection will be clipped to the last index.
y = [ 1, 2, 3 ]; y.clipAt(13).postln;

wrapAt(index) Same as at, but values for index greater than the size of the ArrayedCollection will be wrapped around to 0.
y = [ 1, 2, 3 ]; y.wrapAt(3).postln; // this returns the value at index 0 y.wrapAt(4).postln; // this returns the value at index 1

foldAt(index) Same as at, but values for index greater than the size of the ArrayedCollection will be folded back.
y = [ 1, 2, 3 ]; y.foldAt(3).postln; // this returns the value at index 1 y.foldAt(4).postln; // this returns the value at index 0 y.foldAt(5).postln; // this returns the value at index 1

swap(i, j) Swap the values at indices i and j.
[ 1, 2, 3 ].swap(0, 2).postln;

put(index, item) Put item at index, replacing what is there. clipPut(index, item)

79

Where: Help→Collections→ArrayedCollection

Same as put, but values for index greater than the size of the ArrayedCollection will be clipped to the last index. wrapPut(index, item) Same as put, but values for index greater than the size of the ArrayedCollection will be wrapped around to 0. foldPut(index) Same as put, but values for index greater than the size of the ArrayedCollection will be folded back. removeAt(index) Remove and return the element at index, shrinking the size of the ArrayedCollection.
y = [ 1, 2, 3 ]; y.removeAt(1); y.postln;

takeAt(index) Same as removeAt, but reverses the order of the items following those that which was taken.
y = [ 1, 2, 3, 4 ]; y.takeAt(1); y.postln;

add(item) Adds an item to an ArrayedCollection if there is space. If there is not any space left in the object then this method returns a new ArrayedCollection. For this reason, you should always assign the result of add to a variable - never depend on add changing the receiver.
( // z and y are the same object

80

Where: Help→Collections→ArrayedCollection

var y, z; z = [1, 2, 3]; y = z.add(4); z.postln; y.postln; )

( // in this case a new object is returned var y, z; z = [1, 2, 3, 4]; y = z.add(5); z.postln; y.postln; )

addAll(aCollection) Adds all the elements of aCollection to the contents of the receiver, possibly returning a new collection.
( // in this case a new object is returned var y, z; z = [1, 2, 3, 4]; y = z.addAll([7, 8, 9]); z.postln; y.postln; )

fill(value) Inserts the item into the contents of the receiver, possibly returning a new collection. Note the difference between this and Collection’s *fill.
( var z; z = List[1, 2, 3, 4]; z.fill(4).postln; z.fill([1,2,3,4]).postln;

81

Where: Help→Collections→ArrayedCollection

)

insert(index, item) Inserts the item into the contents of the receiver, possibly returning a new collection.
( // in this case a new object is returned var y, z; z = [1, 2, 3, 4]; y = z.insert(1, 999); z.postln; y.postln; )

addFirst(item) Inserts the item before the contents of the receiver, possibly returning a new collection.
( // in this case a new object is returned var y, z; z = [1, 2, 3, 4]; y = z.addFirst(999); z.postln; y.postln; )

pop Remove and return the last element of the ArrayedCollection.
( var z; z = [1, 2, 3, 4]; z.pop.postln; z.postln; )

grow(sizeIncrease)

82

Where: Help→Collections→ArrayedCollection

Increase the size of the ArrayedCollection by sizeIncrease number of slots, possibly returning a new collection. copyRange(start, end) Return a new ArrayedCollection which is a copy of the indexed slots of the receiver from start to end.
( var y, z; z = [1, 2, 3, 4, 5]; y = z.copyRange(1,3); z.postln; y.postln; )

copySeries(first, second, last) Return a new ArrayedCollection consisting of the values starting at first, then every step of the distance between first and second, up until last.
( var y, z; z = [1, 2, 3, 4, 5, 6]; y = z.copySeries(0, 2, 5); y.postln; )

putSeries(first, second, last, value) Put value at every index starting at first, then every step of the distance between first and second, up until last.
( var y, z; z = [1, 2, 3, 4, 5, 6]; y = z.putSeries(0, 2, 5, "foo"); y.postln; )

83

Where: Help→Collections→ArrayedCollection

++ aCollection Concatenate the contents of the two collections into a new ArrayedCollection.
( var y, z; z = [1, 2, 3, 4]; y = z ++ [7, 8, 9]; z.postln; y.postln; )

reverse Return a new ArrayedCollection whose elements are reversed.
( var y, z; z = [1, 2, 3, 4]; y = z.reverse; z.postln; y.postln; )

do(function) Iterate over the elements in order, calling the function for each element. The function is passed two arguments, the element and an index.
[’a’, ’b’, ’c’].do({ arg item, i; [i, item].postln; });

reverseDo(function) Iterate over the elements in reverse order, calling the function for each element. The function is passed two arguments, the element and an index.
[’a’, ’b’, ’c’].reverseDo({ arg item, i; [i, item].postln; });

windex

84

Where: Help→Collections→ArrayedCollection

Interprets the array as a list of probabilities which should sum to 1.0 and returns a random index value based on those probabilities.
( Array.fill(10, { [0.1, 0.6, 0.3].windex; }).postln; )

normalizeSum Returns the Array resulting from :
(this / this.sum)

so that the array will sum to 1.0. This is useful for using with windex or wchoose.
[1, 2, 3].normalizeSum.postln;

performInPlace(selector, from, to, argList) performs a method in place, within a certain region [from..to], returning the same array.

a = (0..10); a.performInPlace(\normalizeSum, 3, 6);

85

Where: Help→Collections→Association

ID: 43

Association
superclass: Magnitude Associates a key with a value. Associations can be created via the -> operator which is defined in class Object.
( x = ’name’ -> 100; x.postln; )

Accessing
<>key the key object. <>value the value object.

Creation
*new(key, value) Create an Association between two objects. key - any object. value - any object.

Testing
== anAssociation Compare the keys of two Associations.

86

Where: Help→Collections→Association

< anAssociation Compare the keys of two Associations. hash Compute the hash value of the Association.

Streams
printOn(stream) Write a string representation to the stream. storeOn(stream) Write a compileable string representation to the stream.

87

Where: Help→Collections→Bag

ID: 44

Bag
Superclass: Collection A Bag is an unordered collection of objects. In some languages it is referred to as a counted set. A Bag keeps track of the number of times objects are inserted and requires that objects be removed the same number of times. Thus, there is only one instance of an object in a Bag even if the object has been added to the Bag multiple times. Most of Bag’s methods are inherited from Collection. The contents of a Bag are unordered. You must not depend on the order of items in a set.

Adding and Removing:
add(anObject) Add anObject to the Bag. A Bag may contain multiple entries of the same object.
Bag[1, 2, 3].add(4).postln;

Bag[1, 2, 3].add(3).postln;

Bag["abc", "def", "ghi"].add("jkl").postln;

Bag["abc", "def", "ghi"].add("def").postln;

remove(anObject) Remove anObject from the Bag.
Bag[1, 2, 3].remove(3).postln;

Iteration:
do(function)

88

Where: Help→Collections→Bag

Evaluates function for each item in the Bag. The function is passed two arguments, the item and an integer index.
Bag[1, 2, 3, 300].do({ arg item, i; item.postln });

89

Where: Help→Collections→Collection

ID: 45

Collection
superclass: Object Collections are groups of objects. Collection is an abstract class. You do not create direct instances of Collection. There are many types of Collections including List, Array, Dictionary, Bag, Set, SortedList, etc. See the Collections overview for a complete listing of all subclasses.

Class Methods:
*fill(size, function) Creates a Collection of the given size, the elements of which are determined by evaluation the given function. The function is passed the index as an argument.
Array.fill(4, {arg i; i * 2}).postln;

Accessing:
size Answers the number of objects contained in the Collection.
List[1, 2, 3, 4].size.postln;

isEmpty Answer whether the receiver contains no objects.
List[].isEmpty.postln;

Adding and Removing:
add(anObject) Add anObject to the receiver.

90

Where: Help→Collections→Collection

List[1, 2].add(3).postln;

addAll(aCollection) Add all items in aCollection to the receiver.
List[1, 2].addAll(List[3, 4]).postln;

remove(anObject) Remove anObject from the receiver. Answers the removed object.
( var a; a = List[1, 2, 3, 4]; a.remove(3).postln; a.postln; )

removeAll(aCollection) Remove all items in aCollection from the receiver.
List[1, 2, 3, 4].removeAll(List[2, 3]).postln;

removeAllSuchThat(function) Remove all items in the receiver for which function answers true. The function is passed two arguments, the item and an integer index. Answers the objects which have been removed.
( var a; a = List[1, 2, 3, 4]; a.removeAllSuchThat({ arg item, i; item < 3 }).postln; a.postln; )

Testing:

91

Where: Help→Collections→Collection

includes(anObject) Answer whether anObject is contained in the receiver.
List[1, 2, 3, 4].includes(3).postln;

includesAny(aCollection) Answer whether any item in aCollection is contained in the receiver.
List[1, 2, 3, 4].includesAny(List[4, 5]).postln;

includesAll(aCollection) Answer whether all items in aCollection are contained in the receiver.
List[1, 2, 3, 4].includesAll(List[4, 5]).postln;

Iteration:
do(function) Evaluates function for each item in the collection. The function is passed two arguments, the item and an integer index.
List[1, 2, 3, 4].do({ arg item, i; item.postln });

collect(function) Answer a new collection which consists of the results of function evaluated for each item in the collection. The function is passed two arguments, the item and an integer index.
List[1, 2, 3, 4].collect({ arg item, i; item + 10 }).postln;

select(function) Answer a new collection which consists of all items in the receiver for which function answers true. The function is passed two arguments, the item and an integer index.

92

Where: Help→Collections→Collection

List[1, 2, 3, 4].select({ arg item, i; item.even }).postln;

reject(function) Answer a new collection which consists of all items in the receiver for which function answers false. The function is passed two arguments, the item and an integer index.
List[1, 2, 3, 4].reject({ arg item, i; item.even }).postln;

detect(function) Answer the first item in the receiver for which function answers true. The function is passed two arguments, the item and an integer index.
List[1, 2, 3, 4].detect({ arg item, i; item.even }).postln;

inject(initialValue, function) In functional programming, the operation known as a fold. inject takes an initial value and a function and combines the elements of the collection by applying the function to the accumulated value and an element from the collection. The function takes two arguments and returns the new value. The accumulated value is initialzed to initialValue.
[1,2,3,4,5].inject(0, _+_);

15

[1,2,3,4,5].inject(1, _*_);

120

[1,2,3,4,5].inject([], {| a,b| a ++ b.squared }); // same as .collect(_.squared)

[ 1, 4, 9, 16, 25 ]

[1,2,3,4,5].inject([], {| a,b| [b] ++ a ++ [b]});

[ 5, 4, 3, 2, 1, 1, 2, 3, 4, 5 ]

93

Where: Help→Collections→Collection

[1,2,3,4,5].inject([], {| a,b| a ++ b ++ a});

[ 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, 5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1 ]

[1,2,3,4,5].inject([], {| a,b| a ++ a ++ b});

[ 1, 1, 2, 1, 1, 2, 3, 1, 1, 2, 1, 1, 2, 3, 4, 1, 1, 2, 1, 1, 2, 3, 1, 1, 2, 1, 1, 2, 3, 4, 5 ]

any(function) Answer whether function answers true for any item in the receiver. The function is passed two arguments, the item and an integer index.
List[1, 2, 3, 4].any({ arg item, i; item.even }).postln;

every(function) Answer whether function answers true for every item in the receiver. The function is passed two arguments, the item and an integer index.
List[1, 2, 3, 4].every({ arg item, i; item.even }).postln;

count(function) Answer the number of items for which function answers true. The function is passed two arguments, the item and an integer index.
List[1, 2, 3, 4].count({ arg item, i; item.even }).postln;

occurencesOf(anObject) Answer the number of items in the receiver which are equal to anObject.
List[1, 2, 3, 3, 4, 3, 4, 3].occurencesOf(3).postln;

sum(function) Answer the sum of the results of function evaluated for each item in the receiver. The function is passed two arguments, the item and an integer index.

94

Where: Help→Collections→Collection

List[1, 2, 3, 4].sum.postln;

(0..8).sum { | i| 1 / (2 ** i) };

maxItem(function) Answer the maximum of the results of function evaluated for each item in the receiver. The function is passed two arguments, the item and an integer index. If function is nil, then answer the maximum of all items in the receiver.
List[1, 2, 3, 4].maxItem({ arg item, i; item + 10 }).postln;

minItem(function) Answer the minimum of the results of function evaluated for each item in the receiver. The function is passed two arguments, the item and an integer index. If function is nil, then answer the minimum of all items in the receiver.
List[1, 2, 3, 4].minItem({ arg item, i; item + 10 }).postln;

Conversion:
asBag Answer a Bag to which all items in the receiver have been added.
List[1, 2, 3, 4].asBag.postln;

asList Answer a List to which all items in the receiver have been added.
List[1, 2, 3, 4].asList.postln;

asSet Answer a Set to which all items in the receiver have been added.

95

Where: Help→Collections→Collection

List[1, 2, 3, 4].asList.postln;

asSortedList Answer a SortedList to which all items in the receiver have been added.
List[2, 1, 4, 3].asSortedList.postln;

printOn(stream) Print a representation of the collection to a stream. storeOn(stream) Write a compileable representation of the collection to a stream. printItemsOn(stream) Print a comma separated compileable representation of the items in the collection to a stream. storeItemsOn(stream) Write a comma separated compileable representation of the items in the collection to a stream.

96

Where: Help→Collections→Collections

ID: 46

Collections
SuperCollider has a rich hierarchy of Collection subclasses. Collection’s class subtree is detailed below. Subclasses of a given class are indented and enclosed in (possibly nested) square brackets. Most of these subclasses have their own helpfiles. Classes labelled abstract are not for direct use, but classes lower down the tree may inherit methods from them. For this reason it is important to consult the helpfiles of classes farther up the tree in order to get a complete list of available methods.

Collection abstract superclass of all Collection subclasses many methods are inherited from this class [ Array2D a two dimensional array Range Interval ranges of values ranges of Integers with a fixed Interval between them

MultiLevelIdentityDictionary a tree of IdentityDictionaries [ Library ] a unique global MultiLevelIdentityDictionary

Set an unordered collection of unequal objects [ Dictionary an unordered associative collection mapping keys to values [ IdentityDictionary a Dictionary wherein keys match only if identical (rather than if simply equal) [ Environment an IdentityDictionary, one of which is always current; useful for creating sets of persistent variables [ Event ] a Dictionary mapping names of musical parameters to their values NameDictionary an IdentityDictionary for adding named objects

97

Where: Help→Collections→Collections

(objects with a .name method) such that name -> namedObject ] ] IdentitySet an unordered collection of unidentical objects (compare to Set) ] Bag an unordered collection of objects Pair Lisp-like two element cells

TwoWayIdentityDictionary an IdentityDictionary which allows easy searching by both key and value; faster than IdentityDictionary on reverse lookup, but with more memory overhead [ ObjectTable ] associates Integer ids with objects

SequenceableCollection abstract superclass of collections whose objects can be indexed by integer [ Order SequenceableCollection with an indices instance variable LinkedList a doubly linked list

List an expandable SequenceableCollection (compare to ArrayedCollection and Array) [ SortedList ] a List whose items are kept in a sorted order

ArrayedCollection abstract superclass of Collections of fixed maximum size whose elements are held in a vector of slots [ RawArray abstract superclass of array classes that hold raw data values [ DoubleArray a RawArray of double precision floats FloatArray [ a RawArray of floats

98

Where: Help→Collections→Collections

Wavetable

a special format FloatArray

Signal a FloatArray that represents a sampled function of time buffer ] String an array of characters SymbolArray Int32Array Int16Array a RawArray of symbols a RawArray of 32 bit Integers a RawArray of 16 bit Integers

Int8Array a RawArray of 8 bit Integers ] Array an ArrayedCollection whose slots may contain any object; more efficient than List ] ] ]

99

Where: Help→Collections→Dictionary

ID: 47

Dictionary
Superclass: Set A Dictionary is an associative collection mapping keys to values. Two keys match if they are equal. i.e. == returns true. The contents of a Dictionary are unordered. You must not depend on the order of items in a Dictionary.

Creation:
*new(n) Creates a Dictionary with an initial capacity for n key value mappings.

Adding and Removing:
add(anAssociation) Add anAssociation to the Dictionary. If the key value pair already exists in the Dictionary, the key’s value will be replaced.
( d = Dictionary.new; d.add(’monkey’ -> 0).postln; // Add robot as a key with a value of 1 d.add(’robot’ -> 1).postln; // Replaces the value for the key monkey with 2 d.add(’monkey’ -> 2).postln; )

put(key, obj) Associate two objects and add them to the Dictionary. key - key to associate with object obj - an object

100

Where: Help→Collections→Dictionary

d.put("abc", 10).postln;

removeAt(key) Remove the key and the value associated with it from the Dictionary.
d.removeAt(’monkey’).postln;

Accessing:
at(key) Access the value associated with the key.
// Get the value associated with key d.at(’robot’); // Key doesn’t exist d.at(’monkey’);

matchAt(item) The dictionary’s keys are used as conditions against which the arbitrary item is matched. Note: if an item matches multiple criteria, the value returned is arbitrary. This is because a dictionary is an unordered collection. It’s the user’s responsibility to make sure that criteria are mutually exclusive. If the key is an object, the item will be matched by identity (if key === item, the value will be returned). If the key is a collection, the item is matched if it’s contained in the collection. If the key is a function, the function is evaluated with the item as an argument and the item is matched if the function returns true.
d = Dictionary[ 0 -> ’zero’, ’abc’-> ’alpha’, [1, 2, 3, 5, 8, 13, 21] -> ’fibonacci’, { | x| ]; x.even } -> ’even’

101

Where: Help→Collections→Dictionary

d.matchAt(0) d.matchAt(1) d.matchAt(2) d.matchAt(4) d.matchAt(’abc’) // matches both ’fibonacci’ and ’even’, but ’fibonacci’ is returned

102

Where: Help→Collections→DoubleArray

ID: 48

Int8Array, Int16Array, Int32Array, RGBArray, FloatArray, DoubleArray
Superclass: RawArray These classes implement arrays whose indexed slots are all of the same type. Int8Array - 8 bit integer Int16Array - 16 bit integer Int32Array - 32 bit integer RGBArray - 32 bit color FloatArray - 32 bit floating point DoubleArray - 64 bit floating point These classes implement only one method. *readNew(file) Called by *read to read the entire file as an array of this class’ type and return a new instance.

103

Where: Help→Collections→Environment

ID: 49

Environment
superclass: IdentityDictionary An Environment is an IdentityDictionary mapping Symbols to values. There is always one current Environment which is stored in the currentEnvironment class variable of class Object. Symbol and value pairs may be put into the current Environment as follows:
currentEnvironment.put(\myvariable, 999);

and retrieved from the current Environment as follows:
currentEnvironment.at(\myvariable).postln;

The compiler provides a shorthand for the two constructs above .
myvariable = 888;

is equivalent to:
currentEnvironment.put(\myvariable, 888);

and:
myvariable.postln;

is equivalent to:
currentEnvironment.at(\myvariable).postln;

Making an Environment
Environment has a class method make which can be used to create an Environment and fill it with values. What 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.

104

Where: Help→Collections→Environment

( var a; a = Environment.make({ a = 100; b = 200; c = 300; }); a.postln; )

Using an Environment
The instance method use lets you temporarily replace the current Environment with one you have made. The use method returns the result of your function instead of the Environment like make does.
( var a; a = Environment.make({ a = 10; b = 200; c = 3000; }); a.use({ a + b + c

}).postln; )

There is also a use class method for when you want to make and use the result from an Environment directly.
( var a; a = Environment.use({ a = 10; b = 200; c = 3000; a + b + c

}).postln;

105

Where: Help→Collections→Environment

)

Calling Functions with arguments from the current Environment
It is possible to call a Function and have it look up any unspecified argument values from the current Environment. This is done with the valueEnvir and 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.
( var f;

// define a function f = { arg x, y, z; [x, y, z].postln; };

Environment.use({ x = 7; y = 8; z = 9;

f.valueEnvir(1, 2, 3); // all values supplied f.valueEnvir(1, 2); // z is looked up in the current Environment f.valueEnvir(1); f.valueEnvir; f.valueEnvir(z: }); ) // y and z are looked up in the current Environment // all arguments are looked up in the current Environment 1); // x and y are looked up in the current Environment

Now here is how this can be used with an instrument function. Environments allow you to define instruments without having to worry about argument ordering conflicts. 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.
s.boot;

( var a, b, c, orc;

106

Where: Help→Collections→Environment

a = { arg freq, amp, pan; Pan2.ar(SinOsc.ar(freq), pan, amp); }; b = { arg amp, pan, freq;

Pan2.ar(RLPF.ar(Saw.ar(freq), freq * 6, 0.1), pan, amp); }; c = { arg pan, freq, amp;

Pan2.ar(Resonz.ar(GrayNoise.ar, freq * 2, 0.1), pan, amp * 2); }; orc = [a, b, c]; // ’reverb’ { var in; in = In.ar(0, 2); CombN.ar(in, 0.2, 0.2, 3, 1, in); }.play(addAction: \addToTail);

{ loop({ Environment.use({ // set values in the environment freq = exprand(80, 600); amp = 0.1; pan = 1.0.rand2;

// call a randomly chosen instrument function // with values from the environment

x = { orc.choose.valueEnvir; }.play(fadeTime: 0.2.wait; x.release(0.2); }); }) }.fork;

0.2, addAction:

\addToHead);

)

107

Where: Help→Collections→Event

ID: 50

Event
superclass: Environment Events are dictionaries matching Symbols representing names of parameters for a musical event to their values. For more information on Events see: [Streams-Patterns-Events4] and [Streams-Patterns-Events5]

108

Where: Help→Collections→FloatArray

ID: 51

Int8Array, Int16Array, Int32Array, RGBArray, FloatArray, DoubleArray
Superclass: RawArray These classes implement arrays whose indexed slots are all of the same type. Int8Array - 8 bit integer Int16Array - 16 bit integer Int32Array - 32 bit integer RGBArray - 32 bit color FloatArray - 32 bit floating point DoubleArray - 64 bit floating point These classes implement only one method. *readNew(file) Called by *read to read the entire file as an array of this class’ type and return a new instance.

109

Where: Help→Collections→IdentityDictionary

ID: 52

IdentityDictionary
Superclass: Dictionary An IdentityDictionary is an associative collection mapping keys to values. Two keys match only if they are identical. The contents of an IdentityDictionary are unordered. You must not depend on the order of items in a IdentityDictionary. Often IdentityDictionaries are used with Symbols as the keys since Symbols are guaranteed to be identical if they have the same character representation (i.e. they are equal). Two equal Strings on the other hand might not be identical.

110

’ghi’]. An object which is equal to an object already in the IdentitySet will not be added. Different classes may implement equality in different ways.postln.add("def"). Adding and Removing: add(anObject) Add anObject to the IdentitySet. IdentitySets are faster than Sets because testing for identity is much faster than testing for equality. The contents of an IdentitySet are unordered. ’ghi’].postln. 2. Most of its methods are inherited. This allows some methods of IdentitySet to be implemented by fast primitives. You must not depend on the order of items in an IdentitySet. ’def’. "identical"). but identity can be determined just by comparing the object addresses. 111 .postln. "ghi"]. IdentitySet[1. 2.add(’def’). 3]. Look in the Collection class for the most of the relevant methods.add(4). "def".Where: Help→Collections→IdentitySet ID: 53 IdentitySet Superclass: Set An IdentitySet is collection of objects.add(’jkl’). IdentitySet[1.postln.postln. ’def’. // the two strings are equal but not identical IdentitySet["abc". // symbols are guaranteed to be identical if they are equal IdentitySet[’abc’. 3]. IdentitySet[’abc’. no two of which are the same object (aka.add(3).

2. i. 3. 300]. 3]. IdentitySet[1. Iteration: do(function) Evaluates function for each item in the IdentitySet. item. 112 . the item and an integer index.postln }).Where: Help→Collections→IdentitySet remove(anObject) Remove anObject from the IdentitySet. IdentitySet[1.do({ arg item.remove(3).postln. 2. The function is passed two arguments.

8 bit integer Int16Array .64 bit floating point These classes implement only one method.32 bit integer RGBArray .32 bit color FloatArray . 113 . Int8Array .Where: Help→Collections→Int16Array ID: 54 Int8Array.32 bit floating point DoubleArray . Int16Array. DoubleArray Superclass: RawArray These classes implement arrays whose indexed slots are all of the same type. Int32Array.16 bit integer Int32Array . FloatArray. RGBArray. *readNew(file) Called by *read to read the entire file as an array of this class’ type and return a new instance.

32 bit color FloatArray . DoubleArray Superclass: RawArray These classes implement arrays whose indexed slots are all of the same type. 114 . Int32Array. Int8Array . RGBArray.32 bit integer RGBArray .64 bit floating point These classes implement only one method. *readNew(file) Called by *read to read the entire file as an array of this class’ type and return a new instance.8 bit integer Int16Array .32 bit floating point DoubleArray .16 bit integer Int32Array . Int16Array.Where: Help→Collections→Int32Array ID: 55 Int8Array. FloatArray.

*readNew(file) Called by *read to read the entire file as an array of this class’ type and return a new instance.16 bit integer Int32Array .Where: Help→Collections→Int8Array ID: 56 Int8Array.32 bit floating point DoubleArray . Int16Array.32 bit integer RGBArray .32 bit color FloatArray .8 bit integer Int16Array . 115 . Int8Array . FloatArray. Int32Array.64 bit floating point These classes implement only one method. RGBArray. DoubleArray Superclass: RawArray These classes implement arrays whose indexed slots are all of the same type.

Interval. 30. 4). end. step) Create a new Interval. Instance Variables <>start The starting value of the interval.size.new(10. Interval.new(10. Instance Methods size Return the number of items in the interval. Creation *new(start. 4). <>step The step value of the interval. 30. <>end The ending value of the interval.Where: Help→Collections→Interval ID: 57 Interval superclass: Collection An Interval is a range of integers from a starting value to an ending value by some step value.postln.postln. 116 .

4).new(10.postln. 117 . item. 4). do(function) Evaluates function for each item in the interval. i.at(3).do({ arg item. 30. Interval. 30. the item and an integer index.new(10. The function is passed two arguments.postln }).Where: Help→Collections→Interval at(index) Return the indexed item in the interval. Interval.

The last argument to put is the object being inserted: Library.\level.\addressing.\system.at(\multi.\system]).\system). There is only one of them ever. postTree post a formatted description of the entire library Library.postTree.put(\multi.\addressing."i’m the thing you put in here").atList([\multi. 118 .postln.\level. Library.Where: Help→Collections→Library ID: 58 Library superclass: MultiLevelIdentityDictionary This is a single global MultiLevelIdentityDictionary.\level.\addressing.postln. Library.

add(obj) Add an item to the tail of the list. addFirst(obj) Add an item to the head of the list. 119 . Instance Methods Most methods are inherited from the superclasses. popFirst Remove and return the first item in the list.Where: Help→Collections→LinkedList ID: 59 LinkedList Superclass: SequenceableCollection LinkedList implements a doubly linked list. pop Remove and return the last item in the list. last Return the last item in the list. remove(obj) Remove an item from the list. first Return the first item in the list.

This requires a scan of the list and so is O(n). This requires a scan of the list and so is O(n). put(index. This requires a scan of the list and so is O(n). obj) Put the item at the given index in the list. 120 .Where: Help→Collections→LinkedList at(index) Return the item at the given index in the list. removeAt(index) Remove and return the item at the given index in the list.

You should not need to deal with a LinkedListNode directly. 121 .Where: Help→Collections→LinkedListNode ID: 60 LinkedListNode Superclass: Object LinkedListNode is used to implement the internal nodes of the LinkedList class.

(List implements many of the same methods. *newClear(size) Creates a List with the initial capacity given by size and slots filled with nil. 122 . z = x. ( x = Array.) List has no size limitation and is thus more flexible. 5. z.) Arrays have a fixed maximum size.new(3).}).Where: Help→Collections→List ID: 61 List Superclass: SequenceableCollection List is a subclass of SequenceableCollection with unlimited growth in size.add(i). y.postln.new(3). y. Creation *new(size) Creates a List with the initial capacity given by size. (See the Array helpfile. but you must use an assignment statement or the new array will be lost. *copyInstance(aList) Creates a List by copying aList’s array variable. Although not a subclass of Array or its superclass ArrayedCollection it uses an Array in its implementation and is in many cases interchangeable with one. x. If you add beyond that size a new Array is created and returned.add(i). ) Many of List’s methods are inherited from SequenceableCollection or Collection and are documented in those helpfiles.do({arg i. but has slightly more overhead.postln.postln. y = List.

Where: Help→Collections→List *newUsing(anArray) Creates a List using anArray. Instance Methods asArray Returns a new Array based upon this List. List[ 1. at(index) Return the item at index. ( x = List[1. x.postln. 2. 2.postln. ) array_(anArray) Sets the List’s Array. 3 ].clipAt(13). 123 . array Returns the List’s Array.postln. y. allowing it to be manipulated directly.add("foo"). 3].array. 3 ]. y = List[ 1.at(0). clipAt(index) Same as at. x. This should only be necessary for exotic manipulations not implemented in List or its superclasses. but values for index greater than the size of the List will be clipped to the last index. 2.

postln.foldAt(5). replacing what is there. y = List[ 1. item) Put item at index.postln. // this returns the value at index 1 put(index. item) Same as put. foldPut(index) Same as put. item) Same as put. y = List[ 1. // this returns the value at index 0 y. but values for index greater than the size of the List will be wrapped around to 0. 2.foldAt(4). add(item) Adds an item to the end of the List. y. but values for index greater than the size of the List will be folded back. but values for index greater than the size of the List will be wrapped around to 0. 3 ]. 2. but values for index greater than the size of the List will be folded back. clipPut(index.postln. but values for index greater than the size of the List will be clipped to the last index.postln.postln. 3 ].wrapAt(3). y.Where: Help→Collections→List wrapAt(index) Same as at. // this returns the value at index 1 foldAt(index) Same as at. // this returns the value at index 0 y. // this returns the value at index 1 y.wrapAt(4). wrapPut(index.foldAt(3). 124 .

y. 2.postln. removeAt(index) Remove and return the element at index.4]). 125 . y.Where: Help→Collections→List addFirst(item) Inserts the item at the beginning of the List. possibly returning a new collection.fill([1. grow(sizeIncrease) Increase the size of the List by sizeIncrease number of slots. ( var z. Note the difference between this and Collection’s *fill. fill(value) Inserts the item into the contents of the receiver. z = List[1. z. insert(index.3. 4]. the element and an index. The function is passed two arguments. z.postln. shrinking the size of the List.fill(4). item) Inserts the item into the contents of the List at the indicated index. y = List[ 1.postln.removeAt(1). 3 ]. pop Remove and return the last element of the List.2. 2. ) do(function) Iterate over the elements in order. calling the function for each element. 3.

2. then every step of the distance between first and second. ’c’]. 4. item]. ( 126 . y. second. last. i. 5). [i. z.postln. ’b’. last) Return a new List consisting of the values starting at first.postln. 2. z = List[1. z = List[1.Where: Help→Collections→List List[’a’. [i.postln. the element and an index.postln.reverseDo({ arg item. y. z. ’c’].copySeries(0. i. 3. copyRange(start. ) putSeries(first. The function is passed two arguments. up until last. calling the function for each element. second.do({ arg item. }). ) copySeries(first. 2. value) Put value at every index starting at first. then every step of the distance between first and second. 3. y = z.3).postln. 5]. item]. }). 4. ( var y. List[’a’. up until last. 6]. end) Return a new List which is a copy of the indexed slots of the receiver from start to end. z. ( var y. reverseDo(function) Iterate over the elements in reverse order. ’b’. 5. y = z.copyRange(1.

Where: Help→Collections→List var y.mirror. This is useful if the list will be repeated cyclically. The receiver is unchanged. 4. List[1.postln. 3. 5. y. ( var y. z. 3.scramble. 2.reverse. 2.postln.putSeries(0. The receiver is unchanged. 4. z = List[1. the first element will not get played twice. 2. 2. mirror Return a new List which is the receiver made into a palindrome. 5. 5.postln. y = z. y = z. 6]. mirror1 Return a new List which is the receiver made into a palindrome with the last element removed. 3. 4]. 3. List[1. 2. 6]. y. ) reverse Return a new List whose elements are reversed. ) scramble Returns a new List whose elements have been scrambled.postln.mirror1. 127 . The receiver is unchanged. List[1. z.postln. "foo"). 4]. z.postln. 3. 4]. z = List[1. 2.

2. List[1. 2. 3. 5]. List[1.pyramid(i + 1). List[1. Run the examples to see the algorithms. 5]. The receiver is unchanged. ( 10. 4]. 4. List[1.postln. 2.rotate(1).postln.pyramid(1).Where: Help→Collections→List mirror2 Return a new List which is the receiver concatenated with a reversal of itself. 2. 2. 5]. 3.do({ arg i. 2.postln. postive n values rotate right.postln. The center element is duplicated. 2.postln. The receiver is unchanged. The algorithms are numbered 1 through 10.mirror2. 4. List[1. List[1. }). Negative n values rotate left. 4].rotate(3). 3.asCompileString.postln. 4]. The receiver is unchanged. List[1. rotate(n) Return a new List whose elements are in rotated order. 3].rotate(-1).stutter(2). ) 128 . stutter(n) Return a new List whose elements are repeated n times.postln. 3. 4. 3. pyramid Return a new List whose elements have been reordered via one of 10 "counting" algorithms. 3.

List["foo". ’bar’ ].postln. 6. 3].}). The receiver is unchanged. 2.do({| i| x. ( x = List[ 1. 3]. ( x = List[ 1.Where: Help→Collections→List lace(length) Returns a new List whose elements are interlaced sequences of the elements of the receiver’s subcollections. up to size length. ) foldExtend(length) Same as lace but the sequences fold back on the list elements.postln.wrapExtend(9). ) permute(nthPermutation) Returns a new List whose elements are the nthPermutation of the elements of the receiver. 2. 129 . 2. x. 3. up to size length. 2. y = x. y = x. ( x = List[ 1. y. "foo". ’bar’]].postln. x.permute(i). ) wrapExtend(length) Returns a new List whose elements are repeated sequences of the receiver. "foo"]. y. The receiver is unchanged. 6.postln.postln. The receiver is unchanged.lace(12). ( x = List[ [1.

3.foldExtend(9).postln. 2. 1). 3. List[1. Easier to demonstrate than explain.slide(3. 4. List[1. stepSize) Return a new List whose elements are repeated subsequences from the receiver. 4. 6].asCompileString. 5.slide(4. 5. 1). 130 . clear Replace the List’s Array with a new empty one. y. 2). dump Dump the List’s Array. 6]. 5.slide(3. List[1.postln. 2.postln.asCompileString.asCompileString.Where: Help→Collections→List y = x.postln. x. ) slide(windowLength. 3. 6]. 2.postln. 4.

131 .postln.Where: Help→Collections→Loadpaths_example ID: 62 "This text is the result of a postln command which was loaded and executed by loadPaths".

.. internally creating new branches as needed to accommodate the list of keys. putTree(key1. key2b.. [ key3... descend the tree until a leaf is chosen. choose(key1. item1-2a. put(key1.key2 . keyN. keyN) retrieves a leaf node or nil if not found. Addresses within the tree are specified with a series of keys.[ key2a. item1-3 ] // etc.key2 . A way to insert objects into the tree with a syntax similar to the organization of the tree itself. item1-2b. keyN) starting at an address within the tree. ]). item) puts the item as a leaf node. at(key1. 132 .key2 ...Where: Help→Collections→MultiLevelIdentityDictionary ID: 63 MultiLevelIdentityDictionary superclass: Collection A tree of IdentityDictionaries. choose choose a branch at each level. Library is its most useful subclass.. descend the tree until a leaf is chosen.

obj . *put(key. obj) Put an object in the main ObjectTable under a specific key. key . add(obj) Put an object in an ObjectTable and generate an Integer id.the object to put in the table. obj . *init Create the main ObjectTable.Where: Help→Collections→ObjectTable ID: 64 ObjectTable associate objects with IDs superclass: TwoWayIdentityDictionary An ObjectTable is used to associate an id with an object. obj .an Integer or Symbol.the object to put in the table. This is called in Main::startUp. *add(obj) Put an object in the main ObjectTable and generate an Integer id. *at(id) Get an object in the main ObjectTable. id . 133 .a Symbol. This is useful for enabling references to objects on remote systems via Open Sound Control.the object to put in the table.

Where: Help→Collections→ObjectTable *getID(obj) Get the ID of an object in the table.an object in the table. obj . 134 .

Instance Methods: put(time. clear Empty the queue.Where: Help→Collections→PriorityQueue ID: 65 PriorityQueue superclass: Object PriorityQueue implements a priority queue data structure. pop Returns the earliest item in the queue. Example: 135 . isEmpty Return a Boolean whether the queue is empty. notEmpty Return a Boolean whether the queue is not empty. topPriority Returns the time of the earliest item in the queue. It allows you to put in items at some arbitrary time and pop them in time order. which is used to build schedulers. item) Puts the item in the queue at the given time.

}). \b). \a).0.put(1. p. p. p. while ({ p. p.2. p.0. p = PriorityQueue.1.new.2.pop. a ] [ 0.postln.put(0.pop. p. ) [ 0.1.5. d ] [ 0.5. p. p.topPriority.Where: Help→Collections→PriorityQueue ( var p.pop]. \d).postln.postln.{ [p. \e).put(2. b ] nil nil nil 136 . \c). c ] [ 1.postln. e ] [ 2.put(0.notEmpty }.put(0.pop. p.

Class Methods *read(path) Reads a file into a subclass of RawArray and returns the array. defaultName) Opens a save file dialog to save the array to a file. putFile(prompt.Where: Help→Collections→RawArray ID: 66 RawArray Superclass: ArrayedCollection RawArray is the abstract superclass of a group of array classes that hold raw data values. Instance Methods write(path) Writes the array as a file. 137 .

*readNew(file) Called by *read to read the entire file as an array of this class’ type and return a new instance.8 bit integer Int16Array . Int8Array .16 bit integer Int32Array .Where: Help→Collections→RGBArray ID: 67 Int8Array.32 bit floating point DoubleArray . Int32Array. RGBArray.64 bit floating point These classes implement only one method. FloatArray. DoubleArray Superclass: RawArray These classes implement arrays whose indexed slots are all of the same type.32 bit color FloatArray .32 bit integer RGBArray . 138 . Int16Array.

100). step) Fill a SequenceableCollection with an arithmetic series. val) Fill a SequenceableCollection with random values in the range -val to +val.postln. 1. 2). Array. minVal.postln. 1. *linrand(size. *rand2(size. *rand(size. Array.postln. maxVal) Fill a SequenceableCollection with random values in the range minVal to maxVal. maxVal) Fill a SequenceableCollection with random values in the range minVal to maxVal with a linear 139 . minVal. Class Methods *series(size. start. grow) Fill a SequenceableCollection with a geometric series. start.geom(5.rand(8. 100). It has many useful subclasses. *geom(size.rand2(8. Array. Array and List are amongst the most commonly used.postln.Where: Help→Collections→SequenceableCollection ID: 68 SequenceableCollection Superclass: Collection SequenceableCollection is a subclass of Collection whose elements can be indexed by an Integer.series(5. Array. 3). 10.

last Return the first element of the collection. or nil if not found. Array.indexInBetween(5. 3. 6]. indexIn(val) returns the closest index of the value in the collection (collection must be sorted) [2.2) indexInBetween(val) returns a linearly interpolated float index for the value (collection must be sorted) inverse operation is blendAt x = [2.4) 140 . indexOf(item) Return the index of item in the collection.2) [2. 3. 5. 3. 100). 6].Where: Help→Collections→SequenceableCollection distribution. 5. Instance Methods first Return the first element of the collection. 1.linrand(8.blendAt(0.indexIn(5. 6]. 5. 5.blendAt(x) blendAt(floatIndex) returns a linearly interpolated value between the two closest indices inverse operation is indexInBetween x = [2. 6].postln.

141 . flatten(numLevels) Returns a collection from which numLevels of nesting has been flattened.flat. 4. ( var y.[[6]]]]. 2. 5].postln. 2.asCompileString. 2. [[1.[[6]]]]. 3].[[4. z.Where: Help→Collections→SequenceableCollection copyRange(start.copyRange(1. 3]. 5].postln.flatten(1).postln. copyFromStart(end) Return a new SequenceableCollection which is a copy of the indexed slots of the receiver from the start of the collection to end. end) Return a new SequenceableCollection which is a copy of the indexed slots of the receiver from start to end.[[4. remove(item) Remove item from collection. [[1.postln. y = z. flat Returns a collection from which all nesting has been flattened. y. 3. 5]. z = [1.3). z. ) copyToEnd(start) Return a new SequenceableCollection which is a copy of the indexed slots of the receiver from start to the end of the collection.

0. 3.wchoose([0. 7. 2. 3. 2. 1. 11. a > b }).postln. sort(function) Sort the contents of the collection using the comparison function argument. a < b } [6. 4]. 2. 2. [1. b. 12]]. { arg a. 4].flop. 3. 8]. [1. 1. 0.sort({ arg a. 4]. 10. j) Swap two elements in the collection at indices i and j.[[6]]]]. wchoose Choose an element from the collection at random using a list of probabilities or weights.postln. choose Choose an element from the collection at random.sort.postln. 2. 6. 0.postln.asCompileString.3.flatten(2).[9. 5]. The weights must sum to 1.postln. 7. 0. flop Invert rows and columns in a two dimensional collection.4]).choose. If the function is nil.[[4. 3]. [[1.asCompileString.postln. 142 . 5]. 7. The function should take two elements as arguments and return true if the first argument should be sorted before the second argument. 5].Where: Help→Collections→SequenceableCollection [[1.2.1.[5. b. [6. the following default function is used. 2. // reverse sort swap(i.

separate(function) Separates the collection into sub-collections by calling the function for each adjacent pair of elements. [1. 6. 8]. 2. 6. 3. 2. 5. 10]. clumps(groupSizeList) Separates the collection into sub-collections by separating elements into groupings whose size is given by integers in the groupSizeList.Where: Help→Collections→SequenceableCollection doAdjacentPairs(function) Calls function for every adjacent pair of elements in the SequentialCollection. 5.postln. 7. [a. 5]. 4. 7. Math Support 143 . 4.postln.doAdjacentPairs({ arg a.asCompileString.postln. The function is passed the two adjacent elements and an index. 3. clump(groupSize) Separates the collection into sub-collections by separating every groupSize elements. 5. (b .asCompileString. 4. 4. 2. 3. 2. 6.curdle(0.postln.postln.separate({ arg a. 8]. b.a) > 1 }).clump(3).3).asCompileString. [1. b]. If the function returns true. 8.asCompileString. then a separation is made between the elements.2]). }).clumps([1. b. [1. curdle(probability) Separates the collection into sub-collections by separating elements according to the given probability. 2. 6. 3. 8]. 7. 5. [1. 3. [1.

*. sum3rand. fill. theta. div. sqrdif. rrand. reciprocal. 2. even. midiratio. +. log. scaleneg. sumsqr. log10. acos. magnitude. ». phase. cos. ring1. sign. cpsmidi. sinh. odd. asFloat. cubed. frac. ring4. ampdb. softclip. rand. octcps. asInt. ring2. magnitudeApx. abs. bitNot. cosh. excess. coin. cpsoct. imag. tan. Binary Messages: All of the following messages send the message performBinaryOp to the receiver with the binary message selector and the second operand as arguments. atan. +». %. 3.postln. >.postln. angle. round. rand2. midicps. exprand performBinaryOp(aSelector. lcm. linrand. log2. <!.neg. amclip. | . asFloat. floor. 4]. -. isPositive. atan2. sin. ratiomidi. rho. bitXor. clip2. neg. **. sqrt exp.reciprocal. min. <=. >=. 4]. 2. real. hypot. theOperand) 144 . bilinrand. [1. <. isStrictlyPositive. absdif. distort. isNegative.Where: Help→Collections→SequenceableCollection Unary Messages: All of the following messages send the message performUnaryOp to the receiver with the unary message selector as an argument. [1. asInteger performUnaryOp(aSelector) Creates a new collection of the results of applying the selector to all elements in the receiver. asin. nyqring. ring3. 3. gcd. &amp. /. trunc. dbamp. max. tanh. difsqr. squared.. ceil.

5.postln. 2. 2. ([1. 6. ([1. 7]). If the operand is a collection then elements of that collection are paired with elements of the receiver. 4] * 10).Where: Help→Collections→SequenceableCollection Creates a new collection of the results of applying the selector with the operand to all elements in the receiver. 145 . 3. 3. 4] * [4.postln.

add(4). 2.postln. Most of its methods are inherited from Collection. 2. You must not depend on the order of items in a set. Adding and Removing: add(anObject) Add anObject to the Set. 146 . Set["abc". Set[1. remove(anObject) Remove anObject from the Set. "ghi"]. Set[1.postln.add("def"). The contents of a Set are unordered.postln.add(3). 2. 3].add("jkl").remove(3). "def". Set[1. "ghi"].Where: Help→Collections→Set ID: 69 Set Superclass: Collection A Set is collection of objects. 3]. Set["abc". An object which is equal to an object already in the Set will not be added. The function is passed two arguments. Iteration: do(function) Evaluates function for each item in the Set. no two of which are equal.postln. "def". the item and an integer index.postln. 3].

2. 300]. 147 . item.do({ arg item. 3. i.Where: Help→Collections→Set Set[1.postln }).

[0. The Signal will be normalized. Signals support math operations. amplitudes.2.the number of samples in the Signal.3.6]). 1. Signal. *chebyFill(size. phases) Fill a Signal of the given size with a sum of Chebyshev polynomials at the given amplitudes for use in waveshaping by the Shaper ugen.plot.chebyFill(1000. The Signal will be normalized.chebyFill(1000.0/[1. amplitudes.the number of samples in the Signal.plot.an Array of phases in radians for each harmonic beginning with the fundamental. size . amplitudes . phases .sineFill(1000. Signal.an Array of amplitudes for each harmonic beginning with the fundamental.an Array of amplitudes for each Chebyshev polynomial beginning with order 1.5. Signal. amplitudes .4. Creation *sineFill(size. phases) Fill a Signal of the given size with a sum of sines at the given amplitudes and phases. [1]). 1]).Where: Help→Collections→Signal ID: 70 Signal sampled audio buffer Superclass: FloatArray A Signal is a FloatArray that represents a sampled function of time buffer. size .plot. 148 .

the number of samples of the size that is zero padding. *welchWindow(size) Fill a Signal of the given size with a Welch window. Signal. [0.hanningWindow(1024). pad . pad . size . size .welchWindow(1024).8.plot.plot. pad) Fill a Signal of the given size with a Hanning window. 1]). 0. 1.the number of samples in the Signal. size .the number of samples in the Signal.the number of samples in the Signal. *hanningWindow(size. Signal. 512). pad . Signal. Signal.welchWindow(1024. -0.the number of samples of the size that is zero padding.plot.plot.3.the number of samples of the size that is zero padding.plot.plot.hammingWindow(1024). *rectWindow(size) 149 . Signal. Signal. Signal.1]). 512).plot. [0.Where: Help→Collections→Signal Signal.chebyFill(1000. *hammingWindow(size) Fill a Signal of the given size with a Hamming window.plot.chebyFill(1000.hanningWindow(1024.hammingWindow(1024. 512).

Signal.sineFill(512.a Rect giving the bounds of the window.sineFill(512. 150. play(loop. 450)). [1]). pad . number of channels. loop . Signal. bounds) Plot the Signal in a window. 150 . 0.rectWindow(1024).the number of samples in the Signal.sineFill(512.play(true. Signal.plot. returns the buffer so you can free it again. server . // free the buffer again. the name of the window.rectWindow(1024.the server on which to load the signal into a buffer.the number of samples of the size that is zero padding. Default is to loop. Instance Methods plot(name. numChannels . numChannels. 512).plot. name . b.a String. mul. Signal.A Boolean whether to loop the entire signal or play it once.free. server) loads the signal into a buffer on the server and plays it.plot("Signal 1". b = Signal. default is 1.plot. 0.2 by default. [1]). size .Where: Help→Collections→Signal Fill a Signal of the given size with a rectangular window.volume at which to play it. 50.if the signal is an interleaved multichannel file. The arguments are not required and if not given defaults will be used. Rect(50. bounds . [1]).2). mul .

end) Fill the Signal with a function evaluated over an interval.the starting value of the interval end . ( s = Signal. i.the value along the interval.fill(0. function . i .scale(0.3. 0.plot.a function that should calculate the value of a sample. fill(val) Fill the Signal with a value. offset(offset) 151 .5).the ending value of the interval. s. start . 3pi). [1]).sineFill(512.newClear(512). s.plot.asWavetable.2. start. The function is called with two arguments. scale(scale) Scale the Signal by a factor in place. Signal.newClear(512). a. Signal. a.2). x .max(0) }. a = Signal[1.Where: Help→Collections→Signal waveFill(function.the sample index.waveFill({ arg x. ) asWavetable Convert the Signal into a Wavetable.4].plot. sin(x).

1). peak Return the peak absolute value of a Signal. invert Invert the Signal in place.2. Transfer functions are meant to be used in the Shaper ugen. a = Signal[1.peak.5].-4. reverse(beginSamp.2.2.-4. a. Signal[1. Signal[1. normalize Normalize the Signal in place such that the maximum absolute peak value is 1.2.2. endSamp) 152 .3.1]. Signal[1.3.normalize.5).5.-3.Where: Help→Collections→Signal Offset the Signal by a value in place.invert(0. // normalize only a range normalizeTransfer Normalizes a transfer function so that the center value of the table is offset to zero and the absolute peak value is 1.2. a.2.5]. a = Signal[1.2. a.normalize(0.4].5].2.offset(0.5).4].2.normalizeTransfer.3. a. Signal[1.

-1).overDub(Signal[1. 100). 3).fill(10.fade(6. 100).3. a = Signal. overDub(aSignal.4]. a.reverse(1. Signal[1. a. a = Signal.fill(10. // run out of range a = Signal. 9. 3).overDub(Signal[1. endLevel) Fade a subrange of the Signal in place. index) Add a signal to myself starting at the index. // fade out integral Return the integral of a signal. // fade in a. 0). a. a. beginLevel.4].fill(10. 1.overDub(Signal[1. a. fade(beginSamp.2. a. a = Signal.3. 8). endSamp.2.3. a = Signal[1. -4).fill(10. a = Signal.2.fill(10. 1). If the other signal is too long only the first part is overdubbed.3.2.3.fade(0. a.2.3.overDub(Signal[1. 100). 153 .2).4].4].integral.4]. 100).2.Where: Help→Collections→Signal Reverse a subrange of the Signal in place.4].

8). 100). 0).4]. 154 .8].fill(10.fill(10.overWrite(Signal[1.3. a.0].overDub(Signal[1. a.fill(4.3.5.5.4].2. 3). a.fill(4. a = Signal. blend(aSignal.3. 100).2.0]. -2).4].overWrite(Signal[1.0].3. a = Signal.blend(Signal[5.5.4].overWrite(Signal[1. index) Write a signal to myself starting at the index.3. blend) Blend two signals by some proportion.4.fill(10.3. -2). 100).blend(Signal[5. -4).blend(Signal[5.3.2.7.4].5.blend(Signal[5.4].2. 100).4]. a = Signal. a.3.5.2).2. a = Signal. 0.6.4].3. a = Signal.2. -2).0].fill(10. Signal[1.3.2.3. 1).fill(10. 0.4.2. a.2.5.2.5.2. a. Signal[1.overWrite(Signal[1.8].fill(10.2. If the other signal is too long only the first part is overdubbed. 100). 100). Signal[1. -1).overWrite(Signal[1. Signal[1.overWrite(Signal[1. 100).3.Where: Help→Collections→Signal a = Signal.4).7.5. a = Signal. a. a. overWrite(aSignal.5. // run out of range a = Signal.4]. 100). -2).5.4].6.overDub(Signal[1.

Rect(0.4].3.fftCosTable(size).125. fft(imag.fill(size.magnitude) / 100 ]. 500). 155 . 0. imag. { 0.5].fftCosTable(512). imag.0]. real = Signal.blend(Signal[5. // some harmonics real.newClear(size). [21.plot.2.25].overDub(Signal.2.plot("fft". // add a little noise real. cosTable) Perform an FFT on a real and imaginary signal in place. cosTable) Perform an inverse FFT on a real and imaginary signal in place. 0. [55.0.5.sineFill2([[8]. numChannels: ) 3). [real. real. cosTable = Signal.newClear(size). complex = fft(real. complex.flat . Fourier Transform: fftCosTable(size) Fill a Signal with the cosine table needed by the FFT methods. 0. ( var size = 512.5. 512 + 8. cosTable. cosTable).5pi]]). (complex.flop. [13. imag = Signal.Where: Help→Collections→Signal Signal[1. 2). Signal. imag. 0.bilinrand })). ifft(imag.

newClear(size). [0. { 0.5]. [55. x.asin.fill(size.real].25]. cosTable). imag. Rect(0. // add a little noise real. numChannels: ) 2). tan.ifft(complex. 0.1]).plot(numChannels: 9). 0. x. neg.flat. complex = fft(real.125. 500). real.bilinrand })).imag. acos. log. ifft = complex.overDub(Signal. Unary Messages: Signal will respond to unary operators by returning a new Signal. cosh.normalize. 512 + 8. cosTable). real = Signal.normalize. [21. [real. isNegative.cubed. cos. complex. softclip.distort]. [x.fftCosTable(size). imag = Signal.sineFill2([[8]. x. x. // some harmonics real. [13. sinh. distort.5pi]]). log2.real.postln.0. log10. tanh. cubed.Where: Help→Collections→Signal ( var size = 512. x. ifft.flat. atan.squared.plot("fft and back". isStrictlyPositive x = Signal. sin. ifft. cosTable = Signal.2. nyqring. asin. sign.abs.exp.newClear(size). sqrt exp.0. x. abs. 0. x. Binary Messages: 156 .neg. x.0. squared. imag.sign.sineFill(512.flop. isPositive. cosTable. 0.flop.

0) }).fill(512.flat. clip2. <! ( x = Signal. sqrdif. min. ring2. { | i| (i * pi / 64). ring4. y. +. %.sin }). max. **. *. /. amclip. min(x. y) ].5. 1. { rrand(0.plot(numChannels: ) 6). difsqr. y). ring1. y = Signal. absdif. (x + y) * 0. ring3. div.0. x * y. 157 . excess.flop. sumsqr. [x. max(x.Where: Help→Collections→Signal Signal will respond to binary operators by returning a new Signal. -. scaleneg.fill(512.

Instance Methods add(item) Adds an item in the SortedList at the correct position. 7]). 158 . 6].postln. Creation *new(size. 4. SortedList[1.Where: Help→Collections→SortedList ID: 71 SortedList Superclass: List SortedList is a Collection whose items are kept in a sorted order. SortedList[1.postln. 2.add(4). 3. addAll(aCollection) Adds all the items in the collection into the SortedList. function) Creates a SortedList with the initial capacity given by size and a comparison function. 6]. 5. 2. 5.addAll([0.

is equal to the argument or should be sorted after the argument. 159 . "ABCDEFG". Each element is a Char.Where: Help→Collections→String ID: 72 String Superclass: RawArray String represents an array of characters. or 1 depending on whether the receiver should be sorted before the argument. compare(aString) Returns a -1. < aString Returns a Boolean whether the receiver should be sorted before the argument. Strings can be written literally using double quotes: "my string". Instance Methods at(index) Strings respond to .postln. This is a case sensitive compare. == aString Returns a Boolean whether the two Strings are equal.at(2). Class Methods *readNew(file) Read the entire contents of a File and return them as a new String.at in a manner similar to other indexed collections.class.postln. 0.

(1.postcln. To print a % character use \\% . 2. postc postcln As post and postln above. list = %\n". list = [ 1..round(1e-4). pi. 3.1416. 3.4)) this is a test. To print a % character use \\% . postln Prints the string and a carriage return to the current post window. format("this % a %. postf("this % a %.round(1e-4). 4 ] format Returns a formatted string with arguments. 4 ] error Prepends an error banner and posts the string 160 . The % character in the format string is replaced by a string representation of an argument.1416. The % character in the format string is replaced by a string representation of an argument. pi. but formatted as a comment. postf Prints a formatted string with arguments to the current post window. list = [ 1. pi = 3.4)) this is a test..". pi = %. 2. pi = %. "test". "test". list = %\n". pi = 3.Where: Help→Collections→String post Prints the string to the current post window. "This is a comment. (1. "is". "is".

but posts the compileString of the reciever 161 . f. f. inform Posts the string. ) asCompileString Returns a String formatted for compiling. ) postcs As postln.postln.compile.asCompileString. + aString Return a concatenation of the two strings with a space between them. ( var f.postln.postln. compile Compiles a String containing legal SuperCollider code and returns a Function.Where: Help→Collections→String warn Prepends a warning banner and posts the string. ( var f.value. f.postln. ++ aString Return a concatenation of the two strings. f = "2 + 1". f = "myString".

"4..postln.interpretPrint. ) asInteger Return an Integer derived from the String. interpretPrint Compile.asSymbol. "2 + 1". [3. interpret Compile and execute a String containing legal SuperCollider code.postcs. execute and print the result of a String containing legal SuperCollider code.postln.postln.interpret. args) 162 . asSymbol Return a Symbol derived from the String. ( var z.postln. Strings beginning with non-numeric characters return 0.postln. Strings beginning with non-numeric characters return 0..Where: Help→Collections→String List[1. ["comment". returning the result.rand }]. z = "myString". "2 + 1".asFloat.3". "4".class. asFloat Return a Float derived from the String. { 1.0. 2]]. catArgs(. 2. z.asInteger.

postln. {4 + 3}). findAll(string) 163 . {4 + 3}). "These are several words". {4 + 3}]). SinOsc.postln. "a String".ccatList([\fish. args) Same as catArgs.postln.find("fish"). args) Same as catArgs. SinOsc. or nil if not found.postln.Where: Help→Collections→String Concatenate this string with the following args.split. handy for Unix paths. scatArgs and ccatArgs above. scatArgs(.postln.catArgs(\fish.ccatArgs(\fish.postln. {4 + 3}).ar. and is not included in the output array. catList(list) scatList(list) ccatList(list) As catArgs. ccatArgs(. "These are some args: ". "This/could/be/a/Unix/path".postln. "These are several words".scatArgs(\fish. "These are several words". SinOsc. but with spaces in between. split(separator) Returns an Array of Strings split at the separator. The separator is a Char.ar.split($)..find("are"). but with commas in between.. The default separator is $/.ar. "These are some args: "... SinOsc.postln.ar. find(string) Returns the index of the string in the receiver. "a String". but takes a Collection (usually a List or an Array) as an argument.

"These are several words which are fish". containsStringAt(index.findAll("are").findAll("fish").contains("fish"). but case insensitive.Where: Help→Collections→String Returns the indices of the string in the receiver. containsi(string) Same as contains.postln.postln. string) Returns a Boolean indicating if the String contains string beginning at the specified index. Replace all instances of from with to.postln. "These are several words".postln.escapeChar($).containsi("ArE"). or nil if not found. "These are several words". "These are several words". "These are several words". "These are several words which are fish". 164 . tr(from.contains("are").postln. but case insensitive. string) Same as containsStringAt. "are"). contains(string) Returns a Boolean indicating if the String contains string. "This will become a Unix friendly string". escapeChar(charToEscape) Add the escape character (\) at the location of your choice. to) Transliteration. icontainsStringAt(index.postln.postln.containsStringAt(6.

storeOn(stream) Same as printOn. the current working directory is the same as the location of the SuperCollider app and the shell is the Bourne shell (sh). $)). ( // same as File-readAllStringRTF g = File("/code/SuperCollider3/build/Help/UGens/Chaos/HenonC.close.Where: Help→Collections→String ":-(:-(:-(". //turn the frowns upside down printOn(stream) Print the String on stream."r"). but formatted asCompileString.postln. "Store this on Post".rtf". g. stripRTF Returns a new String with all RTF formatting removed.help.readAllString. does not persist: 165 . g. // equivalent to: Post<<< "Store this on Post". ) Unix Support Where relevant. and indeed the shell itself. "Print this on Post".tr($(. inspectorClass Returns class StringInspector. // equivalent to: Post<< "Print this on Post".storeOn(Post). Note that the cwd.postln.printOn(Post).stripRTF.

"ls Help".unixCmd. "pwd".unixCmd.Where: Help→Collections→String "echo $0". pwd". It is however possible to execute complex commands: "pwd.standardizePath).unixCmd. // all defs in this directory will be loaded when a local server boots "SC_SYNTHDEF_PATH". // print the shell (sh) "pwd".unixCmd.unixCmd. pathMatch 166 . "echo $SC_SYNTHDEF_PATH".unixCmd.unixCmd. "echo $FISH".unixCmd.unixCmd.unixCmd. "cd Help/". getenv Returns the value contained in the environment variable indicated by the String. Note that if value is a path you may need to call standardizePath on it (see below). Should you need an environment variable to persist you can use setenv (see below). echo $FISH". setenv(value) Set the environment variable indicated in the string to equal the String value. "export FISH=mackerel. See man sh for more details. cd Help/. This value will persist until it is changed or SC is quit. unixCmd Execute the String on the command line using the Bourne shell (sh) and send stdout to the post window. "export FISH=mackerel". "USER".getenv.setenv(" /scwork/".

See PathName for more complex needs. "Imaginary/Directory/fish. "Imaginary/Directory/fish. Post << "Help/*". //This file posts some text load Load and execute the file at the path represented by the receiver. extension]. loadPaths Perform pathMatch (see above) on this String.rtf". standardizePath Expand to your home directory. " ".pathMatch.standardizePath. then load and execute all paths in the resultant Array. Wildcards apply.rtf".rtf".loadPaths.dirname. dirname Return the directory name from a Unix path. splitext Split off the extension from a filename or path and return both in an Array as [path or filename.Where: Help→Collections→String Returns an Array containing all paths matching this String. nonrecursive. //This will print your home directory basename Return the filename from a Unix path. "Help/Collections/loadPaths example. and resolve symbolic links.basename. 167 .

rtf". else returns nil. ( d = "Help/Help. "foobar". openHelpFile 168 .help.rtf". makeListener) Create a new Document with this. 20). d. ) openTextFile(selectionStart.rtf". selectionLength) Create a new Document from the path corresponding to this. "Here is a new Document".Where: Help→Collections→String "fish. if it exists.rtf". ( d = "Help/Help.findHelpFile.splitext. d.newTextWindow. openDocument Create a new Document from the path corresponding to this. Document Support newTextWindow(title. "Document". Returns the Document. Returns this.class.help.splitext. "Imaginary/Directory/fish.class. ) findHelpFile Returns the path for the helpfile named this.openDocument.openTextFile(0.findHelpFile. The selection arguments will preselect the indicated range in the new window.

Where: Help→Collections→String Performs foundHelpFile(above) on this. and [Pen]. [Color]. 169 .white).new. [SCUserView]. draw Draws the String at the current 0@0 [Point]. See also [Pen]. color) Draws the String at the given [Point] using the [Font] and [Color] specified. and opens the file it if it exists. font. ( w = SCWindow.new.drawHook = { "abababababa\n\n\n". w. "foobar".draw }.scramble. If not transformations of the graphics state have taken place this will be the upper left corner of the window. w.background_(Color. w. and will only be visible once the window or the view is refreshed.background_(Color. Drawing Support The following methods must be called within an SCWindow-drawHook or a SCUserViewdrawFunc function.front. w. w. 30).scramble. ( w = SCWindow.view.drawHook = { "abababababa\n\n\n".front.refresh ) drawAtPoint(point. otherwise opens the main helpfile. See also: [SCWindow].openHelpFile.openHelpFile.drawAtPoint( 100@100. Each call to SCWindow-refresh SCUserView-refresh will ’overwrite’ all previous drawing by executing the currently defined function. Font(" Gadget".view. "Document".white).

w.. ( w = SCWindow. ( w = SCWindow. ( w = SCWindow.3.strokeRect(r). w.3.. w. }.new. 100.scramble. Font(" Gadget". 100. w.3. 30). 100)..scramble. w.front.background_(Color. 0.refresh ) // drawLeftJustIn(inRect) Unfortunately does not work for now.new.white).blue(0. Pen. color) Draws the String into the given [Rect] using the [Font] and [Color] specified.Where: Help→Collections→String Color. Color. 170 . 100. r = Rect(100.white). font.drawHook = { "abababababa\n\n\n".view.5)) }.front. w. 0.drawCenteredIn( Rect(100.5)).blue(0. 30). Color.blue(0. 100.new.drawInRect(r.view.background_(Color. Unfortunately does not work for now. 100).refresh ) // drawCenteredIn(inRect) draws the String into the center of the given rect with font and color into the window.front. Font(" Gadget". 0.5) ) }. w.drawHook = { "abababababa\n\n\n"..refresh ) drawInRect(rect.

100. 100.front. Font(" Gadget".refresh ) // drawRightJustIn(inRect) Unfortunately does not work for now.white). w. 30). 30).drawHook = { "abababababa\n\n\n".view. 100.. 0.3.Where: Help→Collections→String w.scramble.5) ) }.3. Font(" Gadget".drawHook = { "abababababa\n\n\n".white). w. w. 100.5) ) }. Color. w.drawLeftJustIn( Rect(100. 0.drawLeftJustIn( Rect(100. Color.blue(0.background_(Color.view. 100).new.refresh ) 171 .background_(Color.scramble. ( w = SCWindow.blue(0. 100). w..

Creation *sineFill(size.chebyFill(512.1]).plot.3.4.5.chebyFill(512. The Wavetable will be normalized. amplitudes . 0.sineFill(512.an Array of phases in radians for each harmonic beginning with the fundamental.plot. [0.0/[1. *chebyFill(size.must be a power of 2.2. Wavetables cannot be created by new. The Wavetable will be normalized. Wavetable. [1]).plot. Wavetable. 1. 1]).chebyFill(512. [0. Wavetable. Wavetable. 172 . size . phases) Fill a Wavetable of the given size with a sum of sines at the given amplitudes and phases. -0. phases) Fill a Wavetable of the given size with a sum of Chebyshev polynomials at the given amplitudes for use in waveshaping by the Shaper ugen. Wavetable.an Array of amplitudes for each harmonic beginning with the fundamental.8.Where: Help→Collections→Wavetable ID: 73 Wavetable Superclass: FloatArray A Wavetable is a FloatArray in a special format used by SuperCollider’s interpolating oscillators. phases . amplitudes .must be a power of 2.chebyFill(512.plot.3. 1. size .an Array of amplitudes for each Chebyshev polynomial beginning with order 1.6]). [0. amplitudes.plot. 1]). amplitudes.

plot("Table 1". Wavetable.sineFill(512. [1]). Wavetable. bounds) Plot the Wavetable in a window. Wavetable. [1]). name . Wavetable. 150.play. name . asSignal Convert the Wavetable into a Signal. Rect.a Symbol or String giving the name of the mixer channel. The arguments are not required and if not given defaults will be used. 173 .Where: Help→Collections→Wavetable Instance Methods plot(name.play("Table 1"). play(name) Plays the Wavetable in a Mixer channel. the name of the window. 50. [1]). [1]).a String.a Rect giving the bounds of the window.sineFill(512.plot.sineFill(512.plot. [1]).asSignal. bounds .sineFill(512.newBy(50.sineFill(512. Wavetable. 450)).

4 Control 174 .

CmdPeriod. If you need -cmdPeriod to be called on a set of objects in a given order then it is best to wrap those within a [Function] and register that. *doOnce(object) Registers an Object o be evaluated once. This object will stay registered until it is explicitly removed. is pressed. Examples ( f = {"foo". is pressed CmdPeriod allows you to register objects to perform an action when the user presses Cmd-. and will thus respond to additional presses of Cmd-. (You can add such a method in your custom classes. For this reason you cannot rely on the order in which the objects will be cleared.add(f).B. *remove(object) Removes an object that was previously registered. Cmd-.postln }. uses an [IdentitySet] to store its registered objects.Where: Help→Control→CmdPeriod ID: 74 CmdPeriod Superclass: Object register objects to be cleared when Cmd-.) Note that since [Function] implements -cmdPeriod as a synonym for -value. CmdPeriod. ) 175 . N. is pressed. it is possible to register any function (and thus any arbitrary code) for evaluation when Cmd-.postln }.add(g). g = {"bar". and then unregistered. These objects must implement a method called -cmdPeriod which performs the necessary tasks. (See example below.) Class Methods *add(object) Registers an object to be cleared when Cmd-.

g = {"second".postln }.front. CmdPeriod.add(h).remove(g). // order is arbitrary. // you can write: CmdPeriod. CmdPeriod. g.postln } // a typical example: ( w = SCWindow. CmdPeriod. CmdPeriod. ) // Now press Cmd-. CmdPeriod.add(f).postln.remove(f) }.new("close on cmd-.doOnce { w.close }.").Where: Help→Control→CmdPeriod // Now press Cmd-.remove(f).postln }.cmdPeriod. CmdPeriod. Only f executes CmdPeriod.}. so wrap in a function h = { f.remove(h). // must explicitly cleanup //// Controlling order of execution ( f = {"first". // note that often you want to automatically remove the function once it is evaluated // instead of f = { "foo". // Now press Cmd-.doOnce { "foo".cmdPeriod. 176 .

Where: Help→Control→CmdPeriod ) 177 .

178 . The default is 1 slot.Where: Help→Control→ContiguousBlockAllocator ID: 75 ContiguousBlockAllocator A more robust replacement for the default server block allocator. Normally you will not need to address the allocators directly. pos = 0) Create a new allocator with size slots. May be used in the Server class to allocate audio/control bus numbers and buffer numbers. reserve(address. namely the reserve method. You may block off the first pos slots (the server’s audioBusAllocator does this to reserve the hardware input and output buses). *new(size.blockAllocClass = ContiguousBlockAllocator. execute the following: aServer. ContiguousBlockAllocator adds one feature not present in PowerOfTwoAllocator. size = 1) Mark a specific range of addresses as used so that the alloc method will not return any addresses within that range.options. free(address) Free a previously allocated block starting at address. However. PowerOfTwoAllocator. To configure a server to use ContiguousBlockAllocator. alloc(n = 1) Return the starting index of a free block that is n slots wide.

flg=00.asSpec. warp. maxval.\exponential. step. default. gc=00. gc=00.dump Instance of ControlSpec { instance variables [6] (0313FF18.3000.Where: Help→Control→ControlSpec ID: 76 ControlSpec superclass: Spec specification for a control input The original. default) [300. maxval. flg=00.new( minval. (see [Spec] ) ControlSpec.dump Instance of ControlSpec { instance variables [6] minval : maxval : warp : step : Float 0 Float 1 Symbol ’linear’ Float 0 Float 0 (0313FF18.new( minval.48].asSpec. fmt=00. set=03) Integer 100 Integer 300 default : } // partially specified . set=03) 179 . warp. set=03) default : } // array is used as arguments to ControlSpec. and most common spec.. gc=00. The most common way to create one is by anObject.dump Instance of ControlSpec { instance variables [6] minval : maxval : warp : step : Integer 300 Integer 3000 Symbol’exponential’ (0313FC08.units). flg=00. step..100].asSpec. [-48.asSpec // nil becomes a default ControlSpec nil. fmt=00. fmt=00.

map(0. a.5).asSpec.0). ’exp’. a.. returns max 180 . // returns min a.Where: Help→Control→ControlSpec minval : maxval : warp : step : Integer -48 Integer 48 Symbol ’linear’ Float 0 Integer -48 default : } constrain (value) clips and rounds the value to within the spec map (value) maps a value from [0.constrain(803). 100. a. // exceeds the area: clip. // make sure it is in range and round it. // give it a rounding of 30 (Hz) a = \freq.map(1.. 440]. a.constrain(800).1] to spec range unmap (value) maps a value from the spec range to [0. // equivalent: a = [20.5).asSpec. // make sure it is in range and round it. a.step = 100. a. 20000.dump.map(0.1] // example // make a frquency spec with an exponential range from 20 to 20000.

w. c. d = SCStaticText(w. 340.. c = SCSlider(w.01) + ". 300. 10. 300.Where: Help→Control→ControlSpec a.unmap(4000). ) 181 ." + "mapped value" + a.unmap(22. c.value) }.front.round(0. w = SCWindow("control".. 64. d.. 30)). Rect(128.action = { d. Rect(10...value. Rect(10.map(c. 160)). // using spec for sliders: ( var w. 30)). a.0).string = "unmapped value" + c. 40.

free.start.stop. d.boot. s.default.new. y. 182 . d. d = DebugNodeWatcher(s). y = Group.Where: Help→Control→DebugNodeWatcher ID: 77 DebugNodeWatcher Posts when these messages are received from the server: n_go n_end n_off n_on s = Server.

’sine’ .Where: Help→Control→Env ID: 78 Env envelope specification superclass: Object An Env is a specification for a segmented envelope. In this case.3.test. the levels must all be nonzero and the have the same sign. 1.an Integer or nil. An Env can have several shapes for its segments. [2.an array of durations of segments in seconds. with methods such as at and asStream. levels .3. 183 .curvature values for each segments.test.linear segments.new([0. The envelope will sustain at the release node until released.8. releaseNode.sinusoidal S shaped segments. 0. a Float . by an EnvGen within a SynthDef. An Env can have any number of segments which can stop at a particular value or loop several segments when sustaining.an array of levels. // different shaped segments: Env. An Array of Floats . [2. and clientside. curves. loopNode) Create a new envelope specification. 0]. 3.1.flat segments ’linear’ . 4]. The first level is the initial value of the envelope.boot. Basic Creation *new(levels. 1.’linear’). Env.plot.001. loopNode .’exponential’). 0. ’welch’ . There should be one fewer duration than there are levels.new([0. times .natural exponential growth and decay. times. curve .plot. s. 1. the default ’exponential’ .8. 4]. Envs can be used both server-side.sinusoidal segments shaped like the sides of a Welch window. 3.a curvature value for all segments. If not nil the sustain portion will loop from the releaseNode to the loop node.001].this parameter determines the shape of the envelope segments. 0. The possible values are: ’step’ .an Integer or nil. 0. 0. below. releaseNode .

0.Where: Help→Control→Env Env.new([0. 1.new([0. 0. Env. 1.8.3. Env. 1.0. 0.8.3.5. 0]. 4].0.3.plot.test(0. -3. 3.’step’). Env.3. 2). 3.8.8. the EnvGen outputs the nodes between the release node and the loop node until it is released: //release node is node 3.[2.5. it changes from the whatever the current level is to the goal level of the release segment over the specified duration of the release segment.1. The endpoint of that segment is the goal level for that segment and the duration of that segment will be the time over which the level changed from the current level to the goal level.2. Note: The starting level for an envelope segment is always the level you are at right now.plot. 3. 2). 1.3.new([0. 0. 4]. so node zero has duration equal to times[0] and goal level equal to levels[1]. [2. 0.new([0. 2. 3.test. 0.001.plot.test(5).2.1.plot. 1. 2). 0].plot.0.8. releases after 5 sec Env.’welch’).1.0].3.1. ’lin’.3.0].plot. 0.[2.0].3.plot. [2.0.0. 3.[2.8. 2.’sine’). and the gate input of the EnvGen is set to zero.2. After that each node is a goal level and a duration.1. Env.3.plot.5.test(3). If a release node is given.8.8. 1. -2).2.[2. [2. [2.test. it outputs the nodes after the release node: //release node is node 2.1).0.test(5). 0].4].1. -1]). *newClear(numSegments) 184 . 0.8. The loop jumps back to the loop node.new([0.0.test.new([0. Env.1] * 0. If a loop node is given.1] * 0.3.0. 0. 1. 0.8.0. For example when the gate is released and you jump to the release segment.2.001. 3.test.2. 0].test.new([0.4] * 0. [2. loop node is node 1 Env.test.8.0. 0.new([0.0. 0.0. 4].3.1.1. There is an extra level at the beginning of the envelope to set the initial level. 1.8. 2. 1). the level does not jump to the level at the beginning of the release segment. 0. 0].[2. //instant release Env.2. Env.plot.new([0.2.001]. 2). 4].plot.0. 1. 4].3.0.1] * 0.new([0.001].1.001.3.8.1.3. [0.1. 1. 1.001. 3.001.3. 0.

asArray ). This can be useful when passing Env parameters as args to a [Synth]. Out.makeBundle(nil.1]. var env. // create a control argument array envctl = Control. 1). [1.send(s). ) ( s. \exp). \exp). ( SynthDef("Help-Env-newClear".setn(\env.800]. t_gate . 0.newClear(4).ar(EnvGen.300.set(\t_gate. *linen(attackTime. x. }).900.1]. // 3 segments x = Synth("Help-Env-newClear". // make an empty 4 segment envelope env = Env. SinOsc.1.200].names([\env]).setn(\env. e. x. curve) Creates a new envelope specification which has a trapezoidal shape.1.free. Note that the maximum number of segments is fixed and cannot be changed once embedded in a [SynthDef]. [\t_gate. ) x.ar(i_outbus.asArray). 1]). // 4 segments x.Where: Help→Control→Env Creates a new envelope specification with numSegments for filling in later. releaseTime.900. Standard Shape Envelope Creation Methods The following class methods create some frequently used envelope shapes based on supplied durations. envctl. e.500.1. ) ( // reset then play again e = Env([800. Trying to set an Env with more segments than then this may result in other args being unexpectedly set. level. [1. 0.kr(envctl. t_gate).400. { arg i_outbus=0. }). { // must not have more segments than the env above e = Env([700.kr( env.3)). 185 .asArray). sustainTime.

the curvature of the envelope. 0. sustainTime .linen(1. curve) Creates a new envelope specification which (usually) has a percussive shape.the peak level of the envelope. Env.the duration of the attack portion. -3).test. *perc(attackTime. 0. 3.test.sine(1.linen(1. *triangle(duration. 1). 186 .test.plot. Env. 2. 0. Env.the duration of the attack portion. 0. level) Creates a new envelope specification which has a triangle shape.the duration of the release portion.1). releaseTime . level .1.the level of the sustain portion.the duration of the release portion. 0.plot. curve .plot. duration . peakLevel.6. duration .plot. 3. level .1. 2. Env. ’sine’).6). 3.6). releaseTime . curve .6.the peak level of the envelope. releaseTime.plot. level .the duration of the envelope. 0. 3.linen(1.test. level) Creates a new envelope specification which has a hanning window shape.linen(0.the duration of the envelope. Env.2. Env. 0.test. 2.test.the duration of the sustain portion.6.the peak level of the envelope. 0.plot.plot. 2. 3.linen(1.plot. *sine(duration.triangle(1. 2.test. ’welch’). -3).the curvature of the envelope.6. peakLevel . Env. attackTime .boot. Env. s.Where: Help→Control→Env attackTime .linen(1.test.

releaseTime. 4). peakLevel. *dadsr(delayTime. 0.test. releaseTime .the curvature of the envelope. but with it’s onset delayed by delayTime in seconds. sustainLevel. decayTime. -8). sustainLevel.2. -4).test.plot. //release after 0. // change curvature Env. sustainLevel . releaseTime . 1.001. releaseTime. 187 . peakLevel. 1.perc(0. attackTime. 1.test.001. The default delay is 0.the duration of the attack portion.001.25.adsr(0. // sharper attack Env. *asr(attackTime.01.05.45 sec Env.the duration of the decay portion. peakLevel .the duration of the release portion. 0. peakLevel. 1.plot. -4). decayTime . 0.test.2. Env. curve) As *adsr above.25.plot.perc(0. -4).plot. 0. releaseTime. 1. -4).test(0. attackTime .25. 1.the level of the sustain portion as a ratio of the peak level. Env.plot.test(2).adsr(0.001. sustainLevel . // reverse envelope Sustained Envelope Creation Methods The following methods create some frequently used envelope shapes which have a sustain segment.test(2).02. 0.plot. 1.perc(0.Where: Help→Control→Env Env.plot.1. Env. 1. -4). 1. sustainLevel.perc(1. attackTime . curve . *adsr(attackTime. 0.the level of the sustain portion as a ratio of the peak level.2. 0. curve) Creates a new envelope specification which is shaped like traditional analog attacksustain-release (asr) envelopes. 1.45).the duration of the attack portion. decayTime.adsr(0. curve) Creates a new envelope specification which is shaped like traditional analog attack-decaysustain-release (adsr) envelopes. 1. 1.the duration of the release portion.the peak level of the envelope. 1.

curve . 4). 1.asr(0.a number from zero to one. blendFraction) Blend two envelopes.3. curve) Creates a new envelope specification which has no attack segment. 0. blendFraction .cutoff(1. level .2.5. -4).01. 0.test(2).cutoff(1. 0.05. 0.test.test(2). 0. It simply sustains at the peak level until released.plot. Env.the curvature of the envelope.test.2.4. 0.the duration of the release portion.the peak level of the envelope.the peak level of the envelope.5.test(2).asr(0.plot. f. // linear segments *cutoff(releaseTime.4. 0.plot. 0.001. anotherEnv . 0. 0. and more versatile than [Line].2. [0.4]).5.the curvature of the envelope.pop. Useful if you only need a fadeout. 1. a = Env([0. ( Task({ f = (0.test(2). Env.plot.01. Env. -4). 1. 1. b.plot.2]). curve .plot. // sharper attack Env. 0. u). 0.02.2 . Instance Methods blend(anotherEnv. 1.cutoff(1. releaseTime .test.an Env.5. 0. 0. 1. 0]. SCWindow. 0. 2.Where: Help→Control→Env peakLevel . 0. b = Env([0. 0]. 1.plot. 1.5.allWindows..wait. Returns a new Env. [0.asr(0.1.test(2).plot. 0. 1). Env. level. ’sine’).close.test(2).do { | u| blend(a. Env. // close last opened window 1). 188 .01.2.02. ’linear’). 1. 0. 1.plot.

play(AppClock). a = Env.ar(440.do({| fact| Synth("Help-EnvBlend". 1. The default is 3 seconds.The size of the plot. fact.test.1) ) }). 1. 1. The default is 400.If this is a sustaining envelope. 189 .fork. fact). { arg fact = 0.kr(Env. size .1). delay .}). -4). doneAction: * SinOsc.plot.perc.postln]).) delay(delay) Returns a new Env based on the receiver in which the start time has been offset by adding a silent segment at the beginning. b. 2) ( { f = (0. [\fact. test(releaseTime) Test the envelope on the default [Server] with a [SinOsc]. 1..0.perc(0. plot(size) Plot this envelope’s shape in a window. f. a.send(s)). ) // in a SynthDef ( SynthDef("Help-EnvBlend".delay(2).blend(Env.0.plot.The amount of time to delay the start of the envelope.wait. Out.ar(0. releaseTime .Where: Help→Control→Env } }). b = a.0.05. 0. }. it will be released after this much time in seconds.1. EnvGen.test.sine.

sine. isSustained Returns true if this is a sustaining envelope. asArray Converts the Env to an Array in a specially ordered format. embedInStream Embeds this Env within an enclosing [Stream]. thisThread. 5. This allows for Env parameters to be settable arguments in a [SynthDef].do({ e.wait. Timing is derived from asStream Creates a Routine and embeds the Env in it. 1).triangle(1. ( { e = Env. 190 . at(time) Returns the value of the Env at time. false otherwise.asStream. Env.at(0.25. Client-side Access and Stream Support Sustain and loop settings have no effect in the methods below.5).Where: Help→Control→Env asSignal(length) Returns a Signal of size length created by sampling this Env at length number of intervals.next.beats. See example above under *newClear. This allows the Env to function as a [Stream].postln. 0.

fork ) 191 .Where: Help→Control→Env })}.

postln.productID. }). ele.do({arg dev. The last three are used to identify the device. the other one is to start an eventloop that pushes every new value into the language and calls an action (like MIDIIn). This service was mainly designed to use gamepads as control input. A HIDDeviceElement’s information consists out of: the type. }).devices. which store information about the controllers of the device. The HIDDeviceService handles all the primitive calls.manufacturer.usage.cookie. HIDDevice only stores information about a device and holds an array of HIDElements.locID].min.product. [ele. that means that the eventloop actually uses this 192 .max]. ele. ele. the usage.Where: Help→Control→HIDDeviceService ID: 79 HIDDeviceService A Service that provides access to Human Interface Devices like joysticks and gamepads. The name is derived from the mac osx specifications. the vendorID. The vendorID and the productID are static for each device. the usage.do({arg ele. the productID and the locID. initialize the service by calling: HIDDeviceService. the device needs to be queued. the cookie is a number that can be used to identify an element of a device.postln. A HIDDevice’s information consists out of: the manufacturer. [dev. dev. dev. ele. 2. the product.elements. the locID depends on the (usb) port the device is connected to.buildDeviceList. the cookie. dev. now the information about the devices can be found: ( HIDDeviceService. To set up an eventloop follow these steps: 1. the minimum and the maximum value.type. There are two ways of getting values from the device: One is to poll a value. dev. ) 3. dev.vendorID.

postln.action_({arg productID. start the eventloop: HIDDeviceService. the vendorID and the locID of the device and the cookie of the element. val]. locID.devices. set an action that is called by the incoming events. 4. In addition to the value the events also deliver the productID. 6. ) 5. if a nil is passed in all devices are listed. falkenstein deviceSpecs you can add to the classvar deviceSpecs the specs of your device. cookie. vendorID. locID. vendorID.Where: Help→Control→HIDDeviceService device to push values. here is a collection of specs: 193 . val. cookie. [productID.stopEventLoop.queueDevice. ( HIDDeviceService. usage) It is also possible to search for devices in other usage pages.at(0). stop the eventloop: HIDDeviceService.runEventLoop. }). buildDeviceList(usagePage. //HIDDeviceServis by jan trutzschler v. the key used has to be the product name derived from the device info. (look in the class file) the default is: page: GenericDesktop usage: Joystick. HIDDeviceService.

Where: Help→Control→HIDDeviceService //wingman ( HIDDeviceService. \y -> 15. \a-> 1. IdentityDictionary[ \trig -> 0. //front left \r-> 7. \b -> 2. \l -> 8. \c -> 3. \r -> 9. \z -> 16. \f4 -> 7. // hat positions \x -> 14. // arrow buttons \hu -> 10. \hat-> 13 ]) ) //cyborg ( HIDDeviceService. \z-> 5.put(’WingMan Action Pad’.deviceSpecs. \f2-> 5.put(\cyborg. // axes \slider-> 17. //front right \s-> 8. \hr -> 12. IdentityDictionary[ \a -> 0. \x-> 3. \hd -> 13. \mode-> 9.deviceSpecs. \y-> 4. ) //not the right product name yet. \hat-> 18 ]). \yy-> 11. \hl -> 11. \c-> 2. \slider-> 12. 194 . so this doesn’t work. \l-> 6. \f1-> 4. \b-> 1. \xx-> 10. \f3-> 6.

For general programming.vel / 127]. sysrt. Only one set of MIDI input handling functions can be active at a time. chan. 195 .connect. These are: polytouch. vel. polytouch. MIDIIn. program. [chan.noteOff = { arg src. See the [UsingMIDI] helpfile for practical considerations and techniques for using MIDI in SC. // init for one port midi interface // register functions: MIDIIn. }. smpte. control. [chan.postln. sysrt. bend.vel / 127]. program. Certain MIDI messages are supported only through MIDIIn. The MIDIIn class MIDIIn links MIDI input received from the operating system to a set of user defined functions. num. touch.num. smpte The first argument these functions receive is an unique identifier that specifies the source of the data. chan. MIDIIn.Where: Help→Control→MIDIIn ID: 80 MIDIIn A popular 80s technology This document explains technical details of the MIDI hardware interface class. vel. Quick start for 1 port: ( MIDIIn.noteOn = { arg src. }. MIDI responders created directly in MIDIIn cannot be created and destroyed dynamically. sysex. users should not use the MIDIIn class directly.num. Note that the interface in this class has significant limitations. sysex.postln. noteOn. use the MIDIResponder classes (see helpfile: [MIDIResponder]). num. they are stored in the following class variables: noteOff. Instead. which significantly limits the ability to create flexible MIDI configurations.

}.init(inPorts. }. vel. MIDIIn.8192]. }). var outPorts = 2. }. }. MIDIIn.Where: Help→Control→MIDIIn MIDIIn. sysex. MIDIIn.127 *noteOff_(function) uid unique identifier of the MIDI port MIDIchannel ranges from 0 to 15 keyNumber 0 .outPorts). chan.pressure].postln. MIDIIn. Quick start for 2 or more ports: ( var inPorts = 2.val]. chan. val. prog. val.at(i)).prog]. bend.postln.postln. }.postln.bend . sysex. num. [chan.postln.vel / 127].control = { arg src. typically 64 unless noteOff velocity is supported *polytouch_(function) uid unique identifier of the MIDI port MIDIchannel ranges from 0 to 15 196 .sysex = { arg src. chan.val]. chan. ) [chan.sources. it is passed the following arguments: uid unique identifier of the MIDI port MIDIchannel ranges from 0 to 15 keyNumber 0 . MIDIIn.polytouch = { arg src. [chan.num. MIDIIn.num. }.bend = { arg src.program = { arg src. chan. chan. MIDIClient.127 velocity 0 . [chan. MIDIIn.do({ arg i.postln. num. ) // explicitly intialize the client class methods: *noteOn_(function) function is evaluated whenever a MIDI noteOn message is received.sysrt = { arg src.touch = { arg src. inPorts.smpte = { arg src. pressure. MIDIIn.val].postln. [chan.postln. MIDIClient. chan. }. [chan.connect(i.127 velocity 0 . [chan.127. val. }.

127 *program_(function) uid unique identifier of the MIDI port MIDIchannel ranges from 0 to 15 programNumber 0 . *sysrt_(function) uid unique identifier of the MIDI port index ranges from 0 to 15 data 0 .127 #020202 #020202 #020202 #020202 #020202 #020202 #020202 index data message 2 14bits song pointer 3 7bits song select 8 midiclock 10 start 11 continue 12 stop *smpte uid unique identifier of the MIDI port 197 .127 pressure 0 .127 *bend_(function) uid unique identifier of the MIDI port MIDIchannel ranges from 0 to 15 bend 0.16384. the midpoint is 8192 *sysex_(function) uid unique identifier of the MIDI port system exclusive data an Int8Array (includes f0 and f7) see manufacturer references for details note: The current implementation assembles a complete system exclusive packet before evaluating the function..127 value 0 .Where: Help→Control→MIDIIn keyNumber 0 .127 *touch_(function) uid unique identifier of the MIDI port MIDIchannel ranges from 0 to 15 pressure 0 .127 *control_(function) uid unique identifier of the MIDI port MIDIchannel ranges from 0 to 15 controllerNumber 0 .

ar( SinOsc. gate. SMPTE is transmitted at 1/4 frame intervals four times faster than the frame rate.Where: Help→Control→MIDIIn index data ranges from 0 to 7 4 bits Over MIDI. 10. formfreq. x = EnvGen. x = Formant.bwfreq=800. var x.adsr.boot.kr(Env. Out.kr(0. bwfreq ).0.kr(gate.local.gate)) * x. s = Server. index data 0 frames low nibble 1 frames hi nibble 2 seconds low nibble 3 seconds hi nibble 4 minutes low nibble 5 minutes hi nibble 6 hours low nibble 7 hours hi bit OR’ed with frameRate 0 -> 24fps 2 -> 25 fps 4 -> 30 fps drop frame 6 -> 30 fps Nibbles are sent in ascending order. ( MIDIIn.latency = 0.gate=0. x = Synth("sik-goo").connect. s. { arg freq=440.ar(0.Latch. s.02.formfreq=100. freq). SynthDef("sik-goo". x). 198 . }).send(s). 0.

0. x. 0.local. . s. 21).chan.set(\formfreq. val * 0.com writing to the bus rather than directly to the synth s = Server.048828125). MIDIIn.send(s). 199 .clip2(0.048828125 ). //Powerbook G4.matrix6k@somahq.boot.1]. vel.set(\freq.0).kr(0. but i haven’t used it enough //to tell for sure yet. [0.ar(LFPulse. ( s.ar(SinOsc. x.noteOff = { arg src. 0. ) //i used this and got acceptable latency for triggering synths live.midicps / 4. x. 0. { arg ffreq=100.Where: Help→Control→MIDIIn //set the action: MIDIIn. //(val * 0. MIDIIn.set(\gate. x. x.set(\bwfreq. num. x). num.postln. 512mb ram.4).1) . }). }. SynthDef("moto-rev".0).val. vel / 127 * 1000).set(\gate.num. 10.bend = { arg src. ffreq. //The latency might actually be less than sc2.vel. x = RLPF. vel / 200 ). var x.2.noteOn = {arg src.latency = 0.0. }. Out.1).chan.ar(0. }. chan.

chan.1.1. vel.postln.index). amp = 0. 2). x = Synth("moto-rev").1. var e. e = Env.boot.1.matrix6k@somahq.1. num. gate = 1.num. cutoff = 20000. 0]. chan. ’linear’.2. lfospeed=0.value = num. 0.postln. // map the synth’s first input (ffreq) to read // from the bus’ output index x.env.com prepare s.free. 7 to amp // . [0. }.range. MIDIIn. val. mod to rez. b. //set the action: MIDIIn. }.free.new([0.filterfreq.x. 200 . chan.control(s). MIDIIn. 0. KeyboardSplitfor two voices pbend to cutoff. 0.map(0. MIDIIn.control = {arg src.{ arg freq = 700.1). }. val. ( SynthDef("funk". num.adsr(0. b.3.val].midicps. val.bend = {arg src. env=Env. ) // cleanup x.1]. [chan. 0.noteOn = {arg src.connect.postln. rez = 1.Where: Help→Control→MIDIIn b = Bus.b.

1. rezspec = ControlSpec(1.\linear.1.6)}).0.ar([ Mix.s). Mix.0.init. cutbus.1.2. MIDIClient.newClear(128).001). {Saw. cutbus = Bus.1]. rezspec.2. amp = 0.0. {Saw.. gate.ar([0. Mix.at(0)).arFill(2.ar(Mix. gate = 1.0.ar(freq *2 + 0. doneAction: 2)) }). 1].send(s). lfospec.1.sources.arFill(2.value = 10000. 201 . {Saw. doneAction: 2)) }). MIDIClient. 0.enve.2.rand2. ’linear’. 0].rand2.ar(Mix. enve = Env.new(\control.rand2. cutoff).connect(0. cutspec. gate.\linear. ) then.ar(freq *0.10000. amp)}) ]). filterfreq = SinOsc.send(s). Out. [2. rezbus.kr(env.001).ar([ Mix. 0. SynthDef("strings".new([0.1. ( var keys.arFill(2. lfobus..6)}) ]).0.gate)*filterfreq.new. 6000. amp)}).Where: Help→Control→MIDIIn range = cutoff -1.ar([0. {Saw. 2).0.x * EnvGen. rez).abs. cutspec = ControlSpec(100.kr(e. range. x = RLPF. keys = Array. var x.rand2.ar(freq *4+ 0. g = Group.arFill(2.5 + 2.{ arg freq = 700. 0.kr(enve.ar(freq +2. cutbus. EnvGen. x = RLPF.kr(lfospeed.1].1).x * EnvGen. MIDIIn. Out.

bend = {arg src. { keys. if(num < 60. keys.value = 1. { node = Synth. \amp.s). lfospec = ControlSpec(0.value = cutspec.2. node) }. if(num == 7.s). keys.put(num. if(num == 1.midicps.{ rezbus. if (node. cutbus. vel.{ node = Synth.{ lfobus."lfospeed".50.at(num). vel/255]).map(val/16383.3). nil). MIDIIn. "strings". val. node = keys. // // // // // node = Synth."rez".sendBundle(nil.0. node.0.1. chan.tail(g. \amp. var node.map(val/127.new(\control. [\freq."lfospeed".new(\control.put(num. vel/255]).put(num. 202 .\linear.noteOff = {arg src.postln. num. val.noteOn = {arg src.tail(g. \amp. }. num. node) })."rez". chan.1. MIDIIn. }). num. MIDIIn.control = {arg src.map("cutoff". num. chan. chan.1. rezbus. num.2. vel. lfobus = Bus.[\freq.mapMsg("cutoff".value = rezspec.midicps.001).Where: Help→Control→MIDIIn rezbus = Bus.addToTailMsg(g.0). }. }). }. node.value = lfospec. num.0).0).basicNew("funk".s). MIDIIn.2. [\freq. vel/255]). node.3) ).map(val/127. "funk".notNil.1.midicps. var node. s.3.

0).release // then free it ..nodeID. or get the NodeWatcher to do it ) 203 . // or node.Where: Help→Control→MIDIIn s. "gate". node. }.sendMsg("/n_set".. }).

seconds. frameRate ) songPtr ( songPtr ) songSelect ( song ) midiClock ( startClock ( ) ) ) continueClock ( stopClock ( reset ( ) ) sysex ( uid. 0.sysex(MIDIClient. val ) allNotesOff ( chan ) smpte ( frames. len. [src. a. hours.16rf7]) 204 . [uid. m = MIDIOut(0. num ) touch ( chan. }. 27. val.postln.at(0). veloc ) noteOff ( chan. Int8Array[ 16rf0. }. [src. val. MIDIIn. val ) control ( chan.postln }. MIDIIn.sysex = { arg uid. chan. val]. chan. hiStatus. MIDIClient. from the operating system to a set of user defined functions.packet].connect. b. Int8Array ) send ( outport. note. ctlNum.at(0). packet. note. val ) program ( chan.uid.destinations. val].postln. chan. MIDIIn. MIDIIn. 60. m. note. m. uid. 0. chan. veloc ) polyTouch ( chan. minutes.noteOn(16. val ) bend ( chan.sysrt = { arg src.smpte = { arg src.uid). loStatus. 11. latency ) MIDIClient. methods noteOn ( chan.init. 60).Where: Help→Control→MIDIOut ID: 81 MIDIOut MIDIout objects interface MIDI output ports defined by the operating system to the language.destinations. 0.

stop 205 .start m.continue m.smpte (24.16) m.midiClock m.Where: Help→Control→MIDIOut m.

(this is default. The use of an independant object to maintain the state keeps the implementation of the Node classes simple. see: aServer. 206 . Note that server notification should be on. Node that ends is unregistered at that time.notify) the most common use: NodeWatcher. assumePlaying) aNode can be a Group or a Synth. A In some cases this can be an invaluable service.register(aNode). It watches for server node status messages: n_go n_end n_off n_on and sets the isPlaying and isRunning variables on the Node instance accordingly. *new(server) create a new instance listening to the server’s address *newFrom(server) create a new instance listening to the server’s address if there is one present already return that one *register(aNode. the node’s isPlaying field is set to true *unregister(aNode) remove the node from the list of nodes.Where: Help→Control→NodeWatcher ID: 82 NodeWatcher state notify sc-lang side node objects of their server sided Node instances (Synths and Groups) can be registered with the NodeWatcher. the NodeWatcher is created internally assumePlaying: if true.

//create a node object NodeWatcher. n. // example: n = DebugNodeWatcher(s). s. start add the OSCresponderNode to listen to the address stop remove the OSCresponderNode to stop listen to the address // example: ( b = s.makeBundle(false.listSendBundle(nil. a.freeAll.isRunning.new(s).Where: Help→Control→NodeWatcher this happens also when a node is freed. a.isPlaying. reacts to each message. ) a. it can be useful to see every node start and end it doesn’t require registration. 207 . DebugNodeWatcher for debugging. a. //free all nodes a.start. // register before creating on the server }).run(false). //start the node on the server a.isPlaying. s.isPlaying. a.isRunning. b).register(a). { a = Group.isRunning.

Where: Help→Control→NodeWatcher x = Group(s). x.stop. x. 208 .free.run(false). n.

formfreq = formfreq * ((EnvGen. the spec should be an EnvSpec.. Example: In this patch. gate) * fenvsens) + 1). detune. for Env. gate. sig. *new(obj) obj is the object that will be used as the default when the Patch is built. other data structures used to build parallel or serial structures. ffreq. formfreq. 209 . defaultControl defaultControl_ Access or change the object. Since the Formlet filter’s impulse response is a sine wave. e. formHarmAmps| var amp. The object will not be editable after patch creation. a default will be used. fenvsens. If the user doesn’t provide an exciter.kr(formfreqenv. ( // define the Instr Instr([\analog. env. attacktime. so the Patch is still CPU cheap! The result resembles CHANT (IRCA/M. formHarmRatios and formHarmAmps accept arrays that create an additive array of Formlets. { | freq. the Instr defines a filter structure. formfreqenv. The object should be a kind of object that does not have an Editor in the Patch system. or even Functions that provide additional UGens to the Patch. formHarmRatios. decaytime. 1979). Formlet is a very efficient UGen. but leaves the choice of exciter up to the user. vsens. \voxlet]. exciterFunc.Where: Help→Control→ObjectSpec ID: 83 ObjectSpec : Spec Allows any kind of object to be specified as a default for an Instr argument... Suitable objects for ObjectSpec are static Arrays.g.

nil. // formlet is a bit volatile. nil. \amp. 0. 1.07. ffreq). 0. 0. sig = exciterFunc. doneAction:2)) ! }. ) 2 // use the default exciter p = Patch([\analog.value(freq. \voxlet].notNil.ar(LPF.1]. gate)-1) * vsens + 1. \amp.free. 0. 0. p. 1. Patch({ MouseY.01]. \mydetune.9. so limit its amplitude (Limiter.ar(fr) }).play.1) }).0001. [ \freq. [Patch({ MouseX.kr(20. \freq. EnvSpec(Env(#[0. 20000.0001.5.kr(gate. #[0.1) }). // default func is an audio-rate impulse to provide the base frequency // override this with a func for a different exciter // your func may have a frequency and detune argument // it should output 1 channel only ObjectSpec({ | fr| Impulse. nil. [1])).2. 20000. 0.06) * EnvGen.ar(sig). mul: formHarmAmps ?? { 1 }). attacktime.if({ formfreq * formHarmRatios }. 0. \exp.11)). #[20. 0. \amp. 0. // move the mouse to control base freq and formant freq // watch the volume--amplitude can spike at times in this patch // when done: p. 0. \exp.kr(20.Where: Help→Control→ObjectSpec amp = (Latch. 0. 1. 1. 0.ar(sig.ugenfunc fills in the true default here ObjectSpec(nil) ]). { formfreq }). // arrays by default are nil -. \exp. EnvSpec(Env. gate. #[0.ar(Mix. nil.8. 0]. nil. 20000. nil. 0. 1. 1200].adsr(0. 0]). formHarmRatios. nil. // this func is user supplied sig = Formlet. 210 .kr(env. ObjectSpec(nil). detune). decaytime.

1) }).kr(20.free. 1. Patch({ MouseY.play. 0. nil. 0. nil. Patch({ MouseY. p.25. p.reciprocal]). 20000.ar(Saw. nil. 20000.6). 1. [Patch({ MouseX. { | fr. p.. fr*detune])) }.ar(Saw. 211 . nil. nil. p. 0.6). \voxlet]. nil. detune| fr*detune])) }.free.kr(20. nil.ar([fr.kr(20. Mix. 0]). 1. 0.ar([fr. \voxlet]. nil. { | fr.Where: Help→Control→ObjectSpec // free the patch ("free" button) and try this to change the exciter p = Patch([\analog. nil. 0. 0. 0. (1. detune| Mix.play.kr(20. // now let’s add some additiveness to the filters p = Patch([\analog. 1. 20000.25. nil. 1.1) }). nil. nil..1) }).1) }). [Patch({ MouseX. 20000. 1. (1.

ar(4) * 10. Rand(9000. x = SynthDef("test".ar(Impulse. an operation that is asynchronous. add(msg) add an osc message to the bundle add an array of osc messages to the bundle addAll(array) addPrepare(msg) add a preparation osc message. 1000).e. a list object can be used instead.ar(0.1)) }). { OffsetOut. the process waits for their reception abd then sends the bundle. offset] // example // create a new. which is sent before the bundle is sent. // this is why addPrepare is used. quant) like send. If preparation messages are given. 212 . schedSend(server.new. but the sending is synced to a given clock (TempoClock) to the next beat.Where: Help→Control→OSCBundle ID: 84 OSCBundle superclass: Object networkbundle object a bundle object that allows to add preparation messages for async processes. BPF. send(server. we have to wait until it is finished. empty instance a = OSCBundle. 0. they are sent. clock. // i. latency) send the bundle to a server. if this feature is not needed. // a synthdef that needs to be sent to the server. quant can be a pair of values: [quant.

// this can be simply sent . // is finished. 1). TempoClock.asBytes]). // free all nodes on the server // the bundle can contain several preparation messages and messages at a time.boot. // boot the server a. a. // the bundle can also be reused. // add is used with synchronous operations. a. like starting synths. if there is no specific allocated buffers/node ids. TempoClock. // the other bundles are sent.addPrepare(["/d_recv".schedSend(s. "test". 1). s. a.default. a.oscMessages. s.schedSend(s. // the proparationMessages are sent first and only when they are all completed. 1).add(["/s_new".default.preparationMessages. x. // the bundle has now the synchronous separated from the asynchronous bundles: a.Where: Help→Control→OSCBundle a. -1]).default.freeAll.schedSend(s. // free all nodes on the server // scheduled sending: the synths are started on the next beat. the synth is started when the preparation s.the bundle takes care of the server client communication // like waiting for the synthdef to be loaded.send(s). TempoClock. a. 213 .freeAll.

the cmdName parameter is simply replaced by the complete command path. triggerID..cmdName. For example /tr commands. value] This array actually specifies the source of value : [ /tr. for GUI access ) use { . We will refer to that array as a command path. message note that OSCresponderNode evaluates its function in the system process.Where: Help→Control→OSCpathResponder ID: 85 OSCpathResponder client side responder superclass: OSCresponder Register a function to be called upon receiving a command with a specific path. cmdName a command path. nodeID. addr an instance of NetAddr.g. such as [’\c_set’. *new(addr. Path defaults 214 . theResponder.defer. To create an OSCpathResponder for a specific trigger. bus index] action a function that will be evaluated when a cmd of that name is received from addr.action). in order to access the application process (e. usually obtained from your server: server-addr an address of nil will respond to messages from anywhere. args: time.. nodeID. }. Command paths OSC commands sometimes include additional parameters to specify the right responder. which are generated on the server by the SendTrig Ugen create an OSC packet consisting of: [ /tr. triggerID].

responder. For example. aSynth = { arg freq = 1. SendTrig. s = Server. nodeID.postln }. nodeID = aSynth. 666). ( var s. nil. /tr messages from one Synth but with any triggerID. commandpath. triggerID = 1.local. triggerID] makes a responder that responds to /tr messages from any Synth but with a specific triggerID.kr(SinOsc.play. aSynth.remove. triggerID. o. o = OSCpathResponder(s. response = { arg time. triggerID]. s. o.boot. setting the commandpath = [’/tr’. nodeID. message. triggerID. commandpath. }. triggerID = 1. message. response).boot.add. response. ) // switch on and off: o.add.nodeID.kr(freq).Where: Help→Control→OSCpathResponder Any element of the command path array can be set to nil to create a responder that will handle multiple command paths.addr. commandpath = [’/tr’. Buffer-getn 215 . //Here is an example: s.

. arguments: time. Server. Examples: see [OSCresponderNode] *new(addr. addr the address the responder receives from (an instance of NetAddr.addr) an address of nil will respond to messages from anywhere.g. ’/done’ action a function that will be evaluated when a cmd of that name is received from addr. }. The OSCresponder is not active until this is done. addr note that OSCresponder evaluates its function in the system process. Note: A single OSCresponder may be set up for each addr and cmdName combination. for GUI access ) use { .action). not the server).cmdName. e. either Main-recvOSCmessage or Main-recvOSCbundle is called. message. 216 . add add this responder instance to the list of active responders. in order to access the application process (e. theResponder.Where: Help→Control→OSCresponder ID: 86 OSCresponder client side network responder Register a function to be called upon receiving a specific command from a specific OSC address. Subsequent registrations will overwrite previous ones. See [OSCresponderNode]. There.defer. the messages are forwarded to the OSCresponder class using the OSCresponder-respond class method.g.. cmdName an OSC command eg.default. Whenever an OSC message is sent to the SuperCollider application (the language.

//syntax: OSCresponder(addr.add.removeWhenDone. *add(oscResponder) add the responder instance *remove(oscResponder) remove the responder instance *removeAddr(addr) remove all OSCresponders for that addr. 217 .cmdName.Where: Help→Control→OSCresponder remove remove and deactivate the OSCresponder removeWhenDone remove and deactivate the OSCresponder when action is done.action).

0. Sending data from server to client // example from SendTrig ( 218 . r. "Hello App 1"). for GUI access ) use { .0. // end application 1: n. msg| msg[1]. { | t. 57120).remove.Where: Help→Control→OSCresponderNode ID: 87 OSCresponderNode client side network responder Register a function to be called upon receiving a specific command from a specific OSC address.defer. // the url should be the one of computer of app 1 m. Setting up OSCresponder for listening to a remote application // example: two SuperCollider apps communicating // application 1: n = NetAddr("127.add.postln }).disconnect. ’/chat’. but allowsmultiple responders to the same command.disconnect. // end application 2: m. }.1".. 57120). in order to access the application process (e. same interface like [OSCresponder].sendMsg("/chat".1". // application 2: m = NetAddr("127.0. o.. // the url should be the one of computer of app 2 (or nil) o = OSCresponder(n.0. note that OSCresponderNode evaluates its function in the system process.g.

responder.Where: Help→Control→OSCresponderNode s = Server.postln.’/n_end’. ’/tr’. responder.{ SendTrig. 0. msg]. 0. b = OSCresponderNode(s. ) ( SynthDef("help-SendTrig". b. }). msg].addr.send(s).postln.boot. ) x = Synth.addr.new. }). x. a = OSCresponderNode(s.new("help-SendTrig").add.local. "this is another call".remove. Watching for something specific // end of group message s.notify.msg.postln.postln.{ "g is dead !". // register to receive this message a = OSCresponderNode(s. [time. msg.add. // g = Group.boot. }).kr(Dust. 219 .kr(1. msg.0). if(msg[1] == g. [time. s.add. }). }).responder. { arg time. responder.{ arg time. ’/tr’. a.addr.nodeID. { arg time. s.free.remove. responder.9).

responder.{ secs=secs.new.addr.{ secs = "0"++secs.asString. mins = (time/60).}).remove.asString.asString + "("++(mins. g. { arg time. { var mins. //errors.add.asString + msg[2]. (msg[1].asString + "("++(mins.free. }.asString + msg[2].Where: Help→Control→OSCresponderNode g = Group.secs. a.round(0. // put this on a gui //errors. msg. secs = (time%60).stringColor = Color.asString++":"++secs)++")").defer }).asString++":"++secs)++")". }.label = msg[1].remove 220 . ’/fail’.postln.1). f.white. if(secs<10. // cause a failure Synth("gthhhhppppppp!"). Watching for errors // example from ServerErrorGui in crucial lib f = OSCresponderNode(s.round(1). f.

A setting of TempoClock. [ [beat1.. The list should be in the following format. with times in ascending order. Class Methods *new(list) . [OSCcmd1]]. [OSCcmd2]. 0. [OSCcmdn]].as *new. The file must contain a valid SC expression. See Non-Realtime-Synthesis for more details.tempo = 1 (60 beats per minute).as *new but immediately plays it. server) . a List. [OSCcmd3]]. [beatToEndNRT. [beat_n. 0]] // finish ] For NRT synthesis the final event should a dummy event. or similar object. may be used to express score events in seconds if desired. path is a string indicating the path of the file. *play(list. It is thus important that this event be timed to allow previous events to complete. Bundles are okay. Score scheduling defaults to TempoClock. . 221 . (See also the instance method below.returns a new Score object with the supplied list.. [beat2. as well as support for the creation of binary OSC files for non-realtime synthesis. after which synthesis will cease.default.Where: Help→Control→Score ID: 88 Score score of timed OSC commands Score encapsulates a list of timed OSC commands and provides some methods for using it.) If no value is supplied for server it will play on the default Server. [\c_set. *newFromFile(path) . list can be an Array. but reads the list in from a text file.

sampleRate. oscFilePath. score_(list) . *write(list.Where: Help→Control→Score *playFromFile(path. Does not create an instance. Use clock as a tempo base. options . Use clock as a tempo base. oscFilePath. sampleFormat .default if clock is nil. If server is nil. write(oscFilePath.default as a tempo base.default if clock is nil.the sample rate at which synthesis will occur. Does not return an instance.default if clock is nil.the sample format of the output file. stop . oscFilePath . oscFilePath is a string containing the desired path of the OSC file. outputFilePath. inputFilePath.default if clock is nil. *recordNRT(list. quant) . clock) . 222 .as *write but reads the list from a file. Use TempoClock. *writeFromFile(path. The default is ’int16’. TempoClock. TempoClock.a convenience method to synthesize list in nonrealtime.as *play. headerFormat . outputFilePath . options) . TempoClock. sampleFormat.the path of the resultant soundfile.the header format of the output file. clock.an instance of ServerOptions. oscFilePath. Instance Methods play(server. If not supplied the options of the default Server will be used.a convenience method to create a binary OSC file for NRT synthesis.the path to which the binary OSC file will be written. score . server) . Use clock as a tempo base. inputFilePath . sampleRate .set the list. clock) . then on the default server. clock) .stop playing. The default is ’AIFF’.get the list.play the list on server use clock as a tempo base and quantize start time to quant. TempoClock. For details on valid headerFormats and sampleFormats see SoundFile. but reads the list from a file.create a binary OSC file for NRT synthesis from the list. headerFormat. This method writes an OSC file to oscFilePath (you have to do your own cleanup if desired) and then starts a server app to synthesize it.an optional path for an input soundfile. now if quant is 0.

sampleFormat. inputFilePath.write(g. 0. \freq. 0.sort the score time order.kr(1. 0. g. [0. ) 223 .load(s). [\s_new. 0. [\c_set.{ arg freq = 440. For details of the arguments see *recordNRT above. 0. 0.ar(0.2. sort ."w"). \helpscore. 220]]. f = File("score-test". 1002. SinOsc. ) 2) // write a sample file for testing ( var f. \helpscore. g = [ [0. 660]].3. 0.ar(freq.adds bundle to the list. [\s_new. [\s_new. TempoClock. outputFilePath. 0. NRT Examples: // A sample synthDef ( SynthDef("helpscore". sampleRate. 1001. \helpscore. saveToFile(path) . This is recommended to do before recordNRT or write when you are not sure about the packet order recordNRT(oscFilePath. doneAction: ) }).default. [0. Out.asCompileString). headerFormat.1. 1000.Where: Help→Control→Score add(bundle) . 0.synthesize the score in non-realtime. 0. \freq.2) * Line.close. 0. \freq. 440]].save the score list as a text file to path.tempo = 1.5. [1. f. 0]] // finish ]. f. options) .

\freq. 440]]. From the command line. 0. 1000. the file can then be rendered from within the build directory: . 1003. \helpscore.writeFromFile("score-test".boot.new. ) 2) // write a sample file for testing 224 .aif 44100 AIFF int16 -o 1 Score also provides methods to do all this more directly: ( var f. 1001. 0. 0. // boot the default server // A sample synthDef ( SynthDef("helpscore". 0. [\s_new. g = [ [0. 0. 0. \helpscore. [1. Out. 0.osc"). o = ServerOptions. \freq./scsynth -N test. \helpscore.recordNRT(g. 0. 0.1. 0.{ arg freq = 440. "helpNRT.2. \freq. "test. // mono output Score. doneAction: ) }). [\s_new.aiff".2) * Line. options: ) o).ar(0. 0. [\c_set. 0. 0. [\s_new. 1002.ar(freq.3.5.Where: Help→Control→Score //convert it to a binary OSC file for use with NRT Score. \freq. [0. 220]]. 880]]. [0. [\s_new. o.osc _ test.load(s). \helpscore. 660].numOutputBusChannels = 1. SinOsc.kr(1. // synthesize Real-time Examples: s. "help-oscFile". 0]] // finish ].

0. f = File("score-test". [0. 1693 ]]. [1. \freq. \helpscore. \freq. [ \s_new. [ \s_new. [ \s_new. 0. 0. ) z = Score. 1001. [ \s_new. 0. 220]].2. [0. [ \s_new.default. [1.1. 0. TempoClock. \freq. \freq. [0. \helpscore. \freq. \helpscore. 1449 ]]. f. \helpscore. 1000. \freq. 1015. 0. [\c_set. 0. \freq.7. \freq. [1. [ \s_new.newFromFile("score-test"). [\s_new.write(g. 1011. [ \s_new. 1413 ]]. [0. 0.3. 0. 1002. 1010. [0. 333 ]].1. 1000. \helpscore.8. 0. 0. \helpscore. \helpscore. [ \s_new. [ \s_new. [ \s_new. 1003. 880]]. [ \s_new.6.4. 225 . 0. [ \s_new. 1014.asCompileString). 820 ]]. [ \s_new. 417 ]]. 0. [1. \helpscore. \helpscore. 1004. 0. 0. 678 ]].1. 0. \freq. // play it on the default server z. 0. 0.5. [\s_new. 0. 1009. 0. 0. 0. 1033 ]]. [0. [0. \freq. [1. 1320 ]].6. 0. 0.5. [ \s_new.play. 0. \freq. 1016. 0. [ \s_new. 0. 0]] // finish ]. 0. 0. \freq. [0. \helpscore. 0. \helpscore. \helpscore. 0.Where: Help→Control→Score ( var f. \freq. 1008. [\s_new. \helpscore. \helpscore. 864 ]]. \freq. 1003. 0.2. \helpscore. \freq. \helpscore. 0.3. [ \s_new. \freq. \helpscore.3. 1005. [0. 712 ]]. 440]]. 1013. 0. 0. 996 ]]. 660]. 503 ]]. 0. \freq. [ \s_new. \freq. // change the list ( x = [ [0.2. \freq. f. \freq. 1006. [1.0. 1002. \freq. 0. [0. 0. [1. 0. \helpscore. \helpscore.0. \helpscore. 1012. 0.close. 1238 ]]. 1603 ]]. \helpscore. 0. [0.tempo = 1. 410 ]]. 1001. 1349 ]].4.9. 1007. [1. g = [ [0."w"). 0. 0. [\s_new. g.

// play and stop after one second ( z. 0. Prand([0. [ \s_new.sched(1. 1019.5]. 0. 1599 ]].9. SystemClock. z.inf) ). inf).0.score_(x). \freq. [1. ) // make a score from the pattern.read. 226 . \helpscore. // new pattern ( p = Pbind( \dur.0).7. \helpscore. Prand([200. 0. 0. 4 beats long z = p.0.Where: Help→Control→Score [1. \freq. 500].}).score. \helpscore. 968 ]].3.8. 0. 1017. ) // play it z. [ \s_new.postcs. 1018. z. [2. 1347 ]]. \freq. \freq. [ \s_new. [1.asScore(4. [\c_set.play. ) creating Score from a pattern SynthDescLib. 0. 0. 0. 300.stop. {z.play. 0]] // finish ].

rendering a pattern to sound file directly: // render the pattern to aiff (4 beats) p.play.render("asScore-Help.0).Where: Help→Control→Score z. 227 . 4.aif".

This is of interest to functions. to gui interface objects (sliders etc.Where: Help→Control→Spec ID: 89 Spec specification of an input datatype This is an abstract class. common subclasses: AudioSpec ControlSpec ScalarSpec Spec has subclasses which depict different kinds of possible inputs. 228 . Specs specify what kind of input is required or permissible. The class Spec itself holds a master Dictionary of common specifications. and what the range of those parameters are.) and others.

Where: Help→Control→StartUp ID: 90 StartUp ished register functions to be evaluated after the startup is fin- Superclass: Object StartUp allows you to register functions to perform an action after the library has been compiled. Class Methods *add(function) Registers an function to be evaluated after startup is finished.add { // something to do.. } } 229 . *remove(function) Removes a function that was previously registered. *run runs the functions in order. This is used for creating SynthDef in the initClass function of class files in order to be able to make the synthdef directory customizable by the startup script. Examples *initClass { StartUp.. and after the startup file has run.

Where: Help→Control→StartUp 230 .

SuperCollider does not impose much higher-level structure on MIDI functionality. despite my continual reference to CoreMIDI here. The core classes are little more than hardware abstractions (see also the [MIDI] helpfile): MIDIClient: represents SuperCollider’s communications with CoreMIDI MIDIIn: receives MIDI messages and executes functions in response to those messages MIDIOut: sends MIDI messages out to a specific port and channel MIDIEndPoint: a client-side representation of a CoreMIDI device. 231 . device and uid. and routines that wait for MIDI events. containing three variables (name. Note: This document is written from an OSX perspective. The essential behavior of the MIDI interface classes should be the same on other platforms. which is a unique identifier assigned by the system) In most cases. each physical MIDI connection (pair of in/out jacks on the MIDI interface) has one MIDIEndPoint object to represent it in the client.Where: Help→Control→UsingMIDI ID: 91 Notes on MIDI support in SuperCollider Contents Introduction Receiving MIDI input: MIDIIn dewdrop_lib MIDI framework Playing notes on your MIDI keyboard Sending MIDI out MIDI synchronization Third party libraries Introduction SuperCollider’s out of the box MIDI support is fairly thorough (although not as complete as you’ll find in commercial sequencers). All MIDI devices accessible to CoreMIDI are accessible to SuperCollider. Receiving MIDI input: MIDIIn The MIDIIn class provides two ways to receive MIDI input: MIDI response functions.

you can have only one function assigned at one time. Because these are class variables.noteOn = nil. IdentityDictionary. Technical details on each function can be found in the MIDIIn help file. 232 . assign a function to the class variable: MIDIIn. note.. chan. you could have a separate set of response functions for each channel. For example. A common usage is to assign a function that looks up responses in a collection.noteOn = { | port.Where: Help→Control→UsingMIDI 1. MIDIIn provides the responding functions with all the information coming in from CoreMIDI: source (src): corresponds to the uid of the MIDIEndPont from which the message is coming. MIDI response functions MIDIIn has a number of class variables that are evaluated when a MIDI event comes in.connect. MIDIIn. channel (chan): integer 0-15 representing the channel bits of the MIDI status byte .. chan. vel| MIDIIn.postln }. note. vel].new). The MIDIIn help file details all the supported messages along with the arguments of the responding function for the message. with subsequent arguments representing the data bytes. // stop responding [port.fill(16. noteOn = Array. noteOn noteOff control bend touch polyTouch program sysex sysrt smpte To assign a response to a particular kind of MIDI message.

num. // stop responding Supported MIDI event waiting methods are: waitNoteOn waitNoteOff waitControl waitBend waitTouch waitPoly 233 . vel| noteOn[chan].removeAt(\postNoteOn). chan. r = Routine({ var event.stop. there is an alternate technique to supply multiple responses for the same MIDI event type. event. it can take any other action you desire.status. note. // stop responding [port. { | port.noteOn = { | port. // this function will respond only on channel 0 noteOn[0]. [event. vel]. then posts information about the event. num.postln }). The advantage of this approach over using "if" or "case" statements in the response function is that you can add and remove responses without having to change the MIDIIn function.c]. Third-party frameworks exist to handle this bookkeeping automatically. chan.play.waitNoteOn. r. event. loop { event = MIDIIn.postln. 2.do(_. chan.b. See the "Third party libraries" section at the bottom of this file.value(port. vel)) }. After your routine receives the MIDI event. The MIDIIn function can serve as a "hook" into another structure that distributes the MIDI events to the real responders. vel| noteOn[0]. This routine waits for a MIDI event.put(\postNoteOn.Where: Help→Control→UsingMIDI MIDIIn. chan. num. Routines that wait for MIDI events As of December 2004. } }).

s.connect.Where: Help→Control→UsingMIDI You can have multiple routines assigned to the same MIDI event type. even numbered note numbers only. off. [\freq.00315 approx.126). // 0.c * 0. // all note-on events // play the note newNode = Synth(\default. and an incoming event should trigger only 2. If you have 500 MIDI controller routines. event. which incurs a CPU cost. on. [2.newClear(128). This would respond to note on messages from any port. // array has one slot per possible MIDI note on = Routine({ var event.b. either using branching statements or by looking up functions inside collections.waitNoteOn(nil. SuperCollider will iterate over the entire list for that event type. loop { event = MIDIIn.4 234 . and only velocity values greater than 50. 2. \amp.waitNoteOn. all 500 sets of conditions have to be evaluated. MIDIIn.00315]).. Use caution when creating a large number of MIDI response routines with very specific conditions. In that case it may be more efficient to create a smaller number of routines and evaluate some of the conditions inside routines. { | vel| vel > 50 }). ( var notes. channels 2 and 7 only. == 1 / 127 * 0. For each incoming MIDI event. 7]. event. (0. Playing notes on your MIDI keyboard The technical problem is that every note on needs to save its synth object so that the note off message can end the right server-side node. The MIDI wait method lets you specify conditions for the routine to fire based on the arguments of the corresponding MIDI responder function: event = MIDIIn.boot.midicps. newNode. notes = Array.

loop { event = MIDIIn.Where: Help→Control→UsingMIDI notes. MIDI synchronization MIDI synchronization may be performed using MIDIIn’s sysrt or smpte response functions. includes a small suite of classes designed for exactly this purpose. // look up the node currently playing on this slot.play. dewdrop_lib. outgoing MIDI messages may be delayed. // save it to free later } }). When the CPU is busy.stop.set(\gate. It’s up to the user to implement the desired kind of synchronization. newNode).stop. You can have multiple MIDIOut objects to send MIDI to different physical devices.put(event. The MIDIIn help file contains a more elaborate example.value. and release it notes[event. SuperCollider does not have a built-in class to handle this automatically. especially during graphics updates. Many users have reported timing issues with MIDIOut. off. Users interested in this functionality may wish to examine that library. ) // when done: q. } }).b.play. }. Sending MIDI out See the [MIDIOut] helpfile.b]. off = Routine({ var event. with MIDIOut you create an instance of the MIDIOut class with a port and uid.waitNoteOff. Use with caution in a performance situation. q = { on. However. 0). Unlike MIDIIn. one of the third party libraries mentioned below. 235 .

user-extensible: simple functions may be used. but it’s there for users who are desperate for the functionality.25 wait 6 pulses (16th note) 0.Where: Help→Control→UsingMIDI For sysrt. NoteOffResponder. Multichannel MIDI applications are not possible using these classes. multichannel applications. There are significant limitations. The library provides a userextensible framework of MIDI responder classes designed for multiport. and frequently-needed responses can be written into classes that inherit from the framework (see [BasicMIDISocket] and [BasicMIDIControl]) . See the [MIDISyncClock] helpfile for details. Among its features: .easy to use classes for playing MIDI notes and assigning MIDI controllers to synthesis parameters . CCResponder) that simplify the use of multiple responders when all ports and channels should respond identically. discussed in the helpfile. available from <#0000ffhttp://www. This is not really a fully supported class. to simplify assignment of events to hardware controllers 236 . Third party libraries The crucial library (included in the main distribution) includes a couple of classes (NoteOnResponder. dewdrop_lib is a third party library providing a number of useful performance features.dewdrop-world. MIDISyncClock. The responder should count the incoming pulses and multiply the rhythmic value into 24 to determine how many pulses to wait: 0.5 wait 12 pulses (8th note) 2 wait 48 pulses (half note) dewdrop_lib (third party library) includes a class. that receives MIDI clock messages and allows events to be scheduled to keep time with an external MIDI device.net>.a user-configurable array of MIDI controller numbers. external MIDI clocks output 24 pulses per quarter note.

Where: Help→Control→UsingMIDI The framework is not part of the main distribution. 237 . Interested users need to download the tarball from the website above and follow the installation instructions.

5 Core 238 .

1 Kernel 239 .5.

return nil. arguments. (OSX only).dumpAllMethods will post all class methods which this class responds to. source. If not found. Utilities browse Open a graphical browser for this Class.class. etc. return nil. 240 . findRespondingMethodFor(methodName) As above. and has buttons for navigating to the superclass. this. including inherited ones. but climb the class tree to see if the method is inherited from a superclass. If not found. subclasses. cvs. findMethod(methodName) Find the Method referred to by name.Where: Help→Core→Kernel→Class ID: 92 Class superclass: Object A Class describes the structure and implementation of a set objects which are its instances. helpfile. Shows methods. variables. dumpClassSubtree Post the tree of all Classes that inherit from this class. dumpAllMethods Post all instance methods which instances of this class responde too. dumpByteCodes(methodName) Dump the byte codes of the named method.

dumpFullInterface Post all the class and instance methods that this class responds to (i. // This will open the Collection helpfile Conversion asClass Return this. asString Return the name of the class as a String. openHelpFile Opens the help file for this Class if it exists.Where: Help→Core→Kernel→Class dumpInterface Post all the methods defined by this Class and their arguments. those defined in this class and those inherited by it). Array. helpFileForMethod(methodSymbol) Opens the helpfile for the class in which the responding method is implemented. Accessing name A Symbol that is the name of the class.helpFileForMethod(’select’). 241 .e. helpFilePath Returns the path of this Class’s helpfile as a String.

242 . superclasses An Array of this class’s superclasses. cprototype An Array of the initial values of class variables. classVarNames An Array of the names of the class variables for this class.Where: Help→Core→Kernel→Class nextclass The next class in a linked list of all classes. iprototype An Array of the initial values of instance variables. instVarNames An Array of the names of the instance variables for this class. methods An Array of the methods of this class. superclass The Class from which this class directly inherits. allSubclasses An Array of all subclasses of this. going back to Object. subclasses An Array of the direct subclasses of this.

Where: Help→Core→Kernel→Class filenameSymbol A Symbol which is a path to the file which defines the Class. 243 .

There are no instance variables or methods. Frame instances are inaccessible to the user. For error handling routines. this.Where: Help→Core→Kernel→Frame ID: 93 Frame superclass: Object Frames are used to contain the arguments. it is too dangerous to allow access to them. the relevant information from a Frame can be transferred into a DebugFrame object which can safely be inspected.getBackTrace. variables and other information for active Functions.inspect 244 . Dangling pointers could result. Since Frames are often created on the stack.

.. A Function can be evaluated by using the ’value’ method. // another Function c = a + b.postln. c. See the [Functions] help file for a basic introduction. 300]. a = { [100. Functions can respond to math operations by creating a new Function. When a FunctionDef is encountered in your code it is pushed on the stack as a Function. Accessing def Get the FunctionDef definition of the Function. Evaluation value(. // evaluate c and print the result ) See [AbstractFunction] for function composition examples. // a Function b = { 10. 200.args) 245 .choose }. For example: ( var a.value.rand + 1 }. b. Because it inherits from [AbstractFunction]. c. // c is a Function.Where: Help→Core→Kernel→Function ID: 94 Function superclass: AbstractFunction A Function is a reference to a [FunctionDef] and its defining context [Frame].

{ arg a. valueArray(. 2. 10.args. [1.use({ a = 3.valueEnvir. c. b.. If the last argument is not an Array or List then this is the same as the ’value’ method. b. 3]). [1. ) valueArrayEnvir(.valueArray(9. 7]). d].. c.postln }.. 2. { arg a. then it is unpacked and appended to the other arguments (if any) to the Function. 2. then it is unpacked and appended to the other arguments (if any) to the Function.postln }. }). ((a * b) + c).valueArray(9.postln }.args) As value above. valueEnvir(. b. c. d.postln }. { arg a.value(3.postln }. If the last argument is an Array or List. b.valueArray([1. d]. [a. c. 10). { arg a..args. 3]).Where: Help→Core→Kernel→Function Evaluates the FunctionDef referred to by the Function. d. [a. 10.) Evaluates the FunctionDef referred to by the Function. b. { arg a. b. b. b = 10. 3]). c. b. (a * b). ( Environment. If the last argument is not an Array or List then this is the same as the ’value’ method. Unsupplied argument names are looked up in the current Environment. c. b. (a * b).postln }. d]. d. If the last argument is an Array or List.. Unsupplied argument names are looked up in the current Environment.) Evaluates the FunctionDef referred to by the Function. [a. 246 .valueArray([3. { arg a.. The Function is passed the args given. c.

sum(8). t = Task({ { "I’m loopy".postln. { "2 seconds have passed.stop. 1. Useful with Task and Clocks. x = { 4. dup(n) Return an Array consisting of the results of n evaluations of this Function. 247 .loop }).}. Uses AppClock. sum(n) return the sum of n values produced. }.wait.Where: Help→Core→Kernel→Function loop Repeat this function.postln.postln.rand.rand }. t. ! n equivalent to dup(n) x = { 4.defer(2). x. defer(delta) Delay the evaluation of this Function by delta in seconds.start.".postln.dup(4).rand } ! x. { 4. }. t. 4.

.value(999) } }. stackSize) Returns a Routine using the receiver as it’s function. quant. x. You can pass a value to this function and that value will be returned from the block method..bench. block Break from a loop. { 1000000. The default is true. print is a boolean indicating whether the result is posted. } thunk Return a Thunk. Calls the receiver with an argument which is a function that returns from the method block.Where: Help→Core→Kernel→Function bench(print) Returns the amount of time this function takes to evaluate.rand }).fork.do {| i| i.postln.rand }.}) }. To exit the loop.value. and plays it in a TempoClock. if (i == 7) { break.wait.do({ "Threadin.postln.do({ 1. { 4.". 1. fork(clock.0. which is an unevaluated value that can be used in calculations x = thunk { 4. }. call . x. flop 248 .value on the function passed in. block {| break| 100.value.

Unlike Objectswitch. 1.choose. x. 249 . z = [0. e. Less efficient in generation than flop.5. flopEnvir like flop.0]. 1000]).envirFlop. 1. x = case { i == 1 } { \no } { i == 1. 40]). 3). f = { | a. ) { \wrong } { \true }. f.5 } { \wrong } { i == 2 } { i == 0 } x. this is inlined and is therefore just as efficient as nested if statements.postln. i = z. f = { | a| e = (a: if(a > 0) { a + 1 } { -inf } }. 1. 2. ( var i.3. Since the receiver represents the first case this can be simply written as pairs of test functions and corresponding functions to be evaluated if true. but not a big difference in evaluation.Where: Help→Core→Kernel→Function Return a function that.value } case(cases) Function implements a case method which allows for conditional evaluation with multiple cases. 2].flop. 1.use { f. [10. [20. f. 1. when evaluated with nested arguments.3 } { \wrong } { i == 1. -3. does multichannel expansion by evaluting the receiver function for each channel.value([-1.1 } { \wrong } { i == 1. z.value(2.1. but implements an environment argument passing (valueEnvir). b| if(a > 0) { a + b } { -inf } }.

postln }. 456. Returns in methods called by the receiver are OK. handler itself can rethrow the error if desired. Examples: // no exception handler value { 8. nil.postln. 789.postln. \didnt_continue.postln } {| error| [\catch.postln }. \didnt_continue. try { 123. protect(handler) Executes the receiver.postln }.Where: Help→Core→Kernel→Function Exception Handling For the following two methods a return ^ inside of the receiver itself cannot be caught.postln. } try { 8. error]. or nil if there was no error. If an exception is thrown the catch function handler is executed with the error as an argument. error]. ( try { 250 . The error continues to be in effect. try(handler) Executes the receiver. 789. \cleanup.zorg } {| error| error. }. 456. error]. The cleanup function handler is executed with an error as an argument.postln } {| error| [\catch.throw.zorg } {| error| error. error]. protect { 123.postln }.postln } {| error| [\onExit.throw.postln.postln. 789. error].postln.zorg. 789.postln. }. try { 123.postln.throw.postln }. try { 123.postln. \continued. protect { 8.postln } {| error| [\catch. protect { 123.postln.postln } {| error| [\onExit.postln. 789.

789. value { 123.postln. [\onExit.Where: Help→Core→Kernel→Function protect { 123.postln. a[2].postln. error]. a[\x].throw. a[1].postln.postln }. Error("what happened?"). ) ( try { a = [\aaa. \ccc.postln } value { 123. \bbb. 789. a[\x]. \ccc.postln.postln. 789. } {| error| \caught.postln } ( a = [\aaa.postln.postln. error. \bbb. a[2]. error. a[1].throw } ( protect { a = [\aaa.postln }.postln.dump.postln } {| error| } {| error| ) [\catch.postln.dump } 251 .postln. \ccc.postln. \bbb. error]. a[\x]. error.postln. a[1]. \ddd]. } {| error| ) \caught.throw. \ddd]. a[2]. 456. 456.postln.throw.postln.postln. \ddd]. \ccc.dump } ( try { a = [\aaa. } {| error| ) \caught. \ddd]. a[\x]. \bbb. error.postln. a[1].postln. a[2].

0. // note you can set the freq argument x. which is configured to allow the resulting Synth to have its \gate argument set.ar(440.ar(0.0).02 seconds.defName.3))}). 0.play(fadeTime: 0. outbus . Where reuse and maximum flexibility are of greater importance. A Server will be converted to the default group of that server.the output bus to play the audio out on. outbus.play. scope(numChannels. SinOsc.set(\freq. which is just enough to avoid a click.play is often more convienent than SynthDef. etc. SynthDef and its various methods are usually the better choice. Args in the function become args in the resulting def.play. addAction) This is probably the simplest way to get audio in SC3. The default is \addToHead. SynthDef("help-FuncPlay". { Out. and returns the Synth object.a Node.3) }. x. target . Note that reusing such code in a SynthDef requires the addition of an Out ugen. // the following two lines produce equivalent results { SinOsc. This will also be the fadeout time for a release if you do not specify. // the name of the resulting SynthDef (derived from the Functions hash value) x.see Synth for a list of valid addActions. 0.ar(outbus. fadeTime. x = { arg freq = 440. fadetime. The default is 0. outbus. 0. // fadeout over 4 seconds Many of the examples in SC3 make use of the Function.Where: Help→Core→Kernel→Function ) Audio play(target.ar(440. Nil will be converted to the default group of the default Server.play.3) }. particularly for short examples and quick testing. zoom) 252 . bufsize. Server. A Linen is also added to avoid clicks. This is equivalent to Out. The default is 0. SinOsc. such as lagtimes for controls.release(4). theoutput). The latter does have some additional options. addAction . or to respond to a release message.ar(freq.a fadein time. Function. creates and starts a new Synth with it. // this returns a Synth object. or Nil. It wraps the Function in a SynthDef (adding an Out ugen if needed). 0.play syntax. 0. 880). fadeTime .

ar(outbus.The output bus to play the audio out on. Unlike play and scope it will not work with explicit Out Ugens.The duration of the function to plot in seconds. outbus .ar(1 + i)}. bounds) Calculates duration in seconds worth of the output of this function. duration .01.screenBounds).An instance of Rect or Point indicating the bounds of the plot window. so your function should return a UGen or an Array of them. Currently only works on OSX. fadeTime . 0.The Server on which to calculate the plot.A zoom value for the scope’s X axis. If nil the default server will be used. This is equivalent to Out. server. 0. Currently only works on OSX.plot(0. which is just enough to avoid a click. and calls Server-scope to open a scope window in which to view the output. zoom . bounds: SCWindow. The default is 0. Conversion 253 . bufsize . but does not need to be the internal server. The plot will be calculated in realtime. { FSinOsc. Larger values show more. The default is 1. The default is 0.02 seconds. but plays it on the internal Server. starting from outbus.plot(1).ar(440.01.The number of channels to display in the scope window.dup(7) }. { {| i| SinOsc.scope(1) plot(duration. This must be running on your local machine. The default is 2. The default is 0. theoutput).Where: Help→Core→Kernel→Function As play above. numChannels . server . bounds .3) }. and plots it in a GUI window. The default is 4096.The size of the buffer for the ScopeView.A fadein time. { SinOsc.ar(440) }.

fadetime) Returns a SynthDef based on this Function. outClass . The default is 0.Where: Help→Core→Kernel→Function asSynthDef(rates.ar(440. // this must complete first y = Synth. rates .asDefName. 0. sends the resulting def to the local server and returns the SynthDefs name.a fadein time. outClass. prependArgs. adding a Linen and an Out ugen if needed.An Array of rates and lagtimes for the function’s arguments (see SynthDef for more details). asDefName Performs asSynthDef (see above). This is asynchronous. x = { SinOsc. The default is \Out. 254 . fadeTime .The class of the output ugen as a symbol.3) }. asRoutine Returns a Routine using this as its func argument. 0.new(x).

code Get the byte code array. varNames Get the Array of Symbols of the local variable names. Utilities dumpByteCodes "Disassemble" and post the FunctionDef’s byte code instructions to the text window. Accessing Even though it is possible to change the values in the various arrays that define the FunctionDef. argNames Get the Array of Symbols of the argument names.Where: Help→Core→Kernel→FunctionDef ID: 95 FunctionDef superclass: Object FunctionDefs contain code which can be executed from a Function. context Get the enclosing FunctionDef or Method. you should not do it. unless you like to crash. 255 . prototypeFrame Get the array of default values for argument and temporary variables.

if only one function is passed in the argument. Object returns nil when appropriate. function. *new(functions) create a new instance. a = a. "y"]). "extraordinary well written") a.. See the [Functions] help file for a basic introduction. removeFunc(function).postf(x. 1 }. nil. functions is an array of functions or objects addFunc(function.addFunc { | x="". y).value. y=""| a. "this % is an % example\n". remove a function from the list. 256 . This allows allow to deal transparently with several functions as if they were one and to append new functions at a later point. // example a = nil. "there is no % that is %\n". a.) This message is used to be able to add to an Object. y=""| a.valueArray(["x". or to a FunctionList.addFunc { | x="". y). to a Function.addFunc returns a function.postln.Where: Help→Core→Kernel→FunctionList ID: 96 FunctionList multiple function superclass: AbstractFunction A FunctionList is a function that composes multiple functions into one.value("text". 2 }. function .addFunc then returns a FunctionList. a = a.postf(x.

value if(x > 0) { 7 } { 1000. 1. 1]. 500). a.rand }).rand } }. a. 257 . // compatibility with function multichannel expansion a = nil.squared.linexp(0.value([-1.postln }. a.0. a = a. a = a.choose }). 1]) // typical usage (similar in action functions for views) d = Document.valueEnvir("list"). a.removeFunc(x).addFunc { | x=0| a = a.addFunc({ [0.keyDownAction = { "You touched the keyboard. 1.0.postln }.rand } }.value.use { x = "array".value. a = a.addFunc({ 1.Where: Help→Core→Kernel→FunctionList ( (). a. } ) // removing a function x = { "removal test". a. // mathematics a = x. a.addFunc(x).current. if(x < 0) { 17 } { -1000.".value a. y = "ominous". d.value. a = a.flop.addFunc { | x=0| a.valueEnvir.

( d. x<-(1. "already % times\n\n".keyDownAction = d..keyDownAction = d. :: "already % times\n\n".keyDownAction = nil. :: d.keyDownAction = nil.addFunc {:x. d. ).keyDownAction. // even if you don’t know if there is already an action defined // one can add one..). d.Where: Help→Core→Kernel→FunctionList d.keyDownAction = nil.).postf(x) }. 258 .keyDownAction. x<-(1.addFunc {:x.postf(x) }.

In some cases you will require another class to be initalized before you can initalize your own. In this method. This can be accomplished by: YourClass{ *initClass { Class. any class that requires it may initalize classvars or other resources. . You may depend on its resources (a classvar)... it initializes all the classes from Object down. -felix 259 .Where: Help→Core→Kernel→Initclass ID: 97 *initClass When SuperCollider starts up. } .. } Each class will be inited once. a depth first traversal of subclasses. just after it has compiled the library. // .initClass(OtherClass). and the OtherClass will have all of its subclasses inited before the method returns.

g. Assigning another value to ’s’ may cause some of the examples in the documentation to fail.postln"). Interpret interpret(aString) Compile and execute a String. clearAll set the values of the variables ’a’ through ’z’ to nil.postln. this refers to the interpreter itself. ) Compile &amp.Where: Help→Core→Kernel→Interpreter ID: 98 Interpreter superclass: Object The interpreter defines a context in which interactive commands are compiled and executed. x.clearAll.postln. 260 . this.: this. this. e. x. ( x = 123. By convention.postln Accessing The interpreter defines instance variables ’a’ through ’z’ which are always available in the interpreter. In the interpreter. the variable ’s’ is used to hold the default Server.interpret("(123 + 4000).

This will not compile class definitions. z. executeFile(pathName) Reads the file at pathName. only expressions. This will not compile class definitions.postln. The file must contain a valid SuperCollider expression. ) compileFile(pathName) Reads the file at pathName.compile("(123 + 4000). The file must contain a valid SuperCollider expression. naturally.value. z. naturally. compiles it and executes it. 261 .Where: Help→Core→Kernel→Interpreter interpretPrint(aString) Compile and execute a String. compile(aString) Compile a String and return a Function. ( z = this.interpretPrint("123 + 4000"). compiles it and returns a Function. printing the result. only expressions.postln"). returning the result. this.

Override this in class Main to do whatever you want. It has a subclass named Main which is where you should override the methods of Process. run called when the user chooses the Run menu command. One is named ’startUp’ and is called after the class library has been compiled.Where: Help→Core→Kernel→Main ID: 99 Process superclass: Object A Process is the runtime environment for the virtual machine and interpreter. 262 . The other is named ’run’ and is called when the user chooses the Run menu command. startUp called after the class library has been compiled. Override this in class Main to do whatever you want. There are two methods of interest.

if there is one. 263 . primitiveName A Symbol which contains the name of the primitive function that implements the Method. name A Symbol which is the name of the Method.Where: Help→Core→Kernel→Method ID: 100 Method superclass: Function A Method is code that is a part of the set of operations upon instances of a Class. Accessing ownerClass The Class for which the method is part of the implementation.

Override this in class Main to do whatever you want. *tailCallOptimize Returns a Boolean indicating whether tail call optimization is on. startUp called after the class library has been compiled. Setting this to false can help with debugging by including intermediate levels in an error backtrace. There are two methods of interest. 264 . The default is on. Override this in class Main to do whatever you want. run called when the user chooses the Run menu command.Where: Help→Core→Kernel→Process ID: 101 Process superclass: Object A Process is the runtime environment for the virtual machine and interpreter. *tailCallOptimize_(aBoolean) Turns tail call optimization on or off. The other is named ’run’ and is called when the user chooses the Run menu command. It has a subclass named Main which is where you should override the methods of Process. One is named ’startUp’ and is called after the class library has been compiled.

fill(7.choose. This seed can be set and after that..4. you can reproduce any sequence of randomized data just by one integer number that you can write down in your notebook. see also: [RandSeed][Pseed] //every thread.yield }) }). has a random generator seed: ( r = Routine({ loop({#[1. r. //causes this array to be identical Array.randSeed = 1923. 265 . also a Routine. //setting the random generator seed back to our initial seed r.Where: Help→Core→Kernel→Randomseed ID: 102 random generator seed Every Thread in sclang has a (pseudo-) random number generator that is responsible for all randomization within this thread. In order to save diskspace. the randgen (being strictly deterministic) produces exactly the same numbers again. r).3. Each randgen has its own seed (starting point) from which the series of values is generated.fill(7.2. r).5]. ) //using the routine to fill an array Array.randSeed = 1923.

ar(4).fill(7. Array. { arg out=0. r.0. thisThread. //use the seed to completely reproduce a sound: ( SynthDef("help-randomSeed". RandSeed. { arg seed=1956.Where: Help→Core→Kernel→Randomseed Inheriting Seeds Also it is possible to set the seed of the running thread that all threads started within will inherit. freq=440. tbus=0. seed).ar( Dust2.01) ) }).2. 270) + WhiteNoise.3. freq. Array. 10].randSeed = 1923.3. }). 0.ar([10. 0. //reset the seed thisThread.fill(7.kr(1.5]. Line.send(s). SynthDef("help-setRandomSeed".value).value). 0. doneAction:2) * Resonz.yield }) }) }. ) //run a patch ( 266 .choose.randSeed = 1923. r.send(s).4. //create a function that returns a routine r = { Routine({ loop({#[1.ar(out. Out.kr(tbus.

0.set(\tbus.0). 700)]).9. ) //sound starts to loop t. //different loop d = 1925. 0.25.play. 1. 267 .0).wait. 0. d.set(\seed. rrand(440. not interested in anything. [\freq. t. 1.randSeed = d. \tbus.wait. r. //sound is just like random again. x.start.wait.1.stop. }) }). ) //make a reset task ( d = 1250.. r = Routine({ loop({ Synth("help-randomSeed". d = 1251.//seed t = Task({ loop({ x. }) }).Where: Help→Core→Kernel→Randomseed x = Synth("help-setRandomSeed").

Where: Help→Core→Kernel→RawPointer ID: 103 RawPointer superclass: Object A class used to hold raw pointers from the host environment. 268 . no methods. No instance variables.

269 .yield.next.Where: Help→Core→Kernel→Routine ID: 104 Routine Superclass: Thread Routines are functions that can return in the middle and then resume where they left off when called again.postln.yield. Routines can be used to implement co-routines as found in Scheme and some other languages.new({ 1. seed) Creates a Routine instance with the given function.postln. a. a. ) value(inval) resume(inval) next(inval) These are all synonyms for the same method. ( a = Routine. }). Routines are useful for writing things that behave like Streams.next. The result of the method will be what the Routine yields. The other case is that the routine continues after it has yielded. or as the result of the yield method if it is being resumed from a yield. There are basically 2 conditions for a Routine: one is when the routine starts. or it is resumed from where it left off. *new(func. The argument inval is passed as the argument to the Routine function if it is being started.next. Routines inherit behaviour for math operations and filtering from [Stream]. 2. a.postln. stackSize. The stackSize and random seed may be overridden if desired. The Routine function is either started if it has not been called yet.

and you get a chance to pass in a value from the outside. inval = 123.postln. r.value("hello routine"). you are passing in a first inval. instead of declaring a variable like "valuePassedInbyYield": ( r = Routine { arg inval. the next time you call next (or synonym). inval. var valuePassedInbyYield. To access that value within the continuing routine.postln. } ) 270 . you have to assign the result of the yield call to a variable: ( r = Routine { arg inval. } ) r. }. inval.postln. This inval is accessible as the routine function argument: ( Routine { arg inval. the routine continues from there. inval.yield.yield.value("goodbye world"). valuePassedInbyYield = 123. ) When there is a yield in the routine. Typically the name inval (or inevent) is reused. valuePassedInbyYield. inval.value("hello routine").postln.postln.Where: Help→Core→Kernel→Routine When the routine starts (by calling the above methods).

postln. } } ) ( 5.value("hello routine").do { arg i. Typically a routine uses a multiple yield. r.value("hello routine"). inval. A Routine cannot reset itself except by calling the yieldAndReset method. See also in class Object : yield(outval) yieldAndReset(outval) alwaysYield(outval) If a Routine’s function returns then it will always yield nil until reset.postln. quant) 271 . 5.do { r.Where: Help→Core→Kernel→Routine r.postln. inval = (i + 10).yield. in which the inval is reassigned repeatedly: ( r = Routine { arg inval.value("goodbye world"). } ) reset Causes the Routine to start from the beginning next time it is called. play(clock. inval.

it is the SystemClock. 272 . TempoClock by default quant: either a numbern (quantize to n beats) or an array[n. seconds return the elapsed seconds (logical time) of the routine. m] (quantize to n beats. with offset m) In the SuperCollider application. it should do so with a float. usually pausing for that many seconds. Accessible instance variables Routine inherits from Thread. and then resume the routine. If it hs not played. as can any Stream. passing it it the clock’s current time. the clock will interpret that. The beats do not proceed when the routine is not playing. every time the Routine yields. which allows access to some of its state: beats return the elapsed beats (logical time) of the routine.Where: Help→Core→Kernel→Routine clock: a Clock. The seconds do not proceed when the routine is not playing. ( r = Routine { arg inval. it is the converted beat value. postf("beats: % seconds: % time: % \n". a Routine can be played using a Clock. clock return the thread’s clock. loop { // thisThread refers to the routine.

outval = r.new({ arg inval.next(’e’).0.seconds.postln.play. ) r. ("<-outval was " ++ outval). inval = 99. } }. ("<-outval was " ++ outval). outval = r. 1.postln.seconds. r.yield. ("->inval was " ++ inval). inval = 1. thisThread.next(’d’). r.next(’a’). "reset". outval = r.postln.postln. }).beats. outval.postln.yield. r. ("->inval was " ++ inval).yield. ("<-outval was " ++ outval).postln.beats. r. ("->inval was " ++ inval).clock.next(’b’). inval = 2.yield. Routine Example: ( var r.reset. outval = r.elapsedTime ).postln.postln. Main.Where: Help→Core→Kernel→Routine thisThread.next(’c’).stop.postln. ("<-outval was " ++ outval). 273 . ("<-outval was " ++ outval). outval = r. r = Routine.

5.do({ arg a. "done". ("<-outval was " ++ outval).postln.new({ 10.wait. a.postln.Where: Help→Core→Kernel→Routine outval = r. }). // Wait half second before saying we’re done 0.play(r). // Often you might see Wait being used to pause a routine // This waits for one second between each number 1. SystemClock. ) 274 . }).postln.wait.next(’f’). ) ( var r. r = Routine.

Where: Help→Core→Kernel→Thread ID: 105 Thread state 0 = not started 3 = ? 7 = running 8 = stopped 275 .

5.2 Miscellanea 276 .

xor(aBoolean) Answers the exclusive or of the receiver and another Boolean. and(function) and: function If the receiver is true then answer the evaluation of function. if( trueFunc.&amp. aBoolean Answers true if the receiver is true and aBoolean is true. If the receiver is false. or(function) or: function If the receiver is false then answer the evaluation of function. &amp. If the receiver is true then function is not evaluated and the message answers true. If the receiver is false then function is not evaluated and the message answers false.Where: Help→Core→Boolean ID: 106 Boolean superclass: Object Boolean is an abstract class whose instances represent a logical value. | | aBoolean Answers true if either the receiver is true or aBoolean is true. and false if the receiver is true. answer the evaluation of the trueFunc. falseFunc ) If the receiver is true. 277 . not Answers true if the receiver is false. Boolean is the superclass of True and False which are the concrete realizations.

Where: Help→Core→Boolean answer the evaluation of the falseFunc. and 0 if the receiver is false. 278 . binaryValue Answer 1 if the receiver is true.

$c.Where: Help→Core→Char ID: 107 Char ascii characters Chars may be written as literals using the $sign. isAlphaNum answers whether the char is an alphabetic or numeric character. Nonalphabetic chars return themselves. digit answers an integer value from 0 to 9 for chars $0 to $9. See section [01 Literals] Chars may be created from Integers using the Integer methods asAscii and asDigit. Nonalphabetic chars return themselves. $b. Testing isAlpha answers whether the char is an alphabetic character. and values 10 to 35 for chars $a to $z or $A to $Z. 279 . Conversion ascii answers the integer ascii value of a Char. For example $a. toUpper answers the upper case version of a char. toLower answers a lower case version of a char.

isPunct. var a. isFileSafe answers whether the char is safe for use as in a filename.255. 280 .{ arg i.postln.a = i. [i. isPunct answers whether the char is a punctuation character isSpace answers whether the char is white space.isControl].Where: Help→Core→Char isPrint answers whether the char is printable.a.a.asAscii. }). excludes the path separators / and : for(0.isAlphaNum.a.a. isDecDigit answers whether the char is a decimal digit $0 to $9.isPrint.

Where: Help→Core→False ID: 108 False see [Boolean] 281 .

trueFunc. { if( 6 == 9.postln.dumpByteCodes BYTECODES: (18) 0 2 4 5 8 9 11 14 15 17 FE 06 FE 09 E6 PushPosInt 6 PushPosInt 9 SendSpecialBinaryArithMsg’==’ (14) F8 00 06 JumpIfFalse 6 42 A1 00 PushLiteral "hello" SendMsg ’postln’ (17) FC 00 03 JumpFwd 3 41 A1 00 F2 PushLiteral "hello" SendMsg ’postln’ BlockReturn a FunctionDefin closed FunctionDef failure to inline due to variable declarations { 282 .{ "hello".def.{ "hello".postln. which plucks the code from the functions and uses a more efficient jump statement. falseFunc) see also: [Control-Structures] the functions will be inlined. }.Where: Help→Core→If ID: 109 if if( boolean. }) }.

• "hello". ----------------------------------BYTECODES: (12) 0 2 4 5 7 9 11 FE 06 FE 09 E6 04 00 04 01 C30B F2 PushPosInt 6 PushPosInt 9 SendSpecialBinaryArithMsg’==’ PushLiteralX instance of FunctionDef in closed FunctionDef PushLiteralX instance of FunctionDef in closed FunctionDef SendSpecialMsg’if’ BlockReturn a FunctionDefin closed FunctionDef { if( 6 == 9. in file ’selected text’ line 4 char 14 : var notHere.postln.postln.dumpByteCodes BYTECODES: (18) 0 FE 06 PushPosInt 6 283 . }) }.postln.def.postln. }.{ var notHere.postln. }.{ "hello". }) }. "hello".dumpByteCodes WARNING: FunctionDef contains variable declarations and so will not be inlined.{ "hello".def.Where: Help→Core→If if( 6 == 9.{ "hello".

Saw.0.ar ) }.5.0. SinOsc.play ) 284 .0.Where: Help→Core→If 2 4 5 8 9 11 14 15 17 FE 09 E6 PushPosInt 9 SendSpecialBinaryArithMsg’==’ (14) F8 00 06 JumpIfFalse 6 42 A1 00 PushLiteral "hello" SendMsg ’postln’ (17) FC 00 03 JumpFwd 3 41 A1 00 F2 PushLiteral "hello" SendMsg ’postln’ BlockReturn a FunctionDefin closed FunctionDef UGens can also use if the condition ugen is 0 / 1 ( { if( LFNoise1.kr(1.5) .ar.

Pattern-loop x = Prand([1. y = x. Stream-repeat(n) embeds the stream repeatedly 285 . x.yield }. x.nextN(8).repeat(6).next. 10.nextN(8). 2]).nextN(8).asStream.do({ x.asStream. y.loop.repeat(6).Where: Help→Core→Loop ID: 110 loop / repeat create an object that behaves like a stream that returns values for a limited (or infinite) number of times. Pattern-repeat(n) x = Prand([1. 2]). Function-loop repeats the function forever. f = { 3.loop }).postln }) Object-repeat(n) repeat to yield the object x = 5. x = Routine({ f.

repeat(6).yield }) }). x.Where: Help→Core→Loop x = Routine({ 3. i.nextN(8). 286 .nextN(8). Stream-loop embeds the stream repeatedly x = Routine({ 3.do({ arg i.loop. i.do({ arg i. x.yield }) }).

?? aFunction If the receiver is nil. bad values. Since this IS nil then return anObject. In class Object. value the function and return the result. In class Object. ? is defined to answer the receiver. then value the function and return the result. notNil Answer false. In class Object this message is defined to answer false. Dependancy All the messages for the Dependancy protocol (See class Object) are defined in class Nil to do nothing. or terminal values such as end-of-stream. In class Object this message answers true. 287 . This eliminates the need to check for nil when sending dependancy messages. Since this IS nil. ? anObject ? means return first non-nil argument.Where: Help→Core→Nil ID: 111 Nil Superclass: Object Nil has a single instance named nil and is used to represent uninitialized data. ?? is defined to answer the receiver. Instance Methods isNil Answers true because this is nil.

class.name. isMemberOf(aClass) Answer a Boolean whether the receiver is a direct instance of aClass. 5. 5. All objects are indirect instances of class Object. Class membership: class Answer the class of the object. 288 . respondsTo(selector) Answer a Boolean whether the receiver understands the message selector.isKindOf(Magnitude).isMemberOf(Integer). 5. isKindOf(aClass) Answer a Boolean whether the receiver is a direct or indirect instance of aClass.Where: Help→Core→Object ID: 112 Object superclass: nil Object is the root class of all other classes. Selector must be a Symbol.postln.postln.postln.respondsTo(’+’). Use of this message in code is almost always a design mistake. 5. Use of this message in code must be questioned.postln. because it often indicates a missed opportunity to exploit object polymorphism.

The copy’s named and indexed instance variables refer to the same objects as the receiver. The implementation of this message depends on the object’s class. and so on down the structure. Equality. The default implementation in Object is to answer if the two objects are identical (see below). Copying: copy Make a copy of the receiver. The definition of equality depends on the class of the receiver. === anotherObject Answer whether the receiver is the exact same object as anotherObject. In class Object. copy calls shallowCopy. Object always returns 0. != anotherObject 289 . This method works with cyclic graphs. shallowCopy Makes a copy of the object. Identity: == anotherObject Answer whether the receiver equals anotherObject.Where: Help→Core→Object Accessing: size Different classes interpret this message differently. deepCopy Recursively copies the object and all of the objects contained in the instance variables.

isInteger Answer whether the receiver is an instance of Integer. This is used by Dictionaries and Sets to implement fast object lookup. !== anotherObject Answer whether the receiver is not the exact same object as anotherObject. notNil Answer whether the receiver is not nil. Objects which are identical === should have the same hash values. Objects which are equal == should have the same hash values. isNumber Answer whether the receiver is an instance of Number. The default implementation in Object is to answer if the two objects are not identical (see below). Testing: isNil Answer whether the receiver is nil.Where: Help→Core→Object Answer whether the receiver does not equal anotherObject. Whenever == is overridden in a class. hash Answer a code used to index into a hash table. identityHash Answer a code used to index into a hash table. 290 . hash should be overridden as well. This method is implemented by a primitive and is not overridden.

1. 1. 1. ?? aFunction If the receiver is nil. 2. 1. { \wrong }. { \true } ). ( var x.5. 1.postln. 2]. { \wrong }. { \no }.5. 0. Symbols and the functions must have no variables or arguments. value the function and return the result.Where: Help→Core→Object isFloat Answer whether the receiver is an instance of Float.choose. { \wrong }. Chars.1. z = [0. { \wrong }.1. switch (z. 1. switch(cases) Object implements a switch method which allows for conditional evaluation with multiple cases. ? anObject If the receiver is nil then answer anObject. pointsTo(anObject) Answer whether one of the receiver’s instance variables refers to anObject. 1.value) and corresponding functions to be evaluated if true.postln.3.3. These are implemented as pairs of test objects (tested using if this == test. In order for switch to be inlined (and thus be as efficient as nested if statements) the matching values must be literal Integers. otherwise answer the receiver. ) or: 291 . Floats. 1. z.

x. If the last argument is a List or an Array.1} { \wrong } {1.choose) {1} { \no } {1. x = switch (z. 292 . . z.. Sends the method named by the selector with the given arguments to the receiver.5} { \wrong } {2} {0} { \wrong } { \true }..5. args) The selector argument must be a Symbol. Sends the method named by the selector with the given arguments to the receiver.3} { \wrong } {1.3.. 1. The remaining elements are unpacked and passed as arguments to the method named by the selector Printing: post Print a string representation of the receiver..postln. then its elements are unpacked and passed as arguments. z = [0..args.. performMsg(listOrArray) The argument must be a List or Array whose first element is a Symbol representing a method selector.Where: Help→Core→Object ( var x. listOrArray) The selector argument must be a Symbol. 1..1. 1. performList(selector. ) Messaging: perform(selector . 1. 2].

Dependancy: addDependant(aDependant) Add aDependant to the receiver’s list of dependants. The object making the change should be passed as theChanger. theChanger) An object upon which the receiver depends has changed. dump Print a detailed low level representation of the receiver. dependants Answer an IdentitySet of all dependants of the receiver. release Remove all dependants of the receiver. removeDependant(aDependant) Remove aDependant from the receiver’s list of dependants. changed(theChanger) Notify the receiver’s dependants that it has changed. theChanged is the object that changed and theChanger is the object that made the change. update(theChanged.Where: Help→Core→Object postln Print a string representation of the receiver followed by a newline. Any object that has had dependants added must be 293 .

The Routine. The receiver is the result passed to the calling thread’s method. it will start from the beginning. Yields control to the calling thread. yieldAndReset Must be called from inside a Routine. 294 . alwaysYield never returns within the Routine. yieldAndReset never returns within the Routine. Yields control to the calling thread. The result of yield will be the value passed to the Routine’s next method the next time it is called. Yields control to the calling thread. The receiver is the result passed to the calling thread’s method. Routines yield Must be called from inside a Routine. when called subsequently will always yield the receiver until it is reset. The Routine is reset so that the next time it is called. alwaysYield Must be called from inside a Routine. The receiver is the result passed to the calling thread’s method.Where: Help→Core→Object released in order for it or its dependants to get garbage collected.

Where: Help→Core→Ref ID: 113 Ref a reference to a value superclass: AbstractFunction A Ref instance is an object with a single slot named ’value’ that serves as a holder of an object.doSomething. // retrieve value and use it Ref is also used as a quoting device to protect against multi channel expansion in certain UGens that require Arrays.new(nil). Class methods: new(anObject) create a Ref of an object.new(object) one way to create a Ref.value. Instance methods: value Answer the value.new(something). Ref. but there is a syntactic shortcut. get 295 . example: x = Ref. ‘anObject create a Ref of an object. value_(aValue) set the value. The backquote ‘ is a unary operator that is equivalent to calling Ref.method(x). // method puts something in reference x. z = obj.

dereference Answer the value.dereference will remove a Ref if there is one. 296 . asRef Answers the receiver. Therefore anything. This message is also defined in class Object where it just returns the receiver. This is slightly different than the value message.Where: Help→Core→Ref Answer the value. because value will also cause functions to evaluate themselves whereas dereference will not. In class Object this message is defined to create a Ref of the object. set(aValue) set the value.

isSetter Answer whether the symbol has a trailing underscore. asGetter Return a symbol with a trailing underscore removed. They can be used to represent symbolic constant values. etc. asSetter Return a symbol with a trailing underscore added. Symbols are represented syntactically as literals which are described in [01 Literals] . Math 297 . Testing isClassName Answer whether the symbol is a class name. Dictionary keys. Conversion asString Convert to a String asClass Answer the Class named by the receiver.Where: Help→Core→Symbol ID: 114 Symbol superclass: Object A Symbol is a name that is guaranteed to be unique.

Where: Help→Core→Symbol Symbols respond to all unary and binary math operations by returning themselves. 298 . The result of any math operation between a Number or other math object and a Symbol is to return the Symbol. This allows operations on lists of notes which contain ’rest’s to preserve the rests.

Where: Help→Core→True ID: 115 True see [Boolean] 299 .

6 Crucial 300 .

6.1 Constraints 301 .

Not.value(3) c. reject. You can perform logical operations on the constraint object itself to further filter or refine your query. IsIn.Where: Help→Crucial→Constraints→AbstractConstraint ID: 116 AbstractConstraint subclasses: Constraint. obj % 4 == 0 }) (Constraint({ arg obj. NotNil Constraints let you specify conditions in an OOP fashion. divisible by 4 and is not the number 8.value(8) c. c. obj. c = Constraint({ arg obj.value(12) This can be used any place a function that returns true/false is required.even and: and: }) Constraint({ arg obj. IsEven. IsNotIn. select. obj == 8 }). CountLimit. IsNil. SeenBefore. Every. eg. ( // Create a constraint.do({ n = 40.rand. IsOdd. Xor. Any. 302 .not). ) c is now a constraint object that can be used to validate that an input is even. every. any ( // run numbers through it 50.value(4) c.

1.c. num.postln. num. ) ( // Use to filter a Pattern p = Pseries(0.postln }).do({arg num. ) p.do({ arg num.do({ arg num.1.postln }). ) It can be used in place of a function for SequenceableCollections.asStream. ) // Unfiltered Pseries(0.all. num.postln }).rand }) .all.100) .do({ arg num. The below example is expressed using only Constraint.asStream.fill(100.{ 100.}) // Filtered p.select(c). num.value(n)].1.select(c) // acts like a function . }).100) .100).all.reject(c). 303 . Streamsand Patterns ( // filter a collection Array.Where: Help→Crucial→Constraints→AbstractConstraint [n. ( // and here is everybody that gets rejected by the constraint p = Pseries(0.asStream.postln.

d = Constraint({ arg num.and(aConstraint) . ( c = IsEven.not). // if its even and also reject it if it is the number 4 ) 304 . num == 4 }). d = Constraint({ arg num. // if its even or it is the number 3 c = IsEven. It could also be expressed this way ( c = IsEven.Where: Help→Crucial→Constraints→AbstractConstraint ( c = Constraint({ arg obj.reject(aConstraint) . obj == 8 }).even and: and: ) }) Constraint({ arg obj.xor(aConstraint) . obj % 4 == 0 }) Constraint({ arg obj. Constraints respond to .select(aConstraint) by returning a new compound constraint that expresses that logic. obj.reject(d). e = c.not .new.new. obj % 4 == 0 }) (Constraint({ arg obj. num == 3 }).new and: and: ) Constraint({ arg obj. e = c or: ) ( d. obj != 8 }).or(aConstraint) .

Where: Help→Crucial→Constraints→AbstractConstraint 305 .

see [AbstractConstraint] for examples of Constraint 306 .Where: Help→Crucial→Constraints→Constraint ID: 117 Constraint superclass: AbstractConstraint Constraint takes a function that it evaluates whenever the constraint itself is evaluated.not . Its main benefit then over a simple function is that it responds to .xor .and .or .select by returning the logical compound constraint.reject .

77 ] ) 307 . returns true until the limit has been reached.rand. thereafter returns false. 39 ] [ 3. [ 0. r = 100.do({ arg i. if(s. 37 ] [ 2. 58 ] [ 1. 20 ] [ 9. superclass: AbstractConstraint ( s = CountLimit. 100. 38 ] [ 8.new(10).{ [i. var r. 27 ] [ 7. }) }).r].value(r). 99 ] [ 5. 93 ] [ 6. 82 ] [ 4.Where: Help→Crucial→Constraints→CountLimit ID: 118 CountLimit counts how many items have been presented to it.postln.

So it can be used in place of functions in the same manner. 26. This is faster than constructing a FunctionDef { }.postln }) }). 44.{rand(100)}) . 8.do({ arg i. 76.Where: Help→Crucial→Constraints→IsEven ID: 119 IsEven answers whether the item is even. ( Array. 84 ] ) 308 . if(s. 76.select(IsEven) . superclass: AbstractConstraint ( s = IsEven.postln [ 12. ) The class IsEven itself will respond to *value just as an instance will.fill(20. and probably executes faster.{ i.new.value(i). 30. 24. 100. 18.

0].9.3.6. 4.4. 7 ] ) 309 .7.2. 5. [1.6.9.5.8.Where: Help→Crucial→Constraints→IsNotIn ID: 120 IsNotIn answers whether an item is not included in a collection superclass: AbstractConstraint ( a = [1.0].select(IsNotIn(a)).8.3.postln [ 2.

53 ] [ 14. 19 ] [ 2. 56 ] [ 5.do({ arg i.value(r). 71 ] [ 3. 30 ] [ 13.postln. }) }). [ 0. 78 ] [ 8. r = 100. 63 ] [ 10. 5 ] [ 12.{ [i. 74 ] [ 17. 97 ] [ 6. 15 ] [ 15. 44 ] 310 .r].rand. 65 ] [ 9.not. if(s. 83 ] [ 4. 98 ] [ 7. 100. superclass: AbstractConstraint ( s = SeenBefore. 88 ] [ 1. var r.new.Where: Help→Crucial→Constraints→SeenBefore ID: 121 SeenBefore keeps a history of all items and answers whether an item has been seen by the constraint object before. 7 ] [ 11. 70 ] [ 16.

94 ] [ 66. 81 ] [ 30. 91 ] [ 75. 0 ] [ 43. 45 ] [ 62. 92 ] [ 71.Where: Help→Crucial→Constraints→SeenBefore [ 18. 18 ] [ 19. 66 ] [ 22. 10 ] [ 86. 99 ] [ 56. 76 ] [ 54. 36 ] [ 59. 96 ] [ 28. 86 ] [ 69. 25 ] [ 44. 42 ] [ 25. 89 ] [ 79. 60 ] [ 24. 29 ] [ 29. 6 ] [ 23. 13 ] [ 32. 47 ] [ 33. 67 ] [ 61. 62 ] [ 27. 49 ] [ 31. 35 ] [ 84. 59 ] [ 34. 16 ] [ 51. 3 ] [ 46. 90 ] [ 57. 34 ] [ 37. 80 ] [ 72. 57 ] [ 60. 73 ] 311 . 87 ] [ 55. 61 ] [ 36. 20 ] [ 50. 69 ] [ 81. 95 ] [ 26. 1 ] [ 38.

31 ] [ 98. 2 ] [ 89. 33 ] [ 95.Where: Help→Crucial→Constraints→SeenBefore [ 87. 8 ] [ 93. 23 ] ) 312 .

6.2 Control 313 .

install the responder automatically.Where: Help→Crucial→Control→MIDIResponder ID: 122 MIDIResponder Register multiple functions to be evaluated when MIDI events occur. value). A. src. install: If true. src. veloc. src. install = true) TouchResponder(function. chan. veloc. chan. chan. CCResponder Respond to control messages NoteOnResponder Respond to note-on messages NoteOffResponder Respond to note-off messages BendResponder Respond to pitch bend messages TouchResponder Respond to aftertouch messages Creation and initialization: CCResponder(function. install = true) NoteOnResponder(function. src. value.sources[index]. chan.uid) or the index itself. the responder will match any port. value. src. Any of the matching values may be one of the following: Nil: Match anything. B (or for Bend and Touch. chan. Integer: Match only this specific number. chan: The MIDI channel(s) to match. install = true) function: The function to execute when the incoming MIDI event matches the responder. If nil. src. 314 . These subclasses should be used for specific midi work. num: The control or note number(s) to match. the responder will fire only for messages coming in from this port. The function takes the arguments src. MIDIResponder is an abstract class. num. The number may be the system UID (obtained from MIDIClient. If false. value. num. install = true) NoteOffResponder(function. chan. veloc: The velocities to match. chan. install = true) BendResponder(function. value: The value(s) to match. return the responder but don’t install it (it will be inactive). num. src: If a number is given.

simply initialize the MIDIClient yourself before using any MIDIResponders. and only velocity values greater than 50. (0. even numbered note numbers only.remove.. // stop this responder 315 . channels 2 and 7 only. // respond to any modwheel c.postln }. chan. num. }.remove on the responder. this would respond to note on messages from any port.. c = CCResponder({ ..even } or _.126). Removal: Just call . num.even [src. The function should return true or false. vel| nil. NoteOnResponder({ | src. [2. Function: Evaluate the function with the incoming value as the argument. If you have more devices. 2. Any kind of Collection will work here. num: 1). For instance. MIDIResponders automatically initialize the MIDIClient with 1 standard device. chan.Where: Help→Crucial→Control→MIDIResponder Array: Match any item in the array. 7]. vel > 50 }). vel]. { | vel| // could also be { | num| num.

3 Editors 316 .6.

b.gui.Where: Help→Crucial→Editors→BooleanEditor ID: 123 BooleanEditor b = BooleanEditor(false). 317 . b.postln.value.

pchRatio=1.[ Sample("sounds/ a11wlk01.0. sample.ar(sample. startPos: loop: 0 start * sample. IrNumberEditor(0.1.0. the number will be passed ( InstrSpawner({ arg sample.[0.01. sample.3).1).bufRateScaleIr * pchRatio. directly into the synth def.Rand(0.[0.bufnumIr.1. doneAction: 2) }.0.numChannels.[0. IrNumberEditor(0.ar( PlayBuf.2]) ).1.bufFramesIr.05.start=0.0. IrNumberEditor(1.ir rate control a float or integer will not create a synth arg input. Pan2.gui ) 318 .dur=0.3) * EnvGen. NumberEditor(0.4]).2.perc(0.1]).[-4. ).Where: Help→Crucial→Editors→IrNumberEditor ID: 124 IrNumberEditor used with Patch or InstrSpawner to specify an . timeScale: dur.5]) ].05.wav").2.kr( Env.

. ( // works as a stream .update to all its depedants. This includes any NumberEditorGui and also any UpdatingScalarPatchOut. You can move the slider and it sends its IMPORTANT if a KrNumberEditor is connected to a Patch playing on a server. n.play ) */ from an email: KrNumberEditors support lag. whose defaultControl sets the lag to nil.boot.Where: Help→Crucial→Editors→KrNumberEditor ID: 125 KrNumberEditor superclass: NumberEditor This is the defaultControl for a ControlSpec. I have added NoLagControlSpec.n ).changed message and sends . a KrNumberEditor is like its superclass. the message to the server happens when the KrNumberEditor gets the .0.\freq). I would prefer to just have a lag preference in ControlSpec 319 . /* s. except that if used in a Patch it will be a continously modulateable control. which is what actually sends the message to the server.gui. You can set lag to nil for no Lag. Pbind( \freq. convienient for patterns n=NumberEditor(440.

binary things don’t like lag.Where: Help→Crucial→Editors→KrNumberEditor (clients that do lag eg. but it might switch to that. but its more efficient. \binary. or use a NoLagControlSpec when writing the Instr. you can register others. \loop is registred as a NoLagControlSpec. I am experimenting with different kinds of inertia Lag (hysterisis ?). and thus doesn’t use any lag at all. sliders can tell from the spec if they should do lag or not). so I’m not using LagControl right now. either way it violates the contract : it should be a function on the input object. as Jan pointed out a while ago. 320 . not at the receiving end inside of the function.

ControlSpec or StaticSpec.initial value spec .postln. This is the default control view for a StaticSpec. it will return its initial value when the patch starts.next or .6. n. see [Spec] like all editors.value . 321 .\freq).asCompileString. since it returns its float value in response to .next all return the float value.0.asCompileString . 5. but will not be modulateable after that. See KrNumberEditor for modulateable. n.[0.3.gui.Where: Help→Crucial→Editors→NumberEditor ID: 126 NumberEditor holds a float for editing NumberEditor.10]). If used in a Patch.new(value. not the editor itself. .value = 5. NumberEditor can also be used in Pbind.gui message returns a NumberEditorGui n = NumberEditor(440.6 ) ( //note that the .spec) value .value ( n = NumberEditor(2.

startRow.0. ) // programatically set it n.postln }). // now the slider moves // and sends to the server ! // controlling the display ( Sheet({ arg f. f. NumberEditor(440."post NumberEditor asCompileString". ) ( f=MultiPageLayout. ActionButton(f. f.smallGui(f).\freq).\freq). ) ( // so make sure you get the NumberEditor n=NumberEditor(440.gui(f).{ n. // default NumberEditor(440.value.resizeToFit.topGui(f).\freq).new.\freq).asCompileString. n.0.0.postln }).value = 100 n.insp.gui. n.{ n.front."post value". // it compiles as its value ActionButton(f.insp. n.Where: Help→Crucial→Editors→NumberEditor n. // smallGui never has slider 322 . n=NumberEditor(440.changed.0.

\freq).0. NumberEditor(440. h. NumberEditor(440.{ arg i.startRow.smallGui(f).0.0.gui(f. // slider 200 by 40 f.\freq).nil bounds.true).20@100.startRow.smallGui(f).smallGui(f). c = Array. slider: false f.0.\freq).gui(f. false).gui(f. var n.0. n.\freq). // verticle.new. c = Array. NumberEditor(440. true). //use gui.\freq).20@100. f. n = NumberEditor(0.nil.\freq).\freq). NumberEditor(440.smallGui(f).true).true).0.startRow.gui(h).0. 323 . NumberEditor(440. with slider NumberEditor(440. 200@40.\amp).0.fill(10. NumberEditor(440. }).Where: Help→Crucial→Editors→NumberEditor NumberEditor(440.\freq).\freq).gui(f. NumberEditor(440. with slider }) ) bug: verticle not working yet Putting them on a Sheet ( w = Sheet({ arg h. n }).{ arg i. // verticle.60@10. ) Putting them on a MultiPageLayout ( w = MultiPageLayout.startRow.fill(10.startRow.gui(f. // slider 60 by 10 f.0. var n.

n }).25 * i. w.Rect(10.Where: Help→Crucial→Editors→NumberEditor n = NumberEditor(0.13)). n = NumberEditor(0.{ arg i. c = Array. ) using a MultiPageLayout on a window ( w = SCWindow.new.front.on(w). n. w. w. ) put them on a FlowView ( 324 .fill(10. n = NumberEditor(0. var n.front.\amp).gui(p). 150.gui(w).\amp). c = Array. w. n.new. n }).front. p = MultiPageLayout. n }). p.{ arg i. var n. n.fill(10. ) Putting them on normal windows ( w = SCWindow.gui(w.startRow.\amp).startRow.

front.new(w. 325 .fill(10. c = Array.gui(w. n }).gui(p).front.front. n.{ arg i. w.Rect(10 + (15 * i). w.view. c = Array.new. 13.Rect(10.\amp).Where: Help→Crucial→Editors→NumberEditor w = SCWindow.{ arg i. var n. w. n.500.500)).fill(10.bounds). ) // a nice glitch display //verticle not working yet ( w = SCWindow.startRow.10. p.\amp).new.new. c = Array. n }).{ arg i.w. v = SCVLayoutView. n = NumberEditor(0.150)). ) // in SCVLayout not working yet either ( w = SCWindow. n = NumberEditor(0. var n.fill(10. p = FlowView(w.25.

n.view.Where: Help→Crucial→Editors→NumberEditor var n.new. ) 326 .0.{ arg i. v = SCVLayoutView. n = SCSlider(v.fill(10. c = Array.front. var n.Rect(0. w. n }).\amp). n }).new(w.100.100.20)).0. ) //works with sliders ( w = SCWindow. n = NumberEditor(0.Rect(0.bounds).20)).gui(v.w.

6.4 Gui 327 .

receiveDrag handler the list view by default gives an integer when dragging from it.200.postln })."hit me hit me hit me hit me hit me hit me hit me hit me hit me hit me hit me ".{ "yeah baby". ) ( // set minimum sizes for x and y // longer text will still cause it to expand ActionButton(nil. bigger button ActionButton(nil. the size of the button will scale to that of the string ( ActionButton(nil.postln }).40. ) ( // bigger title. 328 .white.{ "yeah baby".. ) // accepting drags by setting the view.postln }. title.{ "yeah baby". a new PageLayout will be created.."hit me"."hit me".Color. function ) if layout is nil.Color.Where: Help→Crucial→Gui→ActionButton ID: 127 ActionButton Superclass: Object crucial dependencies: PageLayout *new( layout.black).

asInteger ].currentDrag."c"]."i accept strings". the action button is accepting strings dragged to it.postln }).Where: Help→Crucial→Gui→ActionButton here i am making the action button accept dragged integers. }.debug("begin dragging").currentDrag.view. a.postln.postln }).receiveDrag = { SCView. b."b".view.items = ["a". b. b.view. b."i accept integers".postln.100@100).{ "was hit".isNumber }.value ].isString }."b". ( Sheet({ argf. }) ) here the list view is made to export a string when dragged from. a = SCListView(f. b = ActionButton(f. }.view. ( Sheet({ argf.100@100). }) ) 329 . a.items[ listView.items = ["a". listView.beginDragAction = { arg listView. a.canReceiveDrag = { SCView.items[ SCView."c"]. a = SCListView(f.canReceiveDragHandler = { SCView.receiveDragHandler = { a.currentDrag.currentDrag.{ "butt hit". b = ActionButton(f. }.

m. } ). } ). 330 . \yourName->{ "you hit yourName". \pork->{ "pork".postln. ) ( m = CXMenu( \myName->{ "you hit myName".postln. \tiramisu->{ "tiramisu".closeOnSelect = false."partials:").postln. }.postln. CXLabel(f.postln. ) On another layout ( Sheet({ arg f. m. The difference between this and PopUp is that here there are separate functions for each menu item.gui(nil). m.postln. }.Where: Help→Crucial→Gui→CXMenu ID: 128 CXMenu A pop up menu that does its action and closes itself after you select an item. }. ( m = CXMenu( \soup->{ "soup". }.gui. and with PopUp there is one action. \duck->{ "duck".

Where: Help→Crucial→Gui→CXMenu f.new.postln.fill(15.asString. x = CXMenu( \a -> { "a".newWith( Array.asSymbol -> { i.add(\more->{ "more".gui(f). ) Note that the arrow keys work to navigate once you are focused on any of the buttons.startRow.\c -> { "c". On a normal SCWindow ( w = SCWindow. i. x. }).{ arg i.postln }).front.closeOnSelect = false. 331 .\b -> { "b". x. }) ) You can add things to the menu above m.closeOnSelect = false.postln }. m. m = CXMenu.gui(w).postln }. w.postln } }) ). m.

f. }).rand).black). w.new. ActionButton(g. In one respect this is simply a lazy contraction of this : w = SCWindow.new.bounds) ( // makes a window automatically f = FlowView.decorator.backColor_(Color."a").startRow.100.100)).flow({ arg g."a").front. SCSlider(g.background_(Color.100.view. // shrinks to fit the contents afterwards // rather than this : // talk to the FlowView f. 332 .Rect(0. // normal sc views are flowed SCSlider(f.0. FlowView(parent.nextLine // it will insert a StartRow object as a pseudo-view. w.100)).0. crucial style gui objects and normal sc views can easily coexist here.Rect(0.new( w.bounds ).decorator = FlowLayout. // flow within a flow g = f.Where: Help→Crucial→Gui→FlowView ID: 129 FlowView superclass: SCLayoutView an SCCompositeView with a FlowLayout inside of it. //lazy crucial gui objects work ActionButton(f.

grey) ) ( FlowView. ) // tests ( FlowView.Rect(0.Where: Help→Crucial→Gui→FlowView // this will keep the flow as you specified it for views that follow it : ActionButton(f.0.background_(Color. }).grey) ) ( FlowView.background_(Color."next line").new.minWidth:140) }). // even after you resize a parent view etc. b = ActionButton(f."hi".minWidth:140).background_(Color.flow({ arg f.flow({ arg f. }).flow({ arg f."hi".background_(Color. f.100)). // b = ActionButton(f.flow({ arg f.grey) ) ( FlowView. b = SCSlider(f. //b = ActionButton(f.new.new.flow({ arg f.100.minWidth:140) }). g = f."hi".grey) ) ( 333 .white) }).background_(Color.new.

b = ActionButton(f. }).background_(Color.white) }). b = ActionButton(f. }).blue). ActionButton(f.flow({ arg f.background_(Color. g = f.minWidth:100).background_(Color. f.flow({ arg f.new."hi".grey) ) ( FlowView.flow({ arg f.grey) ) ( FlowView.flow({ arg f.flow({ arg f.grey) ) ( 334 .background_(Color."hi". ActionButton(f.minWidth:140).background_(Color.background_(Color."hello".flow({ arg f. }).background_(Color."hi".Where: Help→Crucial→Gui→FlowView FlowView.minWidth:100).new.background_(Color.minWidth:140) }).flow({ arg f."hello".minWidth:140).white) }). g = f.new.blue). g = f. b = ActionButton(f. f.white) }). f. f.flow({ arg f. }). f.

blue).new. }).140. b = SCSlider(f.grey) ) ( FlowView.flow({ arg f.minWidth:100). b = SCSlider(f.background_(Color.flow({ arg f.0.flow({ arg f.140.flow({ arg f.white) }). }).flow({ arg f. }). }). f.white) }). b = ActionButton(f. }).new.blue). ActionButton(f.background_(Color."hello".blue). ActionButton(f.Rect(0. ActionButton(f. })."hi".Rect(0. g = f."hello".20)).flow({ arg f. f.minWidth:140).grey) ) 335 .flow({ arg f."hello".new.background_(Color. f.background_(Color.background_(Color.background_(Color.minWidth:100).background_(Color. f.grey) ) ( FlowView.0.Where: Help→Crucial→Gui→FlowView FlowView. f.minWidth:100).background_(Color.flow({ arg f.20)). g = f.

b = f.resizeToFit(true. w.background_(Color.minWidth:140).flow({ arg f. w = f."hi". ActionButton(f.flow({ arg f.minWidth:100).minWidth: 200).grey) ) b.true)."i’m back".background_(Color. 336 . //its messed up. }).background_(Color.remove(true).white) }).Where: Help→Crucial→Gui→FlowView ( FlowView. ActionButton(f. }).flow({ arg f.true).new. g = f."hello". // add something big back in ActionButton(w.blue).resizeToFit(true. outside of the bounds w.

Color Document Font SC2DSlider SC2DTabletSlider SCButton SCCompositeView SCEnvelopeView SCFuncUserView SCHLayoutView SCMultiSliderView SCNumberBox SCPopUpMenu SCRangeSlider SCTabletView SCTextField SCVLayoutView SCView SCWindow resize 337 .Where: Help→Crucial→Gui→Gui ID: 130 GUI Classes Overview The following GUI classes have individual helpfiles. There are a number of undocumented GUI classes listed in Undocumented-Classes.

nameN . ) ( // browse all currently loaded instruments // if you have no Instr loaded. 338 . then Library. ) ( // put in something to library Library.name2 . SinOsc.phase. *new(name1.0.phase=0. onSelect) name1.. you can browse down to the leaves.. if nil.2.amp=0.. it will supply a function that guis the item.at(Instr) will return nil Instr("help-MLIDbrowser". }).ar(freq.amp).put(\test. onSelect the function that is executed when you click on a leaf node.new.name2 .Where: Help→Crucial→Gui→MLIDbrowser ID: 131 MLIDbrowser MultiLevelIdentityDictionary browser From any node.new(\test).{ arg freq=440. it will browse from the top of Library. if nil."hello"). ( // what exactly is in Library right now ? MLIDbrowser.. nameN the name of the node you wish to start browsing at. MLIDbrowser.

Where: Help→Crucial→Gui→MLIDbrowser //make a Patch when you select an instr MLIDbrowser(\Instr. Patch(instr. 339 . [\oscillOrc.do({ arg name.\synths]. you will force it to load. you need to load each one of them.name).at(name) }).{ arg instr. ) To browse all the Instr in your Instr folder. Simply by accessing each one by its first name (filename and first symbol in the name list). Instr.topGui }).

BooleanEditor([true.i. // pops a small window for you var choices.binaryValue * (2**i) }). BooleanEditor([true. ) see also [Sheet] 340 .choose). BooleanEditor([true.choose).do({ arg c.false].false]. choices.choose). choices= [ BooleanEditor([true.postln }). }).choose) ]. // receives those objects choices.false].false].false].false]. BooleanEditor([true.value. BooleanEditor([true.i.sum({ arg boolgui. c.Where: Help→Crucial→Gui→ModalDialog ID: 132 ModalDialog ( ModalDialog({ arglayout.{ // ok function arg choices.choose). choices // return your objects }.gui(layout). boolgui.choose).

they all close.new("flow").30. f.states_([[i. It can be used as the specified parent for any view.view the FlowView on the current window .resizeToFit 341 .close close all windows created by the MultiPageLayout .30 ) ) . .Color.focus( index ) focus the view on the current window . ( var f. Rect(0. creating a new window as necessary to handle overflow.front cascades all windows owned by MultiPageLayout to front .white]]) }). SCButton( f.window returns the current window being written to. f=MultiPageLayout.Color. ) The windows are treated as a group.asString.0. .do({ arg i. When one closes.front.Where: Help→Crucial→Gui→MultiPageLayout ID: 133 MultiPageLayout A MultiPageLayout creates one or more windows with FlowViews on them. It will place the view on the current FlowVIew. 800.black.

f= MultiPageLayout.32).{ arg i. f.flow({ arg subf. }). 30@30 ). but useful // f.rand.new("flow").Where: Help→Crucial→Gui→MultiPageLayout resizes all windows to fit their contents.new("a vaguely practical example"). SCSlider( f. // // 5.do({ arg i.fill(rrand(16."". f. }.300.rand.front.1.80.win.1) 342 . f. // SliderView(f.{ arg subLayout.do({ arg i.rand)) // }). // f=MultiPageLayout.0.rand. 30@30 ). 30@30 ).win.within( 100.0. SCSlider( subf. SCSlider( subf.resizeToFit. f. // // 30. 50@100 ). SCSlider( subf. brings them all to front ( var f.layRight(80. 10@150 ). // // // allocate space for a small layout within // // a verticle strip // f. sliders=Array.sliders. ) // //// layout within a layout //(var f. SCSlider( subf.hr.100. // // // html joke.layRight(100. RangeView(subLayout.rand). 30@30 ). subLayout.

clean house.registerOneShot( f. clean the poop out of their cage etc.remove message. // SliderView(f.rand.Where: Help→Crucial→Gui→MultiPageLayout // }) // }). yourObject. // // // continuing with a new section below // f. // //) A nice way to work with MultiPageLayout is with [Sheet] A MultiPageLayout closes all of its windows when any of its windows is closed.rand. f. 343 . // // // more sliders to the right of the strip // 30. // unregister a keydown etc. this allows them to release any of their own dependancies. it sends the \didClose notification (see NotificationCenter).win. // SliderView(f.win.layRight(80. }). removeOnClose(controller) this method adds the controller to the MultiPageLayout’s autoremove list. // 30.80.{ // stop the model from playing. You can register to receive that notification: NotificationCenter.do({ arg i.rand)) // }). all items on the list will be sent the .\didClose. when the window closes.hr. When a MultiPageLayout closes.rand.rand)) // }). This notification unregisters itself after being called.do({ arg i. f.80.layRight(80.rand.

even though the window is gone and the view is not visible ( and neither the window. thus severing the link between the two. They are Controllers.Where: Help→Crucial→Gui→MultiPageLayout eg: Updater. it calls . and they create actual View objects and control the interface between those and the Model. the view or the model have any direct reference to each other). and NotificationRegistration A Note about MVC/Dependencies this is some under-the-hood stuff that you don’t need to know about but might be interested in. to cause each view to sever its dependency relationship with its model. it sets the window’s onClose function to call MultiPageLayout::release. RangeView etc. When MultiPageLayout creates a SCWindow. ObjectGui (and subclasses). Otherwise.release on all of the MultiPageLayout’s dependants. in sc all Views must actually be on a window.release on all the gui objects when the SCWindow closes. there is still a link between model and view. 344 . these controllers add themselves as dependants on the models.release on every normal v iew (StringView. and the SCWindow keeps track of them in its view. allowing garbage collection. eg. this calls . this gui system has Gui classes that build and maintain an interface/gui on a specific model. when a View is created. it is added to a window.). The gui objects release their dependancy on their models. it will not get garbage collected because there is still an entry in the dependants dictionary (Object classvar) listing that view as a dependant on the model.children array. a PatchGui is a dependant of a Patch when a SCWindow is shut. (ObjectGui::guify). The MultiPageLayout calls . When a subclass of ObjectGui is added to a MultiPageLayout it adds itself as a dependant on that layout.

removeOnClose(guiObject) 345 .Where: Help→Crucial→Gui→MultiPageLayout The Gui objects (controllers) need to know when the window closes so they can release themselves from the model. in Object::guify this happens: layout.

The default guiClass for an Object is ObjectGui.howFast.Where: Help→Crucial→Gui→ObjectGui ID: 134 ObjectGui The guiClass is the class used to build a gui for an object. which // will simply show its value as a string. an example gui class YourSimpleGuiClass: ObjectGui{ guiBody { arg layout. if you click on the "nameplate". it will display // using the default ObjectGui class. // we refer to the model and // access its variable howFast. Many subclasses overide the guiClass method to specify a different class. In the MVC architecture it is the Controller. // if its a simple number. All gui classes should inherit from ObjectGui. } } 346 . which creates Views for manipulating the properties of your Model. see [gui] It is the simplest display. just the the object asString. you will open object’s inspector.gui(layout). model. and receives messages from the View and enacts the changes on the Model.

347 . // tell the model that this gui changed it }). model. // the object you are making a gui for is referred to as the model // display some param on screen.gui(layout).Where: Help→Crucial→Gui→ObjectGui // more complex YourGuiClass: ObjectGui{ var numberEditor.r) . model.action_({ arg butt. model.howFast. numberEditor = NumberEditor(model. numberEditor. }). // using non ’gui’ objects r = layout.action_({ arg val.changed message // is sent to your model update { arg changed.gui(layout). // allocate yourself some space ButtonView(layout. then we already have a correct display and don’t need to waste cpu to update it. // here we assume that someParam is something that // has a suitable gui class // implemented. var r.someParam.[0. if(changer !== this.win.300). model. //for example guiBody { arg layout. } // your gui object will have update called any time the .layRight(300.changed(this).changer.howFast = val. or that the default ObjectGui is sufficient.goApeShit.{ /* if it is this gui object that changed the value using the numberEditor.100]) .

}) ) When the PageLayout window closes that your gui object (Controller) is on. numberEditor. Sheet({ argf.new.gui(f). so it will no longer be sent the update message. n.activeValue = model.howFast.howFast would fire the action as well. */ numberEditor. /* note that numberEditor. and will then be free for garbage collection. n = NumberEditor.Where: Help→Crucial→Gui→ObjectGui if anyone else changed anything about the model. 348 . resulting in a loop that would probably crash your machine.value = model. it will be removed as a dependent on the Model. is passive. */ } } } (// you can gui an object more than once. and does not fire the numberEditor’s action. we will update ourselves here. // they are both active interfaces to the object.gui(f).value = model.howFast. n.

do({ arg i.window.states_([[i.white]]) }). f. f=PageLayout. f=PageLayout. f.layRight(30.layRight(x.Color.asString.black.Color.do({ arg i.window. f.front. You request a rectangle using layout.new("flow").new("flow"). wrapping to a new line.Where: Help→Crucial→Gui→PageLayout ID: 135 PageLayout A PageLayout is a window that manages the layout of views added to it. SCButton( f.front. var r. ) 349 . then to a new window as necessary.y) the layout manager moves its internal cursor. 800.layRight(30. 504. Wraps to the next line ( var f.states_([[i.30).Color.asString. r ) . r= f. ) Exceeding the bottom of the window wraps to a new window ( var f.30) ) . // obtain the rectangle first // in case we cascade to the next window SCButton( f.white]]) }).Color.black.

layRight(10.{ arg subf. they all close.layDown( 30.32).window. f.within( 50.layDown( 30. subf. SCSlider( subf. }).fill(rrand(16. f.window.y) allocates space and returns a Rect of size (x. subf. .30)). f.focus( index ) focus the view on the current window .window.30)). }).150.window. SCSlider( f. sliders=Array.window returns the current window being written to.new("a vaguely practical example").close close all windows created by the PageLayout . subf.layRight(x.{ arg i.resizeToFit. When one closes. SCSlider( subf.window.resizeToFit resizes all windows to fit their contents.layDown( 30. 350 .30)). f= PageLayout.toFront cascades all windows owned by PageLayout to front . brings them all to front ( var f. . 150)).30)).sliders. SCSlider( subf.layDown( 30.Where: Help→Crucial→Gui→PageLayout The windows are treated as a group.y) . SCSlider( subf. subf.

RangeView(subLayout. // 30. // // // continuing with a new section below // f. // // // html joke.rand.rand. // // // allocate space for a small layout within // // a verticle strip // f.rand)) // }).hr. // // // 5. ) // //// layout within a layout //(var f.80.new("flow").layRight(80. // SliderView(f.rand.layRight(80.300.{ arg subLayout.do({ arg i.80.Where: Help→Crucial→Gui→PageLayout f.layRight(80.rand.layRight(100. // SliderView(f. but useful // f.do({ arg i.rand. // SliderView(f. f.rand.win.100.front.rand.80. // f=PageLayout.1) }) // }). f.within( 100.0.win. // // // more sliders to the right of the strip // 30. // //) A nice way to work with PageLayout is with [Sheet] 351 .win.do({ arg i. // // 30."".win.rand)) // }). f.hr.rand)) // }).rand).do({ arg i.0. subLayout.1.

This notification unregisters itself after being called. thus severing the link between the two. allowing garbage collection. (ObjectGui::guify).registerOneShot( f. this allows them to release any of their own dependancies. all items on the list will be sent the . eg: Updater. ObjectGui (and subclasses). }). When PageLayout creates a SCWindow. // unregister a keydown etc. when the window closes. clean house. it sets the window’s onClose function to call PageLayout::release.release on all the gui objects when the SCWindow closes.\didClose. removeOnClose(controller) this method adds the controller to the PageLayout’s autoremove list. this calls . You can register to receive that notification: NotificationCenter. When a PageLayout closes. The PageLayout calls . yourObject. it sends the \didClose notification (see NotificationCenter).Where: Help→Crucial→Gui→PageLayout A PageLayout closes all of its windows when any of its windows is closed. When a subclass of ObjectGui is added to a PageLayout it adds itself as a dependant on that layout. 352 . and NotificationRegistration A Note about MVC/Dependencies this is some under-the-hood stuff that you don’t need to know about but might be interested in.{ // stop the model from playing.release on all of the PageLayout’s dependants. The gui objects release their dependancy on their models. clean the poop out of their cage etc.remove message.

these controllers add themselves as dependants on the models.release on every normal v iew (StringView. this gui system has Gui classes that build and maintain an interface/gui on a specific model. a PatchGui is a dependant of a Patch when a SCWindow is shut. The Gui objects (controllers) need to know when the window closes so they can release themselves from the model. RangeView etc. Otherwise. it will not get garbage collected because there is still an entry in the dependants dictionary (Object classvar) listing that view as a dependant on the model. it calls . and they create actual View objects and control the interface between those and the Model. to cause each view to sever its dependency relationship with its model.Where: Help→Crucial→Gui→PageLayout in sc all Views must actually be on a window. even though the window is gone and the view is not visible ( and neither the window.children array. and the SCWindow keeps track of them in its view. They are Controllers. in Object::guify this happens: layout. when a View is created. the view or the model have any direct reference to each other). there is still a link between model and view. it is added to a window.removeOnClose(guiObject) 353 . eg.).

path) object: anything that can meaningfully respond to . does a no-clobber check.print // prints object .asCompileString based archiving of objects. (makes a difference for save/save as behavior) ( SaveConsole( Array. so you don’t have to stop play.rand(16.10. makes a . nil.saveAs ) 354 . SaveConsole(object. // no previous path nil) //no layout . saves inside a TaskIfPlaying.Where: Help→Crucial→Gui→SaveConsole ID: 136 SaveConsole a tool for managing .asCompileString path: if the object you are supplying was already loaded from disk and has a known path.bak copy of any previously existing file it finds.save .200). tell the SaveConsole of this.

selected 355 ."four"] . // array of labels or a quantity action. { arg selectedIndex. selectButtonSet ]. [ selectedIndex.new( layout. // or color function selectedColor. } ) ) ( SelectButtonSet( nil. } ) ) . labels.postln. SelectButtonSet.y // optional size of each button ) ( SelectButtonSet( nil.selectButtonSet. selectButtonSet ]. // or selectedColor function x.postln. fashioned as a single object.Where: Help→Crucial→Gui→SelectButtonSet ID: 137 SelectButtonSet Radio button style set. color. [ "one". // make 16 buttons { arg selectedIndex."three". [ selectedIndex. "two".selectButtonSet. 16 .

{| i| x: ("Input" + i). ["1".new. {| i| x: ). 30 40. ("Input" + i). ["1". "2"]. 30 40.front. {| i| x: ).400@400). y: 356 .postln}. y: SelectButtonSet( FlowView. y: SelectButtonSet( SCWindow. "2"].postln}. "2"]. ("Input" + i).postln}.front. ("Input" + i).new(SCWindow.new.new. "2"]. 30 40. on various kinds of layouts/windows/nil : SelectButtonSet( nil. {| i| x: ).postln}. ["1". ["1". y: SelectButtonSet( SCHLayoutView.selectedLabel label of the selected select( index) passiveSelect( index ) action not performed color and selectedColor may be either a Color object or a function that will be passed the selected index when valued.Where: Help→Crucial→Gui→SelectButtonSet selected index . 30 40.

357 .Where: Help→Crucial→Gui→SelectButtonSet ).

"selectionStart"."selectionEnd". }).{}). ActionButton(f. A better name might be Page. ActionButton(f. ( Sheet({ argf. ) see also [ModalDialog] 358 .Where: Help→Crucial→Gui→Sheet ID: 138 Sheet a simple PageLayout that auto-resizes to fit its contents.{}).

record("SoundFiles/testy.stop . note: the play button sends the . each method adds another button.scope . 359 . tempo etc. so the button will not appear.Where: Help→Crucial→Gui→SynthConsole ID: 139 SynthConsole *new( object.| . An easy way to use it: ( Sheet({ argf. record.pauseableRecord // | .3) }. This may be used on its own and it is also a component used in AbstractPlayerGui for all Players.tempo // gui the default Tempo toggle recording on and off while you play }) ) certain controls are not yet enabled in sc3. SynthConsole({ argsynth.play message to your object.0.0.write(20) // 20 seconds .aiff") // sets defaultPath for the prompt dialog . SinOsc. stop.play .fftScope .ar(300. layout) convenient buttons for common utilities: play.f) // if no layout provided it will create one .formats .

you.tabletTracking. // turn back on the wacom mouse }).{ arg path.register(yourSynthConsole. NotificationCenter. // path is passed in with the notification savedTo = path.\didStop. }).\didRecordOrWrite.you.Where: Help→Crucial→Gui→SynthConsole see also [FunctionPlayer] SynthConsole sends notifications that you can register to recieve through NotificationCenter: NotificationCenter.{ // do something like true.register(yourSynthConsole. 360 .

onFunction.title. }.new(layout. 361 .initialState) t = ToggleButton(nil. }.offFunction.toggle.{ "on".false).postln.Where: Help→Crucial→Gui→ToggleButton ID: 140 ToggleButton ToggleButton."push me".{ "off". t.postln.

6.5 Instr 362 .

// // // // \freq -> {[ ModalFreq(StreamKrDur(Pseq(Array..0. You could use this to customise your "auto input creation" in any number of ways. EnvSpec -> {[ EnvEditor. In this distribution.adsr) ]} ).Where: Help→Crucial→Instr→ControlPrototypes ID: 141 ControlPrototypes Patches automatically create inputs for This is a registery of controls.fill(16. *define( associations. it gives you some suitable Player object to use as an input.fill( ]}. cataloged by the Spec of their output. 363 . In other words: you give it a Spec. etc. Patch simply selects the first in the list..new(Env.{ rrand(0. In your Main-startUp method: ControlPrototypes. Other methods of ControlPrototypes use the full list. The function is valued each time so that the control is a unique instance.25) .round }).define( \trig -> {[ StreamKrDur(Pseq(Array. no special controls are registered for specific specs..11).. the values are functions that return arrays of prototypes. It was used by Patch to procure suitable control objects to satisfy an argument to a function..) Keys are either symbols or classes. ]}.

gadgets and widgets. 364 . This class also serves to decouple Spec from knowing of the various controls.Where: Help→Crucial→Instr→ControlPrototypes You may freely change or redefine control protypes while working/composing without recompiling.

oscillators.0. By default the directory Instr.dir = " /Documents/SuperCollider/Instr".sin" The older form array notation also works: Instr([\oscillators.sc or oscillators it expects to find in one of those files an Instr named "oscillators.dir is "build/Instr" or you may set Instr. Specify by dot notation to look for a file named ’oscillators’ : Instr( "oscillators.at(\sin) or: Instr(\sin) If the Instr is not found in the Library it will search in the Instr directory and load it from a file. SinOsc.dir in your startup. oscillators.Instrument An Instrument is a named sound function that is stored in the Library. Instr. Storing: Instr(\sin.oscillators. { arg freq.subfolder.sin") It will look for the files oscillators.0. Retreiving: Instr.ar(freq.Where: Help→Crucial→Instr→Instr ID: 142 Instr .amp.txt.\sin]) 365 . amp) }).sin") Instr( "folder.rtf.

these can be guessed from the argnames. and the working range of values..int2 = -5.sin" in folder/subfolder/oscillators [\oscillators.one".width2=0. different lazy ways to specify the spec. They may be used in many other situations.\sin "oscillators.width3=0. \sin] function .the Instr’s ugenFunc When using your Instrument with Patch THERE IS NO NEED TO USE Out.at(\freq) If nothing is found there.Where: Help→Crucial→Instr→Instr Instr(name. inputSpecs Specify what kind of input is required.ar though you may explicitly use it if you wish.int1=5. name .{ arg freq=440.sin" in file oscillators "folder. somewhat optional .function.rq=0.specs.4.specs.1. see [Spec] and [ControlSpec] if no spec is supplied.subfolder. and you will find many uses where you will wish to query the specs.outputSpec).inputSpecs. eg arg freq -> looks for Spec. Instr will use the function’s argument name to lookup a spec in Spec. width1=0.1.. The default/initial value for the Spec is taken from the functiondefaults. 366 . ( Instr("minimoog. ffreqInterval=0. It will be appended to your ugen graph func if needed.. 1 These specs are used by Patch to determine the suitable type of input. it will default to a ControlSpec with a range of 0 .1.oscillators.

// as(Spec.#[ // specs \freq. .\linear.two".specs [-48.0.at(\unipolar) // try the argname width2. 367 . so the default is ControlSpec(0.\linear.int2 = -5. so use function’s arg name (\freq) // to look up in Spec.1.4.1] ]).{ arg freq=440. width1=0. p=Pulse.3). An Instr can be .midiratio. freq.width3]. [ width1.1) [-48.width2.[-48.1]. that fails.3).ar([ freq * int1.1. ffreqInterval=0.48.rq=0.width2. var p.specs.width3=0.1].48.width2=0.#[ nil.kr or can even return an object. [-48.midiratio.\linear) \unipolar. // nil.48. // // try Spec.ar(p).1. \unipolar.ar(p).midiratio].\linear.InstrSynthDef can determine the outputSpec by evaluating the ugenGraph and finding what the spec of the result is.\linear.midiratio.rq) }.ar([ freq * int1. Playing ( Instr. freq * int2. RLPF.freq * ffreqInterval. a player.48.rq) }.new(-48. nil.1.0.ar(Mix.48.int1=5.width3]. freq.midiratio.new("minimoog. freq * int2.midiratio].1]) // => ControlSpec.Where: Help→Crucial→Instr→Instr var p.\linear. p=Pulse. [ width1.ar(Mix. ) outSpec optional . or a pattern.freq * ffreqInterval.ar. RLPF.

play ) ( { Instr.play ) ( { Instr.two".1. [-48.1.kr(0.1] ]).kr(0. }.ar( LFNoise1.Where: Help→Crucial→Instr→Instr [-48.at("minimoog.700) ) }.kr(0. }.1].two") .700) ] ).\linear.300.700) ).[1000]). ) ( Instr.two".48.48. [-48.\linear.1].two".play ) but by far the best way is to use Patch : Patch("minimoog. [ LFNoise1.two"). \unipolar.play 368 .300.\linear.48. \unipolar. \unipolar.1.at("minimoog.ar( "minimoog.ar( LFNoise1.play ) ( { "minimoog.300.

ffreqInterval=0. var p.inf) ). freq.int2 = -5.3).gui Patterns ( Instr([\minimoog.{ arg freq=440. // args are passed into the function \int1.kr(Env. d.int1=5.1.Where: Help→Crucial→Instr→Instr Patch("minimoog.midiratio].asSynthDef.two").store.doneAction: 2) }).width1=0.width3].ar([ freq * int1. d = p.play ) see also InstrGateSpawner and InstrSpawner An Instr is not a SynthDef An Instr creates an InstrSynthDef (a subclass of SynthDef) 369 .inf).width2=0. // no args.perc.0.30].Prand([10.11. p=Pulse.name.midiratio.rq) * EnvGen. // note is converted to freq by things in NotePlayer \note.0.freq * ffreqInterval. Patch automagically creates KrNumberEditors SynthDescLib.read.width3=0.4.width2. freq * int2.20.1. Prand([-3. RLPF.midiratio.\two]).rq=0. [ width1.ar(Mix.1.ar(p). Pbind( \instrument. p = Patch([\minimoog.\two].13].global.7.

Using different Patches.maxDelay)]. audio }). quantity=4.). audio = AllpassL.decay=1. can be passed into Instr functions. 0.01. 370 . fixed floats. the others were fixed floats that did not require synth inputs. For instance an Integer may be passed in: // caution: mind the feedback. Patch(\qAllpassA.ar([1. An Instr can also include extra arguments that will be used in building the synth def. decay) }).rrand(0.2]) }.ar(audio. Envelopes. Envelopes etc. but will not be Control inputs in the final synth. When Patch is used to specify the inputs to the function some of these inputs will be reduced to fixed values (integers.Where: Help→Crucial→Instr→Instr Each argument in the function for a SynthDef creates a Control input to the Synth that will eventually play on the server.3. [rrand(0. floats. and the resulting SynthDef will contain those inputs hard-coded. fixed integers.1. Samples etc. 1.maxDelay).[ { AudioIn.asInteger). it is possible to write many SynthDefs from the same Instr. 8 ]).play ) The first input to the synth is a stereo audio rate input. AudioIn ( Instr(\qAllpassA.3. ( quantity.maxDelay=0.do({ var x.01.chanDiff=0.{ arg audio. maxDelay.

ar(\rlpf. Here the \rlpf that is used inside doesn’t produce a synth def. sfp. the better approach is : Instr("can-do". but is used as a simple function in the ugenGraph of the \sawfilter Instr which does make a synthDef.[ Patch({ Saw.ffreq=400.0.ar( input.{ arg input. It is not generally possible to use the . 371 .{ arg input. Instr(’no-can-do’.{ arg sfp.amp=1.ar method on a player inside of an Instrument function.ffreq.amp=1.rq. It is a complex process that cannot be compiled into a SynthDef. If the input supplied is stereo.ar([400.ar * amp }). a bus. and various stages of preparation.1.0.{ arg freq. rq ) }). [ Saw.1) }) // in stereo ]).0. ffreq.440].Where: Help→Crucial→Instr→Instr Instr(\rlpf.rq=0. Because an SFP (soundfile player) will require a buffer.0. the synthDef produced will be stereo. RLPF.play ) It is possible to play another Instr inside of your Instr: ( Instr(\sawfilter. ( Patch(\rlpf. This was possible in sc2.1) . Instr. input * amp }). You cannot use a sound file player in this way: sfp = SFP("path/to/soundfile"). rq ]) }) ) and thus get further reuse out of your library of functions.ar(freq. ffreq.

at("minimoog.gui see [Patch] [InstrGateSpawner] 372 .Where: Help→Crucial→Instr→Instr Patch("can-do".gui The gui for Instr is a simple display of the arguments and specs.[ SFP("path/to/soundfile") ]) .one"). // default gui display for Instr Instr.

InstrAt could be used in Pbind or Pwhile or anywhere a { } function is needed. 373 . reloadable reference to an Instr by its name a Patch already saves the name of the Instr as its means of addressing it.Where: Help→Crucial→Instr→InstrAt ID: 143 InstrAt a compile-string-saveable.

PlayBuf. sample. 1 ) * EnvGen. args that are of rate \scalar (floats.as per Patch.ar( sample. Envs.pchRatio=1. nil args will be auto-created. Env.fill(4. args that are of rate \stream (all Patterns) will be streamed. args that are Players will play continously in their own synths and be patched into each spawn event synth.numChannels.inf).0.0.choose.doneAction: }. Prand( Array.0. 1. start * sample.-2].4) 2) 374 .wav").1. delta . pchRatio.as per Patch.bufFramesIr.start=0.bufnumIr.1.kr(env.midiratio. args. delta ) instr . args .env.sine(0.[ Sample("a11wlk01. samples) will be passed into the instr function and are subsequently fixed. in seconds see InstrGateSpawner for beats and for variable legato // start and pchRatio are streamed ( InstrSpawner({ arg sample.{ Pseries(rrand(-20.rrand(5.2. Pbrown(0.20)) }).30). may be a function or an Instr name.Where: Help→Crucial→Instr→InstrSpawner ID: 144 InstrSpawner superclass: Patch InstrSpawner( instr .a float or pattern.inf).[2.

levelScale: rq) * EnvGen.asr. is fixed at -1 ( InstrSpawner({ arg sample.doneAction: }.rq.wav"). 7.[ Pfunc({ 0.bufnumIr. 2) fenvmod).play ) // pchRatio will not stream.range(0.0. Env. PlayBuf.bufFramesIr.1.05).ar( Pulse.ar( freq.degreeToKey([ 0. 10 ]).0.midicps * 3 }).1 ) * EnvGen. 8.0.4) 2) ]. width. 5. sample. 1.0.play ) the Patchin the width input plays continuously and is patched into each spawn event ( InstrSpawner({ arg freq.kr(envperc.1.1.fenvmod. 15. -1.width.start=0.inf). Pbrown(0. Env.0.1.start * sample.ar( sample.numChannels. 3.0. 2.pchRatio=1. RLPF.pchRatio.Where: Help→Crucial→Instr→InstrSpawner ]. // an OutputProxy 375 .debug("width").envperc.env.0.3.2.99) }). width ).rand.kr(fenv.01.[ Sample("a11wlk01. EnvGen.kr(env.06). 6000.fenv.0. Patch({ FSinOsc.125).doneAction: }.sine(0.kr(0.

fenvmod.perc(releaseTime: ]. Env.envperc.amp=0.0.kr(fenv.8) 15. 5.env.width.midicps * 3 }).range(0.play ) note: 0.0).ar( Pulse.125). 3.perc(releaseTime: ]. Env.kr(0.0.1. 2. SinOsc.range(0.[ Pfunc({ 0.degreeToKey([ 0.125).{ arg freq=1000.levelScale: rq) * EnvGen. 8. 2) fenvmod).99).debug("width").fenv.0.0.0.0.ar(freq. Patch({ [ FSinOsc. width ).mul: amp) 376 .kr(0.doneAction: }. RLPF.3.1. 7.asr. 1.0.ar( freq.rq.play ) 0. width.Where: Help→Crucial→Instr→InstrSpawner Env.99).01.rand. EnvGen.01.05.0.05. ] }). FSinOsc.kr(envperc.5). 6000. 10 ]).8) for beats see InstrGateSpawner the stereo Patchin the width input causes the InstrSpawnerto expand to stereo ( InstrSpawner({ arg freq. // an OutputProxy ( Instr(\InstrSpawner.

1.3.kr(env.inf).1.sine // does not get streamed ]. 2) i = InstrSpawner(\InstrSpawner.[0.[ nil.[ Pbrown(45.1 ). 0.gui ) // how to get eventCount like sc2 Spawn ( 377 . 0.05. // accept a default KrNumberEditor nil. SinOsc.kr(env. InstrSpawner(\InstrSpawner.doneAction: }). i. Env.0]) // polled each time ).90.ar(freq.amp=0.doneAction: }).play ) sliders are polled on the gui ( Instr(\InstrSpawner. NumberEditor(0.Where: Help→Crucial→Instr→InstrSpawner * EnvGen.mul: amp) 2) * EnvGen. // accept a default KrNumberEditor Env.1.env.midicps.1.{ arg freq=1000.sine // does not get streamed ].

freq.envperc.0. width ).0.rand.. of the event count all in the pattern domain. 7. Env.inf). and lets you do wrapping or scaling etc.5.asr. Pseries(0.levelScale: rq) * EnvGen.1.0.rq. 378 .play ) 0. EnvGen.Where: Help→Crucial→Instr→InstrSpawner InstrSpawner({ arg eventCount=0.width. // do something with eventCount if you need it. Env. 3. is only on when you need it. 10 ]).kr(envperc. this is more flexible.25).kr(fenv.degreeToKey([ 0. 5.5]. // infinite counting //aeolian Pfunc({ 0.fenv.0.midicps * 3 }).0.ar( freq.1. 2.[0. 8..perc(releaseTime: ].ar( Pulse.1) 15. doneAction: }. RLPF. Patch({ LFTri. 6000.1.kr(0.fenvmod.5) }).[ 2) fenvmod).

env.0. 0. Saw.args.2.inf).-1.midicps.kr(env.25 // 16th notes 379 .0.{ arg freq=1000.doneAction: }).mul: amp) 2) * EnvGen. Env.0.amp=1. z = InstrSpawner2(\InstrSpawner.0.Where: Help→Crucial→Instr→InstrSpawner2 ID: 145 InstrSpawner2 InstrSpawner2.90.ar(freq.0.asStream and the stream is iterated during play noteOn is a stream of values meaning: 1 noteOn arg streams are iterated and sent to a new synth 0 rest -1 legato arg streams are interated and sent to the last synth beatsPerStep (default 0.[ Pbrown(40.3.25) how many beats to wait between each step tempo (default is global Tempo) the Tempo object used for conversions ( Instr(\InstrSpawner.inf).sine // does not get streamed ].noteOn.0. beatsPerStep. 0.0].0.tempo) name the instr name args each argument is taken .new(name.1.0.-1.0. Pseq([1.

stop. z.play.gui 380 . ) z. z.Where: Help→Crucial→Instr→InstrSpawner2 ).

thus fixing them in the synthDef objects such as Sample can be used in the course of the ugenGraph evaluation to add ’secret’ additional inputs. all other classes need do nothing.argIndex) BufferProxy classes use the argument index to build a unique key so they dont conflict with other BufferProxies.lag) addIr(argName.value) addInstrOnlyArg(argName. and in fact the control it was passed is nil since it would have used 381 . objects such as Env or Float or Array will pass themselves as an instrOnly arg. how it works : InstrSynthDef. (see below) the synthDef builds Control objects from the kr and ir inputs.Where: Help→Crucial→Instr→InstrSynthDef ID: 146 InstrSynthDef this is how Patch performs its magic.build( instr.kr(control. outClass ) each object is asked to initForSynthDef(synthDef.1) Object returns itself so a Sample or an Env is passed into the instr function.argIndex) Players return In.kr the control is a kr OutputProxy that indicates the bus that input should listen to. each object is asked to return an instrArgFromControl(control. it can safely pass a 0 as it will be asked what bus it is playing on when the actual synth is being started. this. if a Player does not yet know its bus assignment. each object is asked to addToSynthDef(synthDef.argName) depending on the objects rate it asks the synthDef to addKr(argName. objects.value) the object may choose which initial value to pass.value.ar(control. KrNumberEditors return either the raw control or wrap it in a Lag Stream2Trig returns an InTrig.numChannels) or In.

thus a Sample can pass itself to the instr function as an object. the name should represent the instr name and the fixed inputs that were used to evaluate it. this can also be used to request a tempo bus input (not yet implemented) the Out. the unique synthDef name is calculated. 382 . and then request a synth input that will be used to get the bufnum dynamically passed in when the synth actually plays. BufferProxy objects (Sample etc. any Patch that uses the same fixed inputs (SimpleNumbers) should be able to share the synthDef.) may request to addSecretIr or addSecretKr arguments. this is to request additional inputs to the synth that do not have arguments in the instr function. during the course of the ugenFunc evaluation.ar and a kr control of the name \out are added bassed on the rate and numChannels of the result of the ugenFunc. and all the variable inputs should be of compatible rate and numChannels.Where: Help→Crucial→Instr→InstrSynthDef addInstrOnlyArg the instr function is valued with those objects.

build a gui for that player.Where: Help→Crucial→Instr→Interface ID: 147 Interface This sets up an environment in which you can build a player. You may decline to customize your gui. Personally I use the gui stuff to set up parameters for performing. simplistic example ( 383 . KeyDown/KeyUp keyDownAction keyUpAction (only when guied. and then when performing I use no gui. The gui is quite optional. only MIDI controllers and key commands. and respond to midi and keyboard control. MIDI If you set any of these handler functions: onNoteOn onNoteOff onPitchBend onCC then appropriate midi responders will be enabled when the player starts to play and disabled when it stops. and in fact non-screen-staring is one of its primary goals. PlayerPool etc. GUI You can set a custom gui function.gui style and normal SCViews The Interface can be placed on any other windows of any style. only when focus is within the MetaPatch’s views) Interface is great for having no gui at all. This includes if the player is being started/stopped by external mixers. This can use any combination of .

Patch({ arg freq.{ var x.0. }). // at this time not in environment metaPatch. syncFreq.amp=0.gui(layout).rand ).12000. 384 .[100.gui = { arg layout. }) }). var joy. syncFreq.1.1200.0.setUnmappedValue(sl.\exp]).changed. // the same environment is again in place freq. amp ]) }). syncFreq.y_(y).\amp).\exp]). // action button now remembers the environment ! freq. joy = SC2DSlider(layout. ActionButton(layout.setUnmappedValue(sl. amp = KrNumberEditor(0.freq) * amp }.rand ).y.[100. joy.3. // setting the gui m.use({ // use the metaPatch’s environment freq.x_(x).metaPatch. syncFreq = KrNumberEditor(800.Where: Help→Crucial→Instr→Interface m = Interface({ // an environment is in place here freq = KrNumberEditor(400.y ).action_({ arg sl.setUnmappedValue( x = 1.ar(syncFreq."twitch". 100 @ 100) .setUnmappedValue( y = 1. SyncSaw.x).[ freq.syncFreq.

Rect(20.changed. metaPatch.20.Rect(30.30 @ 30.new("other". nil.gui ) You can place them on any window ( w = SCWindow.blue(alpha:0. Klank. then play your midi keyboard ( Instr([\klankperc. w.0.01.1.30.041. }) }).0. g = m.stimeScale ).value).ar(trig).[0. // creating a gui m.fold2(foldAt) 385 .squared.0. g.200)).700.background = Color. ) MIDI handler installed on play takes some seconds to start up.\k2a]. FloatArray[ 0.\exp].Where: Help→Crucial→Instr→Interface EZNumber(layout.0.sfreqScale=1.value_(ez.gui(w.{ arg trig=0."amp".607 ].stimeScale=1.ar( ‘[ FloatArray[ 87.foldAt=0.200)).front. 0.0.4).use({ amp.sfreqOffset=0. 198. }.sfreqOffset.15595 ] ]. K2A.{ arg ez.500.4.165394. sfreqScale.

quantity = quantity.setUnmappedValue(vel / 127.100] ]). pool.midiratio). }). i * (3. }). working on it. 0.\k2a].25). [0.10000]. Patch.0.onNoteOn_({ arg note. foldAt = KrNumberEditor(0. // Create 5 patches. pool = PlayerPool( env: round: a. [ BeatClockPlayer(16).1.{ arg i.[ nil.new([\klankperc. Env.midiratio).poll.select(note % }). i * (3.changed. // the same environment is in place here // foldAt.01.Where: Help→Crucial→Instr→Interface }. Simple CC example 386 .0).01. cycle through them on each midi key Interface({ arg quantity=5.play quantity) ) // fast triggering still trips it up.01.01).01]) ]).100].vel.0. [0.releaseTime: 0.0.asr(0. 1.fill( quantity. [0.[1. a = Array.

freq) * amp }. amp ]) }).\exp]). SyncSaw.}). SyncSaw.1200.syncFreq.}). amp = KrNumberEditor(0.amp=0.3.[100.onCC_({ arg src.value.\exp]).{ }) .\amp).Where: Help→Crucial→Instr→Interface ( Interface({ freq = KrNumberEditor(400.[100.play freq.12000.setUnmappedValue(value/127).}).setUnmappedValue(value/127).num.\exp]). Patch({ arg freq.syncFreq. syncFreq.\exp]).{ if(num == 81.12000. amp. amp = KrNumberEditor(0.[ freq.\amp).1.3. syncFreq = KrNumberEditor(800.setUnmappedValue(value/127). syncFreq. if(num == 80. syncFreq = KrNumberEditor(800. Patch({ arg freq.1200. syncFreq.[100.freq) * amp }.{ if(num == 82. amp ]) 387 .amp=0.1. ) ( Interface({ freq = KrNumberEditor(400.chan.[ freq.[100.ar(syncFreq.ar(syncFreq.

{ arg value. ) ) . syncFreq.0. but the Interface will be handling that CCResponder(80.0.[0.2.25]).0.{ arg value. pchRatio.beatsizeIr.0.onCC_( ResponderArray( // these normally install themselves immediately.envadsr. pchRatio = pchRatio * sample.0.}.bufnumIr.setUnmappedValue(value/127).play freq.setUnmappedValue(value/127).amp=0.numChannels.}. beatStart1 = NumberEditor(0. patch = InstrGateSpawner({ arg sample. gate. pchRatio.dur / tempo). beatStart.8.ar(sample.25]). sample. 1.0.tempo.pchRatioKr.0.0. PlayBuf.}.3.beatStart.setUnmappedValue(value/127).0.doneAction: }.kr(envadsr.Where: Help→Crucial→Instr→Interface }). false). gate = Trig1.0.0) * EnvGen.install: false). 1.\lin. durations = [ 2.8.[ 2 ) 388 . beatStart = beatStart * sample.dur.kr(1. CCResponder(81. beatStart2 = NumberEditor(0.0.\lin.{ arg value. var gate.[0.install: false) ) ( // beat juggler Interface({ argsample.0].install: amp. CCResponder(82.amp.

inf)) // juggle back and forth ].ir input into the synth function pchRatio = IrNumberEditor(1. layout. // get an . // dur uses a Pfunc to ask the delta till the next event Pfunc({ arg igs.25]). // . (igs.[ // a blank sample Sample. // stream of beat durations Pseq( durations. // we are given a FlowView var env.0.\lin. beatStart2 ]. /* but when view actions fire you will be in a different environment so save it here in a variable for use later */ env = currentEnvironment.500@100).2. patch }.ir input Pswitch1([ beatStart1.bdsp. // patterns naturally create an .gui_({ arglayout."Click the sample path (nil) to browse for a sample.Where: Help→Crucial→Instr→Interface sample.delta * 0.inf)). while playing. You can choose new samples even /* the environment from the build function above is available here */ sample.ddsp.startRow.gui(layout. CXLabel(layout. SC2DSlider(layout.").vert({ arg layout.vert returns an SCVLayoutView so we can stack each 2d over its caption layout.9) }).Pseq([0.0.[-2.1].100@100) 389 .new(nil) ]) .

SCStaticText(layout.4.y).100@13).value].setUnmappedValue(sl.100@13).value]). bdsp.part).round(0. beatStart2.25).setUnmappedValue(sl.asString + "=" + }).part. layout.y)).vert({ arg layout.100@120).part).put(0.clip(0.sum.put(1. stride = 2 ** [3.5. }). map it to the spec ranges of the NumberEditors beatStart1. bdsp = SCStaticText(layout.object_("Beat starts:").object_( durations.stride .Where: Help→Crucial→Instr→Interface ."pchRatio:").x).gui(layout). }) .value. beatStart2.object_([ beatStart1. ddsp = SCStaticText(layout.action_({ arg sl.0. env.use({ // set a 0.gui durations).100@100) . pchRatio.x * 3).1 value.25).stride .25. ddsp. durations).object_( [ beatStart1. durations.0 . SC2DSlider(layout. ) <>onCC the control change handler is installed (via CCResponder) when play starts and unistalled when 390 .sum. env.value.6].100@120).object_("beats")..125. durations.asString + "=" + }.changed.at((sl. }) }).action_({ arg sl. beatStart2. SCStaticText(layout.100@13).changed. }.100@13).use({ var stride.asString).object_( durations.sl. part = (stride * (1. CXLabel(layout.asInteger) * 0.

{ [\slider.onCC = { arg src. or a custom class: onCC = KorgMicroKontrolCC( [\slider.value(src.value. { }] ). }]. a CCResponder that responds on a specific number.install: false). }].chan.num. }.chan.1. because the Interface will install and uninstall it when play starts or stops) onCC = CCResponder(num.value).{ [\x.{ [\encoder.Where: Help→Crucial→Instr→Interface play stops. [\y.{ }. [num.0. }].0. <>onPlay <>onStop <>onFree ( Interface({ 391 .{ }].num.1.value]. (note: tell it NOT to install itself.postln. }]. whatever it is will be asked to respond to ’value’ : thing.{ [\encoder. It can be a simple function: interface.

postln. }) . }) .1200. SinOsc.onPlay_({ "playing". amp ]) }) .[0. You can then address them by name. }).Where: Help→Crucial→Instr→Interface freq = KrNumberEditor(400.onFree_({ "freeing".01.4.1.[ freq. 392 .onStop_({ // also on command-.\exp]). amp = KrNumberEditor(0.postln. supply paramaters as you do for Patch and you will get an Interface which will use the gui and midi functions from the InterfaceDef.ar(freq) * amp }. These can be created and stored in the same fashion as Instr and kept in the same folder.\exp]).amp.0.postln.[100.play ) InterfaceDef the function that builds the player is actually an InterfaceDef. "stopping". Patch({ arg freq.

args) ( Instr(\bubbles.run(false).gui. p. var f.ar(SinOsc. LFSaw. p = Patch(\bubbles). 0.kr([8.Where: Help→Crucial→Instr→Patch ID: 148 Patch A Patch connects an Instr function with input arguments to that function.7. 4).2. { arg amp=1. Patch(instr. 3.play. 0. zout = CombN. 0. 24.23]. f = LFSaw.insp.0.midicps.2. ) p. p. // default server will be booted.play. 0.04). will also stop all sounds p. zout * amp }). zout. p. 0. //inspect it p.run(true).ar(f. def written and loaded p. 80)).stop. // command-. 0.4.kr(0. // close the window 393 .

p = Patch(i. LFSaw.04).0.23]. f = LFSaw. 0.amp) }). zout * amp }).7.amp=1.[ q = Patch(\bubbles) ]). var f. 0. 80)). 4).freq + 30]. zout.freq=500.{ arg freq=100. ( Instr(\bubbles. 24.1.kr(0. 0. SinOsc.{ arg audio=0.0.midicps.gui ) a Function 394 .Where: Help→Crucial→Instr→Patch // open it again p.ar([freq.ar(SinOsc.gui ) Instr can be specified as an Instr ( i = Instr("help-Patch". 0.gui. rq) }).4. zout = CombN.3 ]).[ 500. 3.kr([8. RLPF. p.ar(audio. 0.rq=0. p = Patch(\rlpf.2.0. p.ar(f.2. 0. 0. freq. { arg amp=1. Instr(\rlpf.

ControlSpec : KrNumberEditor StaticSpec : NumberEditor (for quantities or max delay times etc. 0. 0.4. varying in output rate or number of channels or internal structure. p.gui ) or by the Instr name // the Instr stores itself when created ( Instr(\bubbles. LFSaw. { arg amp=1. 0.2.Where: Help→Crucial→Instr→Patch ( p = Patch({ arg freq=100.kr([8. 24.freq + 30].[0. SinOsc. 0. var f.midicps. The spec returns this from the defaultControl method.amp=1.7. zout.23].kr(0.04). zout * amp }).ar(SinOsc.0.4] ). 4). p.gui ) Patch can be easily saved to disk.ar([freq. 3. // the patch retrieves it p = Patch(\bubbles.0. 80)).2. expanding the number of output channels or .3 ]).[ 500. 0. 0.) EnvSpec : EnvEditor 395 . and can make use of a large library of Instr functions.0. Automatic Input Creation For any nil arguments. a default control will be created. zout = CombN.amp) }.ar(f. An Instr can produce many different possible SynthDefs. f = LFSaw. 0.

simple ones. buildPatch.[ arg instrName. Setting their values will control the playing synth.specAt(1). Most simple synth inputs (ControlSpec) will end up being KrNumberEditors.specAt(0).at(instrName). you can even keep your factories themselves in Instrument libraries: Instr(\joysticker. it will make default ones.1. value) I recommend experimenting with factory methods to create your patches.1. var i. ]) }. supplying them with inputs useful for what you are working on. If you use a certain physical controller or wacom : buildPatch var i. i = Instr.[ { i. 396 .kr(0. i = Instr.Where: Help→Crucial→Instr→Patch SampleSpec : Sample see the implementations of defaultControl This gives the impression that Patch is "an automatic gui for an Instr / SynthDef".map( JoyAxis. aPatch.map( JoyAxis. but the real power of Patch is to supply functions with complex and varied inputs. = { arg instrName. Sitting there with 5 sliders on a 1 dimensional Instrument isn’t really the height of synthesis.value( \boingboing ). Patch(instrName.kr(0. { i.set( index. If you do not supply arguments.axis:5) ) }.axis:5) ) }.at(instrName).

zout = CombN. 80)).axis:5) ) }. LFSaw.axis:5) ) }. 0. patch = Instr(\joysticker). 0.kr([8.04). f = LFSaw.7. Patch inside Patch ( // lets collect the cast. this Instr is not used for audio. you can query the argument name and the spec.specAt(0).ar(f.map( JoyAxis. Keep files in databases. its just used to build and return a Patch You could choose different controllers for different common inputs.2.midicps. freq.1.{ arg audio=0. other saved patches or randomly chosen net radio feeds. Instr(\bubbles.[ q = Patch(\bubbles) 397 .ar(SinOsc.1. 0.rq=0. var f. zout.value( \simple ).kr(0. 4).. zout * amp }). You could flip coins and choose from soundfiles. { arg amp=1.map( JoyAxis.1.[ { i. rq) }). // put bubbles into the filter p = Patch(\rlpf.kr(0. ]) }). 3.freq=500.4.0. RLPF.2.specAt(1). 24. 0. // note that the same function will work as stereo or mono // depending on what gets put into it Instr(\rlpf.23]. 0.ar(audio. 0. audio in.kr(0.Where: Help→Crucial→Instr→Patch Patch(instrName. load other Patches or soundfiles from disk.. { i.

stop. but the filter p is still reading from its old bus q.play. // stopping p now still stops q because it is still a child of p p.play. // allocates new everything p.Where: Help→Crucial→Instr→Patch ]). // additional play // does not start an additional process p.play.play. // stop q. // should still have 9 ugens playing // sent the play message. // replaying the whole structures p.stop.play. // stops the parent and the child q p. ) // watch the ugen count in the default server window // and also the error window results p.stop. q defaults to play out of the main outputs // not through the filter p q. 398 .

’moto-rev’].5)}.1].kr(1.insp. PatchIn classes Fixed Arguments Floats and other scalar values including Envelopes. RLPF. {arg upDown=0.{ arg lfo=0.2 ]).5)} // upDown 0 or less ==> pitch goes down 399 .[ 0.kr(0. but not to the SynthDef or the Synth.gui. 10. 0. This can be used to select from different kinds of filters or to .ar(LFPulse.ar(SinOsc.0. 0.rq=0.freq=1000. var line. freq.1). They are not modulateable. q = Patch([\jmcExamples.2.0. [0.1. rq). if (upDown>0. q. }). {line = Line.4). // upDown>0 ==> pitch goes up {line = Line.’moto-rev’].kr(lfo. are transparently dealt with by Patch. These items are passed to the Instr function. q.clip2(0. Instr(\upOrDown. 21). ( // fixing arguments Instr([\jmcExamples.1.insp. ) You can design Instr to take parameters that are used only in the building of the SynthDef.Where: Help→Crucial→Instr→Patch // note the AudioPatchOut and the inputs: p.

c = Bus.play The upDown param acts as a switch between different synth def architectures.new.0.ffreq) }.ar(in.\exp]) ]).numChannels) LPF.ar(440*line.[ StaticIntegerSpec(0. p=Patch({ arg in. // play something onto this bus in a group before that of the filter y = Patch({ Saw.ar(400) * 0.2).play(group: a.index. Patch(\upOrDown.after(a). 400 .play(group: b). Busses ( s. KrNumberEditor(3000.Where: Help→Crucial→Instr→Patch ). // the Bus is passed in as In.1) ]).audio(s.ffreq.0) without the StaticIntegerSpec making it clear that its a static integer.8000.bus.ar(bus.boot.0.1 }). [ 0]). SinOsc. If your Instr library is well designed you can acheive very sophisticated sound structures with automatic optimizations and code reuse. }.ar(500) * 0.[ c.1 }). bus: c ). Note that the Patch would assume upDown to be a modulatable control input (with a default of 0. b = Group.play(group: a.[200.1). bus: c ). z = Patch({ Saw. a = Group.

ar(in. // no index.new. y. the bus is yet to be allocated KrNumberEditor(3000.stop.after(a).\exp]) ]).boot.play(group: b). y = Patch({ arg in.2).ffreq) }.play //command-.nil. bus: c ) Mapping values you can use a spec to map a signal : 401 .401]) * 0. // a proxy. a = Group.play(group: a.insp // play onto this bus in a group before that of the filter z = Patch({ Saw.Where: Help→Crucial→Instr→Patch z.ffreq.ar([400. // now that the patch has played. ) // you can make the bus play to a main audio output c.[ c. b = Group. not yet allocated c = Bus(\audio. the bus allocated itself c. LPF.stop.8000. to stop all ( s.[200.1 }).

range(0.play ) 402 .1) } ) ]).ar( spec. SinOsc. Patch({ arg freq.1) }) ).1) ) }. Patch({ arg freq.[ spec.18000.\exp]. SinOsc.18000.1).play ) you can use that as an input to a patch: ( var spec.\exp].ar(freq) }.ar(freq) }.map( ) SinOsc.map( Patch({ SinOsc.play ) or map another player’s output and then use that as an input to a patch : ( var spec.kr(0.asSpec.asSpec.18000. spec = [ 100.1).range(0.\exp].[ spec.1).kr(0.Where: Help→Crucial→Instr→Patch ( var spec. spec = [ 100.debug("i am a") ]). spec = [ 100.map( { SinOsc.range(0.asSpec. { SinOsc.kr(0.

play(SystemClock) 403 .1). // //c = Bus.wait 0.0.25). 2) c).0.0) //}). // }) //}). a should be playing already and b should just patch it in each time.1).[0.kr(Env([0. // 100.kr(1.05].gate.prepareForPlay(s).05.25.\welch. // gate = Trig1.spawn(atTime: 0. Spawning still wrong. that is to say if you do math on functions you get another function.ar(tone. (// // //a = Patch({ // SinOsc.doneAction: //}[ // c.0.1.audio.play(bus: // //b = Patch({ arg tone.map is taking the player (which is a kind of function : a potential piece of music once it is valued ) and creating a BinaryOpFunction out of it. // tone = In.0. // //b.0]. //a. // var gate.do({ // // b. // // //Routine({ // 1.Where: Help→Crucial→Instr→Patch so spec.ar(800. // tone * EnvGen.0.wait.index //]).1).

Where: Help→Crucial→Instr→Patch // ) 404 .

though the stream may return any kind of envelope.linen. StreamSpec( [ 0.01 and 8. though usually you will be more intereseted in using Patterns as inputs.0. The most common use is for InstrSpawner and InstrGateSpawner.ir rate input to the synth function. An IrNumberControl or a Pattern (any object that returns a rate of \stream) will result in the creation of an .Where: Help→Crucial→Instr→StreamSpec ID: 149 StreamSpec superclass: HasItemSpec StreamSpec( specOfItemsReturnedInTheStream) a StreamSpec specifies an input that will be used in a stream or pattern. the default envelope is an Env.\exp ] ) a stream of values between 0. Then on each spawning.0 any control should use an exponential fader StreamSpec( EnvSpec(Env.linen) ) a stream of envelopes. the synth is created and on that .ir rate input is passed in the next value of the stream. 8.01. 405 . The default control is an IrNumberControl.

6.6 Introspection 406 .

You can click to open the class file or the test file. ’!==’ -> { var a. a = Object.test. Any class can find and run its test: Float. TestCases for each class can be stored in "TestingAndToDo/Tests" as Classname.rtf (note that if you check "hide extension" it will just say Classname.test. 407 . a = Object.test). this uses a simple instance. a == a // test passes if it returns true } ). ’==’ -> { var a.runAll.new. If not found. TestCase(Object. a !== a // a deliberate failure } ). An individual test case that you are working on can be run: TestCase(Object. a message is posted.new. All classes can try and run their tests if they have them: TestCase.run.Where: Help→Crucial→Introspection→TestCase ID: 150 TestCase Unit Testing Rather than write full classes that test each method of your class.

Where: Help→Crucial→Introspection→TestCase 408 .

6.7 Miscellanea 409 .

as time goes on. start them. InstrSpawner. Envs (envelopes). and can be 410 . It should not be an all or nothing commitment. Although there is a convienient system for instantly making guis for instrument functions. you can stop them. then you are approaching it wrong. other players. If you perceive it as that.insp . They handle all the messy details of loading their resources to the server. record them and save them to disk. Interface specify a player and interface elements and how they are connected. Try out one or two things and work them into what you are normally doing. The inputs are taken as streams and interated. introspection tools . learn some more objects. This patches inputs into a function. Patch The most common and well known Player. A Patch plays continously and infinitely (until you stop it).gui It is not advisable to use "the whole library"–don’t think of it as a single entity.Where: Help→Crucial→CRUCIAL-LIBRARY ID: 151 CrucialLibrary Higher level interfaces for managing musical objects. and getting them off again when you are done.insp class browser AbstractPlayer. AbstractPlayer This encapsulates things that play. the purpose of the library is not "a gui system". Inputs can be floats. allows custom gui and midi functions. Samples. It is flexible. InstrGateSpawner a Patch that plays successive events.a debugging tool "any object". or SFP (sound file player).

command-h to open help file ] Instr Patch InstrSpawner InstrGateSpawner Interface gui SynthConsole NumberEditor AbstractPlayer StreamKrDur Tempo TempoBus TempoPlayer BeatClockPlayer Stream2Trig PlayerEfxFunc PlayerPool 411 .Where: Help→Crucial→CRUCIAL-LIBRARY used in any coding situation. frequent updates are maintained through CVS. [ double click to select. INSTALLATION crucial is distributed with SC and should not needed further installation.

honest. i rock the house. buy my album 412 .Where: Help→Crucial→CRUCIAL-LIBRARY What you can do for Me: send me a copy of any record/CD you put out using this stuff write Instr and offer them to me or to everyone Write Usable Classes and share them with me suggest or implement improvements build things i wouldn’t build identify issues report bugs fix bugs hook me up with gigs.

This class initializes some lightweight resources relevant to crucial library and loads some useful utilities into the Library (a shared dictionary of reusable functions).sc) will get overwritten by CVS updates from time to time. see [CRUCIAL-LIBRARY].menu. In Main-startUp you can set: // you can move all of your documents to your home directory Document. as this file (Crucial. see Document Instr.dir = " /Documents/SuperCollider/Instr/".menu. Crucial. see Instr // this would allow your sounds to be shared by other applications Sample. } You should set personal preferences in Main-startUp.Where: Help→Crucial→Crucial ID: 152 Crucial superclass: Object If you are looking for the intro to the library.wav to there for use in helpfiles ! 413 . see Sample // copy a11wlk01.dir = " /Documents/SuperCollider/".soundsDir = " /Sounds/". You can put this in Main if you like: run { // called by command-R Crucial.

creates some useful common Specs installs some general use Library functions. see [Library] 414 . root paths.Where: Help→Crucial→Crucial everything is called in *initClass preferences: Colors.

6.8 Patching 415 .

They are used to make connections to other Players. PatchIn objects hold NodeControl objects that enable communication to one input of a Node (Synths and Groups). PatchOut objects hold either Bus objects (for audio and control) or sources (for control and scalar).connectTo(aPatchOut) aPatchOut. PatchOuts may be connected to multiple PatchIns.Where: Help→Crucial→Patching→Patching ID: 153 Patching PatchIn AudioPatchIn ControlPatchIn ScalarPatchIn PatchOut ControlPatchOut AudioPatchOut ScalarPatchOut These objects hold information about a Player’s inputs and outputs.connectTo(aPatchIn) connect the input on the node to the output of the bus or source. sources are client side objects that produce float values to send to the inputs of Nodes. aPatchIn. Both PatchIn and PatchOut remember who they are connectedTo. Possible sources are gui objects like sliders or Patterns and other automatons.value with a Float can be a source for a ScalarPatchOut. Bus objects hold the information about the Bus that the Player is playing onto. and to manage that connection and all subsequent repatching or disconnections. play(patchIn) server 416 . either for setting the value or mapping the input to read from a Bus. Anything that can respond to .

where it will be created patchIn also hold source ?. search for synth examples: drag output of player to some input patchOut. else when it plays it will get the value if player is not playing anywhere else if input is reading from something else insert mixer drag filter to player if player is not playing anywhere else node after same buss for out filter reads from that buss this is a kind of player if player is playing to another filter 417 .Where: Help→Crucial→Patching→Patching plays on top group at head group plays at group of head integer default server. audio output number they should be even gui-able. a drag drop maybe even a player makes ins and outs when created prepare(group) sets the patchOut group.connectTo(patchIn) sets nodeControl if playing.

Where: Help→Crucial→Patching→Patching remove other node after same buss for out filter reads from that buss 418 .

new.02 ] ).new ]).[ PlayerInputProxy. 1). -0.ffreq. 100.ffreq) }. it holds the place. inf). StreamKrDur. notes: /* XFadeEfxFunc.ar(audio.new(PbrownGUI. Patch. RLPF. 8. an input to an effect. [ PlayerInputProxy. a potential controller/interface input PlayerInputProxy(spec) p = Patch({ arg audio. p. it is silent.new([ ’efxFilters3’. ’combN’].new("Patches/breaks/felaoopkunnzz". 419 . if the patch is played.play other classes can detect these inputs and patch into them. 1000.Where: Help→Crucial→Patching→PlayerInputProxy ID: 154 PlayerInputProxy represents an audio or control input for a player that is to be dynamically patchable at runtime. eg.new(600.

1.new. and sets it on the PlayerInputProxy so pip can save blank if pip is played (silent). it has defaults and would play it as mono PlayerInputProxy. it would have to respawn 420 .Where: Help→Crucial→Patching→PlayerInputProxy 0.5. 1) */ the XFadeEfxFunc would know numChannels and rate of input.play if the channels changes while playing.

9 Players 421 .6.

1 Miscellanea 422 .

2 SFP 423 .

6.10 Sample 424 .

55]. 0.ar(LFPulse.kr([3.jmc // mouse x controls discrete pitch in dorian mode Patch({ arg scale. 1.midicps.15).Where: Help→Crucial→Sample→ArrayBuffer ID: 155 ArrayBuffer superclass: BufferProxy Passes an array into a Patch for use in UGens which need an array supplied as a buffer index. 12.new( array ) ( // modal space . 72 ) + LFNoise1.15). 0. ArrayBuffer. 0.ar( ( DegreeToKey. var mix. mix = // lead tone SinOsc. MouseX.1) // convert midi notes to hertz // mouse indexes into scale // 12 notes per octave // mul = 1 // offset by 72 notes // drone 5ths + RLPF. 425 .kr(0.midicps.bufnumIr.3]. 0. If saved as a compile string to disk.04) // add some low freq stereo detuning ).kr( scale. saves the array with it.ar([48.

mix) }. 9. 2.1. 0. 5. 10]) ]).31. 2.31.Where: Help→Crucial→Sample→ArrayBuffer SinOsc.1).gui ) 426 . 7. 10. 1. 3.1. 0.kr(0.ar(mix.[ ArrayBuffer(FloatArray[0. 72). 0. 0. // add some 70’s euro-space-rock echo CombN.midicps. 0.

trig. See Sample (a subclass of BufferProxy) if you need to load soundfiles.2) \stereo. suitable for recording.gui ) Make sure your audio input and buffer numChannels match. run: offset = start * buffer. // == AudioSpec.buffer. ( Instr([\recordPlay.\linear].numChannels. [-5. pitch = 1. RecordBuf.Where: Help→Crucial→Sample→BufferProxy ID: 156 BufferProxy Allocates and supplies a buffer for use in Patches. 427 . \unipolar ]).new(2).#[ \buffer. this is the DEFAULT that will be used if you DON’T specify an input to a Patch. }.25.\JemAudioIn].offset. The buffer is unfilled.bufFramesKr. trigRate = 0.[ BufferProxy(44100 * 4. offOn. Patch([\recordPlay.\JemAudioIn].ar(buffer. input. trig = Impulse.5.10. you can place a BufferProxySpec and specify any default size you would like.kr(trigRate).trig. start = 0. // == BufferProxySpec(44100.\linear]. // 4 secs in stereo AudioInPlayer.loop: 1). \unipolar. Usually you pass in a BufferProxy to the patch that is the size that you wish.new ]).offOn = 1.5.bufnumIr. [0.pitch. PlayBuf.ar(input.buffer.trigger: trig). var offset.bufnumIr. an argName of spec symbol of \buffer will create a BufferProxySpec with the default 44100 frames (1 second). 2). {arg buffer.

Where: Help→Crucial→Sample→BufferProxy 428 .

/Library/Sounds/ or /Sounds/ ).bufnumIr. PlayBuf. and even beat synchronizing of a small sound file. 1.bufRateScaleKr. ( p = Patch({ argsample.soundsDir to the directory of your choice (eg. Sample. You can set the Sample.0. p.wav") ]). sample. 1.gui. 0.ar(sample. but it holds all the intelligence to allow other things to play it very easily.[ Sample("a11wlk01. ) Notice that the path to the sample is relative to the sounds/ directory. not to SuperCollider’s own directory. sample. It will not clear the copyright.Where: Help→Crucial→Sample→Sample ID: 157 Sample superclass: AbstractSample This class can be used as an argument to a Patch. measuring.0) }.new(soundFilePath. allocating.numChannels.wav to your own sounds directory so you can still play examples.0. Copy a11wlk01. 429 . It will take care of all the troubles of loading.tempo) It will not play by itself.

sampleRate a float of the current sample’s sample rate. this will get the dynamic bufferID of your Sample object. sampleRateIr a ir rate signal that will NOT change if you load a different sample into the buffer. use when you know the sample will not change. embedded into SynthDef as a constant. and will be slightly more efficient. or if you know that all samples are the same sampleRate anyway.Where: Help→Crucial→Sample→Sample Within the Instr function you use these methods on your Sample object bufnumIr at the start of the synth.even while playing. Multiple synths may use the same basic sample synthDef for many voices with no need to compile new SynthDefs and send to the server. bufRateScaleKr the nominal pitchRatio value needed to play at the original pitch bufRateScaleIr the nominal pitchRatio value needed to play at the original pitch. bufFramesKr a kr rate signal with the number of frames of the current sample bufFramesIr an ir rate signal with the number of frames of the sample bufSamplesKr a kr rate signal with the number of samples of the current sample bufSamplesIr an ir rate signal with the number of samples of the current sample duration duration in seconds of current sample. bufDurKr 430 . embedded into the SynthDef as a constant. sampleRateKr a kr rate signal that will change if you load a different sample into the buffer. the def will be resuable for all samples of that sample rate. will NOT change if you load a different sample into the buffer. this Instr will reuse SynthDefs where possible.

Then start play.pchRatio=0. p = Patch("help-Sample". and you can browse for more and change it while playing.[ Sample("pick a stereo sample. PlayBuf.0. Click on the name of the sample (in black font) and browse for a stereo sample. p. }).") ]). bufChannelsKr number of channels of the current sample. the SynthDef will still be reusable for all samples of the same numChannels. ( Instr("help-Sample". 1.gui ) The def name was : help-SampleO8NEut 431 .50. sample. number of channels of the current sample.0)...Where: Help→Crucial→Sample→Sample duration in seconds bufDurIr duration in seconds numChannels integer. you cannot use this to modulate a PlayBuf.numChannels. // finds the buffer number when the synth starts sample.bufnumIr.1. you cannot use this to modulate a PlayBuf. bufChannelsIr number of channels of the sample.ar(sample. You can swap the samples while playing.{ arg sample.bufRateScaleKr * pchRatio. this will be embedded into the SynthDef as a constant.0.0.

and this will fully restore the complete sound. // edit controls on the gui p. ’Sample’ ].\Sample]. [ Sample. // finds the buffer number when the synth starts sample. PlayBuf.new("a11wlk01.bufFramesKr.6347258775994).wav".0. 1. 0.0). start * sample.pchRatio=1. // loop }).17441860465116 ] ).0. ) Patch object: ( p = Patch([\help.Where: Help→Crucial→Sample→Sample You can build up a library of Instr functions and exploit them with Patch. [ Sample("a11wlk01. 1.start=0.gui ) save it.play ) BeatLock 432 .\Sample].wav") ]). 0.bufnumIr.new( [ ’help’.sampleRateKr / 44100 * pchRatio.ar(sample. ( Instr([\help.0.{ arg sample. 1. sample.46511627906977.numChannels. ( Patch.

[ \sample. }. [ Sample("a11wlk01. }. p = Patch([\help.[ \sample.0.reciprocal. PlayBuf.bufnumIr.\Sample]. // move the tempo slider p.ar( sample.gui ) This is roughly equivalent to this: ( //beatlock Instr([\help.numChannels.tempo.0.\Sample].1. sample.numChannels.0).0. sample.0.0).pchRatioKr. 1.\Sample].wav") ]).ar( sample.sampleRateIr / 44100 * tempo * sample.{ arg sample. sample. \tempo ]).tempo. PlayBuf. but what the monkey thinks the music in the sample is will remain fixed in the SynthDef. 433 . ( //beatlock Instr([\help. Tempo’s tempo can vary.1.0.Where: Help→Crucial→Sample→Sample This will embed the sample’s tempo into the SynthDef as a constant. 1.0.{ arg sample.bufnumIr. sample.

Where: Help→Crucial→Sample→Sample \tempo ]).wav").new ]). p = Patch([\help.size .\Sample]. [ Sample("a11wlk01.gui ) soundFilePath end signal.1 the last indexable position in the signal duration totalMemory numFrames * numChannels The following methods are relevant if the sample is some kind of loop. TempoPlayer. tempo beats per second the original recording is regarded to have. // move the tempo slider p. beats number of beats beatsize the number of samples per beat 434 .

0 / q).1).geom(8.pchRatioKr.series(q.2 ** -5.kr(GetTempo.end * 0. sample.numChannels) }. 435 .sample.0.sampleRate.0.0.sample.scramble.env. var pchRatioKr.ar(sample.kr * sample.rand.rrand(1.end).topGui 2.32). Sample(":Sounds:floating_1").gate.inf.0). rrand(0. [ Stream2Trig( 1.5). Pseq(Array.Where: Help→Crucial→Sample→Sample /*** ( // hit load and select a rhythm // will stay beat locked and the beat will flow despite the cutting q = rrand(8.5.rrand(3.sample.asr(release:0. StreamKrDur( Pslide(Array. Env.end * 0. ReTrigger2.pchRatio.env.pchRatioKr * pchRatio.4.6)). pchRatioKr = sample.sample.5).inf) ) ( // will stay beat locked and the beat will flow despite the cutting q = rrand(8.0.start.start.5) ) ]).ar({ PlayBuf.poll.beats.0. sample. start = LFSaw. ). }.reciprocal.signal.125.32). Patch({arg gate.

0.5). p = PlayBuf.sample. Sample(":Sounds:floating_1").0.env.perc(release:0.kr(GetTempo.5).start. var p.rand.Where: Help→Crucial→Sample→Sample Patch({arg gate.1.2).sample.0.inf) ) ( Patch({arg gate.0.ar(sample. sample.ar(p.0.env.{ 2 ** rrand(-5.sample.1.5)).env.5.env.geom(8.sampleRate.pchRatioKr.2 ** -5.signal. Env.gate.signal.0) ) ]). [ Stream2Trig(‘([1.0. ReTrigger2.asr(release:0.0. [ Stream2Trig( 1.pchRatioKr * pchRatio. Enveloper2.sample.pchRatio.ar({ PlayBuf.1.sample.1).0. Env.sample.topGui ) ( 436 . StreamKrDur( Pslide(Array. sample. pchRatioKr = sample.end).0 / q).sampleRate.numChannels) }.0.fill(8.0). ).reciprocal. start = LFSaw. rrand(0.125.scramble.-1) }))).‘(Array.beats.-2.rrand(3.numChannels) }.end * 0.rrand(2.end).poll.topGui 2.2.1]).inf.sample.series(q.ar(sample. Pseq(Array.gate. var pchRatioKr.end * 0.sample.pchRatioKr.sample.kr * sample. }.scramble. Sample(":Sounds:floating_1") ]).start.

s.topGui ) ***/ 437 . }.signal.sample.25) }).2.{ 2 ** rrand(-7.{[1.e.Pfunc({ 2 ** rrand(-4.rand.2)})) ]).rand.9000.gate.sample.numChannels) }.s.pchRatioKr.rand.‘(Array.4.sampleRate.env. p = sample.125.0. Env.0.fill(128.5000.0].choose})).kr(0. s = startBeat * sample. var p. [ Stream2Trig(‘(Array.0.sample. StreamKrDur( Pfunc({ s.round(0.-1) }))).beats. e = s + LFNoise1.startBeat.perc(release:3.ar({ PlayBuf.Where: Help→Crucial→Sample→Sample Patch({arg gate.0).p.s. s = Sample(":Sounds:floating_1"). Enveloper.beatsize.0).env.fill(128.e).ar(sample.

11 Scheduling 438 .6.

execute the following several times.ar( tempo ) }. ( Patch({ arg tempo. Impulse.play(atTime: 4.ar( tempo ) }.[ TempoPlayer. they will each start at the start of the next bar.new ]).[ TempoPlayer.Where: Help→Crucial→Scheduling→Attime ID: 158 atTime this is an argument for many methods. it will be scheded in sclang and only sent close to the time // start in 4.new 439 .5 seconds ( Patch({ arg tempo. Impulse.5) ) Integer : according to TempoClock on the next 1 bar 2 half bar 4 beat 8 8th note 16 16th note etc. it specifies when the bundle or event should occur Nil : immediately Float : that many seconds from now if time is greater than server latency.

. Impulse.rawSeconds + 10.play(atTime: d) ) 440 .localtime or Date.play(atTime: 1) ) Date : at that time on that date if in the future Date has to have raw seconds set to work ! use Date.getDate to create a Date object with the raw seconds set.month . you can’t make a Date..) and expect that to work.[ TempoPlayer. note: a getRawSeconds primitive would solve this problem.ar( tempo ) }.rawSeconds = d.Where: Help→Crucial→Scheduling→Attime ]). ( d = Date. Patch({ arg tempo. and then make relative changes to that date.getDate. // 10 seconds in the future d. ie.new(year..new ]).

xsched or xqsched will be cancelled.tsched(seconds.new. this is incredibly useful in situations where several messages 441 .function) exclusive time based schedule any previous messages scheduling using xtsched. You may also create individual instances that maintain their own scheduling queues. All of these methods exist as both class (the default global scheduler) BeatSched.function) The default clock used is the SystemClock. and time epochs. and is used for all beat <-> second calculations. absolute seconds or absolute beats. clearing the queue will affect everybody. This class uses TempoClock for scheduling.function) time based scheduling delta specified in seconds xtsched( seconds. If using BeatSched instances you can clear the queue. tempii. and has some overlap of capabilities with that. or you can use a specific TempoClock instance. beatSched = BeatSched. There is a default global BeatSched that can be addressed through class methods. relative beats. tsched(seconds. The TempoClock class is used to specify what the tempo is. It uses the SystemClock and the default global TempoClock.function) and instance methods (a specific scheduler). but you may also specify to use the AppClock.Where: Help→Crucial→Scheduling→BeatSched ID: 159 BeatSched A beat capable function scheduler Functions can be scheduled for precise execution using relative seconds. beatSched.tsched(seconds. The default global TempoClock object is used. only affecting your own events. If using the global BeatSched class.

or immediately if you happen to be exactly on a division. you then switch to a different sequence.0 means on the downbeat of a 4/4 bar ). changing his mind about which sound to play next.function) delta specified in beats xsched(beats.function) will happen at the time specified in seconds schedAbs(beat. and the server would choke trying to execute them all. this is also used to start a "song": zero the beat. you don’t have to worry about it.function) exclusive quantized beat based scheduling tschedAbs(time. xblock blocks any and all pending x-scheduled messages.function) will happen at the beat specified. xqsched(quantize. time get the scheduler’s time time_(seconds) set the scheduler’s time beat get the scheduler’s current beat beat_(beat) set the scheduler’s current beat. example: a monkey is hitting many buttons. you don’t want the note that was scheduled from the previous sequence to happen. all using xsched. this would result in many messages being stacked up all at the same time.function) exclusive beat based scheduling qsched(quantize. and all absolute times previously scheduled events will be unpredictable 442 . this is a kind of enforced monophony.Where: Help→Crucial→Scheduling→BeatSched might be sent and you only want the last one to be used as the final answer. using one of the x-methods. sched(beats. the old notes will be cleared when new ones are scheduled.function) will happen at the next even division ( 4. another example: a sequence plays successive notes.

0.default.postln.Where: Help→Crucial→Scheduling→BeatSched deltaTillNext(quantizeDivision) returns the number of seconds untiil the next quantizeDivision.new.time = 0.{ "2 seconds absolute time". }).qsched(4. b.time = 0.tempo = 1.0.{ "hello".beat.0. b. b. TempoClock. b.0 means the next 4 bar cycle 0.25 means the next 16th note clear clear all scheduled events.tschedAbs(4. b.0 means the next even bar 16. b = BeatSched.qsched(4.postln.0. }).{ "4 seconds absolute time". }).0.postln. 443 .0.time. b.postln.tempo = 2. b.postln. b.tschedAbs(2. // reset the time b.beat.time. remember to execute groups of code lines together.{ "hello". TempoClock. }).beat. 4. b. In the examples.postln. // since the app started b.default.

play(d). due to rounding errors in the several math ops that have happened.tdeltaTillNext(4.tempo = 120 / 60. 4.0.do({ var t.default.432346276 + 1. }).432346276 ] 1.xsched(2. 5207.xsched(4. { "4 beats later".00092713799949706 its appears to be slightly ahead of schedule. 5206.5676537239997 that would be 5206. 444 .0.Where: Help→Crucial→Scheduling→BeatSched b.wait.432346276 we ask for deltaTillNext 4 [ 5204.999072862 ] 0.00092713799949706 as far as BeatSched is concerned.0). ) at 5206. t = BeatSched. A little rounding error ( TempoClock.postln }).5676537239997 // at 5208 5208 // but when the scheded event comes due: [ 5204. so the right answer is 0.postln. SystemClock. d = Routine({ 20. // cancels previous xsched b. t. t.global. 4. { "2 beats later".0. }).postln }).

postln.wait. }). mostly you just want to know when the next even beat is so you can get your groove on. 445 . OSCSched.bpm_(120). you will suffer from rounding errors. }).BeatSched.global.postln. mostly you would never set up a loop like this.tdeltaTillNext(4.. d = Routine({ "wait for the downbeat. [i. 32.Where: Help→Crucial→Scheduling→BeatSched but if you try to loop like this.do({ arg i. Tempo.beats2secs(1.0). Tempo.0).wait.beat].".play(d). SystemClock..

You may also create individual instances that maintain their own scheduling queues. A default global Tempo object is used. relative beats. They are sent to the server just before execution. This could be used to show a change in the gui or to update some setting on a client side object. Bundles can be easily cancelled up until the time they are sent to the server.tsched(seconds. oscSched. and time epochs.Where: Help→Crucial→Scheduling→OSCSched ID: 160 OSCSched A scheduler for sending OSC bundles to servers. tempii. absolute seconds or absolute beats. and then actually sent to the server in a time stamped bundle.clientSideFunction) and instance methods (a specific scheduler). with exact simultaneous execution times. The bundle is kept on the client until the last possible moment. just before it is due to be executed. The Tempo class is used to specify what the tempo is.server. All of these methods exist as both class (the default global scheduler) OSCSched.bundle. and is used for all beat <-> second calculations. The default clock used is the SystemClock. or you can create a specific Tempo instance if y’all got your own separate grooves. but you may also specify to use the AppClock.bundle. oscSched = OSCSched. An optional clientSideFunction can also be supplied that will be evaluated on the client at the exact time as the OSC bundle is scheduled to happen.clientSideFunction) 446 . Bundles can be scheduled for precise execution using relative seconds.server. There is a default global OSCSched that can be addressed through class methods.new. Bundles can be scheduled on multiple servers. It uses the SystemClock and the default global Tempo.tsched(seconds.

example: a monkey is hitting many buttons. another example: a sequence plays successive notes. scheduling each one when it plays the previous one. using one of the x-methods. and the server would choke trying to execute them all.clientSideFunction) will happen at the time specified in seconds schedAbs(beat. this would result in many bundles being stacked up all at the same time.server. you then switch to a different sequence.clientSideFunction) delta specified in beats xsched(beats.server.bundle.server.server.0 means on the downbeat of a 4/4 bar ).clientSideFunction) exclusive beat based scheduling qsched(quantize.server.bundle.bundle.bundle. xqsched(quantize.clientSideFunction) will happen at the next even division ( 4. xsched or xqsched will be cancelled.server.Where: Help→Crucial→Scheduling→OSCSched tsched(seconds. or immediately if you happen to be exactly on a division. you don’t have to worry about it.bundle. you don’t want the note that was scheduled from the previous sequence to happen.clientSideFunction) exclusive time based schedule any previous bundles scheduled using xtsched.bundle. this is incredibly useful in situations where several bundles might be sent and you only want the last one to be used as the final answer.bundle. changing his mind about which sound to play next. sched(beats.clientSideFunction) will happen at the beat specified.bundle. this uses TempoClock for scheduling xblock blocks any and all pending x-scheduled bundles. time get the scheduler’s time time_(seconds) 447 .clientSideFunction) time based scheduling delta specified in seconds xtsched( seconds.server. it will just be cancelled.clientSideFunction) exclusive quantized beat based scheduling tschedAbs(time. so this forces a kind of monophony of bundles.server.

use the beat based scheduling methods. ( SynthDef("bubbles". and all absolute times previously scheduled events will be unpredictable deltaTillNext(quantizeDivision) returns the number of seconds untiil the next quantizeDivision.0 means the next even bar 16.midicps. repeatedly scheduling its next note at the time of playing the current one. To switch the pattern with another or abruptly start it over. 448 .boot. 4. simply do so: if you used xsched.local. 0. All of the x-methods establish a block such that a subsequent schedule using another xmethod will cause the previous one to be cancelled. zout. s. and change your mind before the event you have triggered comes due. For scheduling.kr(0. 0. not tested recently load all of these for use in all following examples s = Server. LFSaw. you will wish to create a private instance of OSCSched when using this technique.kr([8. clear clear all scheduled events.23]. Another example is a pattern that returns delta beat values. This is particularily useful when you are controlling something from a gui or process.0 means the next 4 bar cycle 0. 80)). then the previously scheduled event will be cancelled. this is also used to start a "song": zero the beat. In most cases. 24.Where: Help→Crucial→Scheduling→OSCSched set the scheduler’s time beat get the scheduler’s current beat beat_(beat) set the scheduler’s current beat.4.25 means the next 16th note This value is only correct so long as you don’t change the tempo. { var f.7. 3. warning: older examples. f = LFSaw.

"bubbles".04). c = OSCSched.sched(2. }). 0.0 beats c. // number of beats since SC itself started up c.postln. the scheduler’s time is number of seconds // since SC itself started up c.send(s).beat = 0. Out. // how many of those beats since time started c.bpm = 96.postln. 0 ].beat.2. zout).tempo. // defaults to 1.beat. // how beats since time started c.postln. 449 .postln.postln.i.0. ) // unitialised. o = [ ’/n_free’.time. 0. 1. 1002 ].ar(SinOsc. 0.0.0 beats per second Tempo.s. 1002. // set the default global Tempo Tempo.Where: Help→Crucial→Scheduling→OSCSched zout = CombN.2.beat. i = [ ’/s_new’.{ "starting". 0.ar(f. 4).new. // start in 2. // tell the scheduler what beat we think it is c.postln. }).ar(0.

s. // note the floating point imprecision }).s.i.postln.{ "4. Absolute Beat / Time scheduling c.s.0 seconds c.tsched(4. }).s.s.0". // out c.xsched(4.schedAbs(39. // but first in c.schedAbs(36.beat = 32.o. }).schedAbs(43.s. // out c. // we are starting at beat 32 c. }).0.0.schedAbs(41.0.o.i).{ "this will never happen.i).0.i.0.beat.0.schedAbs(46.0. ( c.0.s.schedAbs(40.postln.o). ) Exclusive ( c.0.0.postln.i.clear.{ c.{ c.o).schedAbs(42. its in the past".Where: Help→Crucial→Scheduling→OSCSched // free the synth on the next even bar c. 450 .0.s. }).o).qsched(4. // start in 4.{ "starting".postln.s. c.s. // in c.

o).sched(8..s. ) 451 . // not affected // changed my mind. }).s.0". c.0..{ // the x-methods are exclusive "3.postln.0.i.Where: Help→Crucial→Scheduling→OSCSched c.xsched(3.

u = Tempo. Tempo.beats2secs(4. It can be used to convert beats <-> seconds. TempoBus adds itself as a dependant to the Tempo object. but this value is only accurate at the time you make the computation. Tempo.gui. // there is a gui class Tempo.3. // in beats per second Tempo. // in beats per second All of the following methods exist as class methods (the default tempo) 452 .gui.tempo = 1. t. It can be used for translations between seconds. separate tempii. it is informed.postln. It holds an instance of TempoClock which it sets to its own tempo whenever that is changed. Tempo. and it updates the value on the bus accordingly. beats and bars.0).Where: Help→Crucial→Scheduling→Tempo ID: 161 Tempo tempo calculations This class represents the concept of tempo. so when the tempo changes.bpm = 170.bpm = 170.postln. UGens can use this for scaling their frequencies for beat based rhythms etc.bpm = 170. A TempoBus can be started on the server. u. t. Tempo.3.beats2secs(4.new. t = Tempo.0).new. and it will keep the Tempo object’s tempo as a float value on a Bus on the server. You can create an instance of Tempo if you need individual.bpm = 10. Tempo. All class methods refer to the default global tempo.tempo = 2. If the tempo is changed the value is of course no longer valid.

secs2bars(seconds) sched(delta.function) Schedule a function to be evaluated at an absolute beat. or Tempo. or Tempo. your function will still be evaluated at the time originally calculated.bpm_(96).0.0. Use OSCsched for more sophisticated control (able to reset the beat). schedAbs(beat. If you change the tempo after scheduling. bpm bpm_(beatsPerMinute) Tempo. A more sophisticated solution will be presented later.tempo_(2. tempo in beats per second tempo_(beatsPerSecond) Tempo. A more sophisticated solution will be presented later.bpm = 96.Where: Help→Crucial→Scheduling→Tempo and as instance methods.function) Schedule a function to be evaluated delta beats from now.beatsPerBar = 7.tempo = 2. If you change the tempo after scheduling.0). your function will still be evaluated at the time originally calculated. 453 . as measured from the time SuperCollider first booted up. beats2secs(beats) secs2beats(seconds) bars2secs(bars) you can change the beats per bar: Tempo.

Where: Help→Crucial→Scheduling→Tempo 454 .

new(server. a === b // they are the same object ) ( s = Server.trig.postln.tempo) TempoBus.kr(tempo). Out.0). amp = Decay2. t. ( a = TempoBus. trig = Impulse. It can be used as a multiplier in any Synth on the Server that needs to know the Tempo. var tempo.tempoBus. the shared instance will be returned for any subsequent requests.1).0.kr(trig. SynthDef("help-TempoBus". Any Inst/Patch that needs a tempo input should use a TempoPlayer.new default server.ar(300) 455 . t = TempoBus.ar(out.Where: Help→Crucial→Scheduling→TempoBus ID: 162 TempoBus A Bus whose value is set by a Tempo.index. tempo = In.new.amp. default tempo There is one TempoBus per server. TempoBus. After the first time it is created.clip2(1.bpm = 60.{ arg out=0.local. Tempo.new. per tempo.new(s).0.kr(tempoBus). b = TempoBus. amp * SinOsc. It is used by BeatClockPlayer.01.

default.1.bpm = 666.0.gui(f).play(s.bpm = 40. Tempo. Tempo. Sheet({ argf.[0. Tempo.bpm = 100.Where: Help→Crucial→Scheduling→TempoBus ) }).index]). // move the slider.t. Tempo. it works }) ) see TempoPlayer 456 .

Impulse.[ TempoPlayer.{ argtempo. ( Instr(\helpTempoPlayer.new ]).insp whose defaultControl is a TempoPlayer \tempo.asSpec. and so don’t incur any additional resources.specs as a TempoSpec \tempo.gui ) A TempoBus belongs to a specific server for its whole object-lifetime. A TempoPlayer can be saved in a larger musical structure and that structure is capable of being played on disparate servers.ar( tempo ) 457 . A TempoPlayer is only told which server it is to play on when it is asked to prepare for play by its parent object.[ \tempo ]). Impulse. Move the tempo slider. All TempoPlayers share the same TempoBus.Where: Help→Crucial→Scheduling→TempoPlayer ID: 163 TempoPlayer Outputs the current tempo in beats per seconds.ar( tempo ) }. the symbol \tempo is registered in Spec. Patch({ arg tempo.asSpec. Patch(\helpTempoPlayer .defaultControl.insp so that the argname tempo in an Instr would by default result in a TempoPlayer for a Patch using that Instr.

Where: Help→Crucial→Scheduling→TempoPlayer }).ar( tempo ) }.new ]).gui execute this many times ( Patch({ arg tempo.play(atTime: 1) ) see BeatClockPlayer 458 .[ TempoPlayer. Impulse.

6.12 Sequencers 459 .

LFNoise1.12. ( Patch({ arg freq=100.Prand([0.0.2. 0. scaleArray.0. 7.1. ModalFreq. 1. inf).0])).10 ].new(Pseq(#[ 7. freq * 0.5].25.amp=1.new( StreamKrDur. root. 2.play ) Used as a Stream. stepsPerOctave ) Used as a kr rate Player. 4. Patch({ arg freq=200. 0.1.inf).2) }. 460 .new( degree.kr([0. pseudo-ugen ModalFreqUGen. ( m = ModalFreq.1).25. 0.5.Where: Help→Crucial→Sequencers→ModalFreq ID: 164 ModalFreq Control rate player For backwards compatiblity and convenience.ar( [freq.3.5).0. 3. FloatArray[ 0.25.0.0.1]. StreamKrDur(Pbrown(2.1). Not as efficient as using it directly as a Player.8. 0. Can also be used with Pbind or any other Pattern.4. octave.1). This actually returns a Patch on the Takes floats or player inputs and puts out control rate signal of frequency.0.[ m ]).new(Pbrown(1. 12 ). 6. 0.10 ]. StreamKrDur. Pulse.6.

Where: Help→Crucial→Sequencers→ModalFreq SinOsc. 0.0.5.0.25. 1 ]).2.amp) }.inf).[ StreamKrDur( ModalFreq(Pseq([1.ar([freq.1).inf)).freq + 30].75].0.play. ) 461 .3. Pseq([0.4].

arrayOfBeatDurations.new.Where: Help→Crucial→Sequencers→PlayerSeqTrack ID: 165 PlayerSeqTrack Play a series of Players in a sequence. This is only designed to work with Players that already saved to disk.{ l. f.value... if(ok. attack.add(loadPath(path)). path3 . if you use paths. even while playing.] ( // locate some players on your hard drive and add them to a list // hit cancel when you have enough l = List.value ) 462 . path2. loop) arrayOfPlayerPaths . path2.arrayOfEnvelopes. }) }).or nil (players can be added later ) or they can be actual players. PlayerSeqTrack( arrayOfPlayerPaths. They can be added and removed dynamically. f = { GetFileDialog({ argok. with individual control over duration. path1. then identical paths in the array will play the identical player (only one copy is loaded). }. f. The primary design difference between this and CyclePlayers is that PlayerSeqTrack does not need to know all of its players before play/editing.path.release and level. so the sequence can contain repeats: [ path1.

4).choose ). p. p.gui.setDuration(1.changed. 463 .changed. weve already loaded the players p. p.4).insertLast(Properties(\working). }). p. p.insert( 3.new.4).4).4).setDuration(0.setDuration(3.free.gui ) p.do({ p. p.play.setDuration(2.wchoose.setDuration(5. p.Where: Help→Crucial→Sequencers→PlayerSeqTrack ( p = PlayerSeqTrack. // update the gui ) // while playing is fine.loadDocument). p.4). p. 6.asString. ) p. l.setDuration(4.insp PlayerSeqTrackGui now while watching the pretty visuals: ( p.

}). p. l. p.16.5. // no gui display of release times ) ( 5.32].0) ).changed.changed.2. ) ( 5. GUI Hot-Keys While selected on any of the sequences these keys are active: <select previous 464 .do({ arg i.Where: Help→Crucial→Sequencers→PlayerSeqTrack p. ( 5. rrand(0. p. }). [4.changed.setDuration( p.choose ).1.insert( 8.rand. p.insert(i. }). l.do({ arg i.rand.setRelease( i. It also changes when you change the tempo.8. rrand(0.01.0) ). }). p.deleteAt(6). ) ( 5.playerSeq.size.choose ).do({ arg i. Note that the duration display changes also.do({ arg i.setLevel( i. // no gui display of levels ) p.changed. p.choose ).

new.level. attack.topGui(f). all steps with this player.infoGui(f). Its turtles all the way down It is of course possible to put a PlayerSeqTrack inside of another PlayerSeqTrack. PlayerSeqTrack. }) ) Note that topGui returns the PlayerSeqTrackGui object.Where: Help→Crucial→Sequencers→PlayerSeqTrack -> select next opt -> move selected left opt <move selected right up increase dur by 1 bar down decrease dur by 1 bar opt-up double duration opt-down half duration shift-opt-up double durations of all steps shift-opt-down half durations of all steps ‘ relocate (while playing) to this step delete delete this step g gui the player at this step i open information window escape focus on the first focusable view in this window that is not one of the sequence steps The information window in the information window you can edit duration. which responds to infoGui(layout). 465 .decay. all steps It is also possible to embed the info window on the same layout: ( Sheet({ argf. envelope in three selectable scopes: this step.

// return the gui itself Label(f.player. player).insert(g.topGui(f). Live Insert of Players ( // insert players at the selected step.name.round: }) }) 1."insert:").changed }) ) ( // insert players NOW at the presently playing step // 808 style Sheet({ argf. ActionButton(f.player.changed }) ) 466 . l. And the gui will be not lined up verticle. g = p. though they won’t easily remained synchronized if you relocate while playing. p.{ p. Eventually i will write a multi-track version that holds and synchronizes multiple PlayerSeqTrack.0). p = PlayerSeqTrack.name."insertNow:"). even while playing Sheet({ argf.new.new. Label(f.{ p.insertNow( player.selected ? }) }) 0 .do({ arg player.do({ arg player.Where: Help→Crucial→Sequencers→PlayerSeqTrack Multiple tracks are obtainable via the use of PlayerMixer. p = PlayerSeqTrack. ActionButton(f.topGui(f). l.

2. nil) ] 467 . duration .01.01. notice that the steps 0 and 3 repeat the same player. Env. 1. 0. When this example saves.the number of beats it should play for if nil.1 ]. use 128.env) step. [ 0. 16.01.the player object or path to insert in the example above. 0. 16. nil).01. use the natural beatDuration of the player if that is nil. 1. 1.new( [ ":Patches:footfist:dawhohop". ":Patches:footfistwhisker:buggercraft". [ -2.1 ]. 1. Env. 1. [ 0. -2 ].1 ]. 2. -2. nil). ":Patches:footfist:dawhohop". 1. 0 ]. [ -2. 16. -2 ]. nil). 1. 1. 2. 0.duration. 0. 2. use default envelope All players that you insert must have a path (must have been loaded from disk).01. use the duration of any previous appearance of this player in the sequence if that is nil. -2.new([ 0. 2. 1.new([ 0. 2. -2 ]. they will share the same copy.the envelope to use if nil. -2 ].Where: Help→Crucial→Sequencers→PlayerSeqTrack insert(step. nil). 0 ]. 16. PlayerSeqTrack.new([ 0.1 ]. 1.01. -2. 0 ].new([ 0. 0.index to insert at player . 1. you share the same player instance.player. ":Patches:footfistwhisker:dhallooo". 1. 16 ]. -2. -2. [ 0. nil). [ 0. -2. ":Patches:footfist:simp"]. 1.new([ 0. 0 ].new([ 0.1 ]. Env. 1. [ -2. ":Patches:footfistwhisker:basscl". use the envelope of any previous appearance of this player in the sequence if that is nil. 0. i used the actual player because its faster. 1.1 ]. [ 16. 1. On reloading. 1. 0 ]. and it doesn’t have to load anything from disk while its playing.0 beats env . -2 ]. 0 ]. [ Env. -2 ]. [ 0. 1. [ 2. [ 0. [ -2. Env. [ -2. Env.

-4. 0.new( [ ’minimoog’.01. -2. 1 ]. 1. 440. ’SyncSaw’]. Patch. -2 ].214. 16.new( [ ’minimoog’. [ 0.1 ]. 1. 0. 1. 1. -2 ]. [ 0. nil). 0 ]. 1. 2.new([ 0. 0. 1.1 ].new([ 0. ’detune’]. 0 ]. 1. 0.Where: Help→Crucial→Sequencers→PlayerSeqTrack ) Actually PlayerSeqTrack could play players without a path. 2. [ BeatClockPlayer(16) . [ 0. -4. ’detune’]. 4. [ 16.new( [ ’synths’. Env. 16 ]. [ -2. [ 440. 1. 1 ] ) ].new( [ Patch. [ Env.new([ 0. Env. Env. -4. [ -2. 0 ]. 2 ] ). 0. but the gui would display them all as "nil" "nil" etc.01. 0.01. [ 440.5. ’stereo’. -2 ].4. And it would save as something like this: PlayerSeqTrack. 447.01. nil) ] ) And on reload the identical steps 0 and 3 would not be able to share the same copy. -2. Patch. nil).4. 0. 0 ]. -2.5.new([ 0.3. 1. 0. 0. 2.1 ]. 0. 468 .4. [ 0. 0. 2. nil). [ -2. 1 ] ). 1.

inf) { 1. }.0.Where: Help→Crucial→Sequencers→Stream2Trig ID: 166 Stream2Trig generate a trigger signal from a stream superclass: StreamKrDur Stream2Trig(levels.1).A stream of values for the level of each trigger 1. p = Pulse.A stream of values for the delta in beats between each trigger. nil.0].env.new(\Stream2Trig.inf) deltas . 0.0.25.0. {arg gate=0. Enveloper2.25 Prand([0.16.0.freq=440.rand } ‘[ 1.2.deltas) Take a pattern and use it as a stream of values for a trigger. \envperc ]).kr(0.] // Ref converted into Pseq([1.5] // Ref ( Instr(\Stream2Trig. This plays the pattern in real time on the client.ar(freq.abs.env.0.2).0 Prand([1.0.1.5).0) }) ‘[1. and sends messages to the server.1.gate.LFNoise1.0].ar(p. levels .[ nil.5].125.0.0. Patch. [ Stream2Trig( 469 .25.inf) FuncStream({ rrand(0.0.0.

Pseq([0.0.inf) ).0].0. 470 .inf).inf).gui ) A nice sequel would be to make a class that also takes a gate duration stream (in beats or legato).1.0.2)].25.1. Pshuf([0.25.30.1.gui ) ( Patch. StreamKrDur(Pseq( Array.125].0]. [ Stream2Trig( Pseq([ Pn(Pshuf([1.0.0.0.0.0.midicps.1 ) ]).0.0.2.Where: Help→Crucial→Sequencers→Stream2Trig Pseq([ Prand([1.4)].25.125].125.2.25.0. Pseq([0.125.3).4).inf ).0].1.1.new(\Stream2Trig. so that the gate will stay open for that long.50).0.25.25.0.0. 84 ]).0.inf) ).25. 0.rand(16.

1). using less than it takes to switch from one text window to another..{ rrand(20. 0.midicps }). if 0.16). AbstractPlayer StreamKrDur. 471 . Its timing are exact.0 (default) no Lag will be used.new(pattern.0.5.80).lagTime) This plays a pattern in real time on the client. and sends those values as /c_set messages to its bus on the server. Durations are specified in beats by a second pattern.// a float 0. freq = StreamKrDur( Prand(Array. its messages are sent to the server with a small latency period before they should be played.fill(rrand(4. That is to say when you start playing a StreamKrDur. dalek mating season I ( var freq. pattern a Pattern or Stream of floats durations a float specifying the beat constant duration a stream or pattern of beat durations or a ref to an array of beat durations eg ‘[0.durations.25.. It is extremely efficient in CPU usage on the client.kr that will be added to the output. It is cancellable and stoppable within the value of Server-latency.inf).25. it will run slightly and exactly ahead of time.1] lag lag time for a Lag.Where: Help→Crucial→Sequencers→StreamKrDur ID: 167 StreamKrDur superclass: StreamKr .

ar(freq.{ rrand(20.80).100.[ freq ]). freq = StreamKrDur( Pbrown(40.pmindex.inf).3) }. ‘[ 1.2) }.inf). 0. freq = StreamKrDur( Prand(Array. // times are in beats Patch({ arg freq=440. 0. Saw.16).play ) dalek mating season II ( var freq.100.100.ar(freq.ar(freq.[ freq ]).0.// a float 0.inf).0.Where: Help→Crucial→Sequencers→StreamKrDur Tempo. // an array 0. SinOsc.3)) //PMOsc.ar(600.25.1).100.SinOsc. 472 .25]. // times are in beats Patch({ arg freq.freq2.play ) ( var freq.bpm = 100.0.midicps }).0.2. Tempo.100. freq2 = StreamKrDur( Pbrown(40.0.1.fill(rrand(4.05).0.bpm = 100.

25]. Prand([0.{ arg freq=400.0.Where: Help→Crucial→Sequencers→StreamKrDur ‘[ 1. p=Patch.0.0].1).0.fill(rrand(4.3.0.inf). ‘[ 1. 0.bpm = 100.0.inf).ar(freq.inf).3.0.3.pmindex.0.{ rrand(20.inf).phasemod=0.1.3) }. [ StreamKrDur( Prand(Array.ar(freq. // an array 0.[ freq.amp=1.0. PMOsc.freq2. ’pmosc’].2. PMOsc.25.pmindex.0. 0.inf).100.1.05).// a float 0. 473 . pmindex ]). // a pattern 0.16).1. // times are in beats Patch({ arg freq.80).3. pmindex = StreamKrDur( Pbrown(1. freq2.25.100.05).new([ ’oscillOrc’.1).125. StreamKrDur( Pbrown(1.\pmosc].0.gui ) same thing with a separated Instr ( Instr([\oscillOrc.1.0. 0.5. StreamKrDur( Pbrown(40.freq2.25]. Tempo.pmindex. // an array 0.1). // a pattern 0.amp) }).25.phasemod.2.0.inf).freq2. freq2=500. 0.midicps }). Prand([0.5.0].pmindex=0.125.

0.0).minWidth: 250). layout = FlowView. 500.0.new."Nome". 500 ].inf). StreamKrDur( Pseq([1.01.0.25. and both stream kr durs are running all at the same tempo. 750.75.not.75.5. See the example there.25.0. 500.0.3 ]).5. 4) }) ) In this case since the beat clock. then this would be a good starting point.25. nome = Patch({ arg beat.0.stop }) }.0.ar( K2A.ar( freq. StreamKrDur( Pseq([ 750.0. 400. ToggleButton(layout.25] * 0.freq.gui.25. 500. 1.5. SinOsc. 300. 400.isPlaying. Only one scheduler then instead of 2. ) A metronome ( var nome.new(4.layout.5.0) ]).inf).ar(beat).0. But if you wanted them in different syncs.isPlaying.0. amp ) ) }.play(atTime: }. 500. 1.{ if(nome.25.{ if(nome.0.[ BeatClockPlayer.amp.75.0). 0.Where: Help→Crucial→Sequencers→StreamKrDur 0.0.0. you could better use an InstrGateSpawner and do separate events. p.25. 474 .0. 500.11. 500.0. 500. different streams and a continous running synth (have fun with the Decay).25.{ nome.01. Decay2. 400.0. 750.{ nome. 750. 0.

( Tempo.pmindex=0. 475 .16).\trigged. PMOsc.0.5. // a pattern 0. freq2=500.0. ‘[ 1. \pmosc]. Instr([\oscillOrc.3 ]).1).inf).midicps }).100.// a float 0. what I am doing here is like an analog synth: the oscillators play constantly and it is gated to create notes.Where: Help→Crucial→Sequencers→StreamKrDur with a Pbind you are creating a new event for every note and creating new UGens and a new Synth each time.25].80). this is not so efficient. \pmosc]. Prand([0.inf).05).amp=1. its more fluid.{ rrand(20.3. 0.inf). freq2. // an array 0.1).ar( freq. StreamKrDur( Pbrown(40. phasemod.100.phasemod=0. pmindex. this can even be done with samples.0.2.0.25.0].bpm = 130. p=Patch.{ arg trig=0.1. Decay2. StreamKrDur( Prand(Array.freq=400. liquid and uses significantly less cpu.new([\oscillOrc. [ BeatClockPlayer(16.125.0).1.\trigged. 0.3.0.inf). 0.25. StreamKrDur( Pbrown(1.kr(trig) ) }).0. 0.0.fill(rrand(4.

0.1.1.reject({ arg t.Where: Help→Crucial→Sequencers→StreamKrDur p. // //l = [0.125. // ////fails //l = Array.fill(8.125.5].5].1. // //(l % (l. 1.5) }).minItem // //l / g should be all integers // or it fails // 476 .25 + 0.0.0.25.0. ) //durations will be multiples of trigger pulse // //stream kr dur has to find the lowest common multiple // //l = [0.0.minItem)).25.{ rrand(0.gui.1. t==0 }).minItem)) every is 0 //or // //g = (l % (l.

6.13 ServerTools 477 .

When a player is stopped or freed. several players are using the same bus.. Only the PlayerMixer itself should be able to free the Bus. A SharedBus will not free its bus number until given explicit permission by its owner by calling . it frees its Bus..releaseBus. and they will free that Bus when the player is replaced by a new player in the socket. which frees the Bus number for reallocation. use it .. each player that plays in the socket is given the bus.. Again..as(SharedBus). In the case of PlayerSocket. only the PlayerSocket itself should be able to finally free the Bus. .. In the case of PlayerMixer. // releases and frees the Bus index 478 . sbus.releaseBus If you are writing a class that for instance hosts various Players and you wish them to share busses or to keep ahold of the bus you are playing them on without having the Player free it: sbus = bus.Where: Help→Crucial→ServerTools→SharedBus ID: 168 SharedBus superclass: Bus This simple class solves a problem with sharing busses between players.

14 UncoupledUsefulThings 479 .6.

gate = In.Where: Help→Crucial→UncoupledUsefulThings→Enveloper2 ID: 169 Enveloper2 gate the audio input with an Envelope.adsr) }.{ arg i.Env. b.2.free. Enveloper2.0. 480 .ar(440 + rrand(1. ) // On b.0. SinOsc.local).qnty=4.value = 0.5)) }) * qnty. ( b = Bus.value = 0. p = Mix. // Off b.value = 0.ar(p.gate.value = 1. b.control(Server.gate.play.arFill(qnty.asInteger.index).0.kr(b. b. { var p.reciprocal.

false. This object should be used as the keydown or keyup action for a view in place of a function. ( #1322ff k = KeyCodeResponder.register( }). // match single modifiers exclusively 481 .new.Where: Help→Crucial→UncoupledUsefulThings→KeyCodeResponder ID: 170 KeyCodeResponder Handles multiple registrations for keycode and modifier combinations. Its a simple way to hook up keys to respond. false. and change from machine to machine. true. though the physical location of the key may still vary according zee nationality ov der keyboard. but it won’t transfer to other people’s computers. #1322ff #1322ff see [SCView] Use this to post the keycodes ( KeyCodeResponder. KeyCodes are hardware dependant. see also [UnicodeResponder] which matches based on the unicode. { k.tester ) it prints // shift : 41 . false.

functionKeyModifier . 123 . { ". #1322ff #1322ff // match multiple modifier combinations // shift caps opt nil. false.postln. opt.opt. w = SCWindow.normalModifier | KeyCodeResponder. }).keyDownAction = k. v. 123 . v = SCSlider.new.postln }).normalModifier.postln }). k. function) for shift. 52 .front.cntl 482 . k.registerKeycode(KeyCodeResponder. yes either shift-option regardless of CAPS".new(w.normal( 36 -> { "return". }).register( 36. yes control true. // arrow keys are considered function keys and must be bit ORd with function key modifier k.postln.postln }).postln.postln.registerKeycode(KeyCodeResponder. k.shift( 36 -> { "shift return". ) register(keycode.100. "<- k. { "enter".shift( 36 -> { "SHIFT RETURN only". cntl.registerKeycode(KeyCodeResponder. { no k. true.functionKeyModifier . // overwrites previous registration k.100)).focus. }). { "control <-". shift. // "return: }). }).Where: Help→Crucial→UncoupledUsefulThings→KeyCodeResponder k.controlModifier | KeyCodeResponder.Rect(10. caps.option( 36 -> { "option return".postln. caps.10. v.

"you touched me"....1) }). ..keyDownAction = { 0. . keycodeN -> functionN ) Any player’s gui can have its keyDownAction set ( p = Patch({ arg freq=440. ) 483 . .Where: Help→Crucial→UncoupledUsefulThings→KeyCodeResponder true indicates a required modifier false indicates an excluded modifier nil expresses that you really don’t care one way or the other normal(keycode -> function) normal(keycode -> fuction... }.ar(freq.postln. keycodeN -> functionN ) option(keycode -> function) option(keycode -> fuction. SinOsc. keycode2 -> function2 . keycode2 -> function2 .mul: g = p.gui. keycodeN -> functionN ) control(keycode -> function) control(keycode -> fuction. keycodeN -> functionN ) note the association ( key -> value ) shift(keycode -> function) shift(keycode -> fuction. keycode2 -> function2 .. g.. keycode2 -> function2 . .

keyDownAction = kcr. these keys will be active providing that the view that is actually in focus doesn’t handle the key event (it should have a nil keyDownAction function or pass nil)..postcln }).. aPatchGui. kcr.shift( 36 -> { "shift 36". notice that every key stroke is passed.gui.{ "shift.nil. ( KeyCodeResponder. aPatchGui = aPatch.Where: Help→Crucial→UncoupledUsefulThings→KeyCodeResponder focus on the slider. /* this will fire on shift-’r’ shift must be held down caps may or may not be down cntl or opt status is irrelevant */ 484 . the slider does not swallow them. You can concatenate KeyCodeResponders using ++ global keydowns not yet tested. This means that when ever the player is focused (any of its controls is in focus).option( 36 -> { "option 36". kcr.true. no caps".register(15.new. /* this will fire on shift-’r’ shift must be held down caps must NOT be down cntl or opt status is irrelevant */ KeyCodeResponder..false. or you can use KeyCodeResponder kcr = KeyCodeResponder.clear.nil.postln }).postln }).

{ "overwrote the previous one".nil.nil.{ "shift. // q no modifier 485 .r KeyCodeResponder.nil. Only one function per deny/require mask combination is possible per keycode: ( // hit shift . ) The simpler.tester ) // using characters KeyCodeResponder.nil.focus }). yes/no caps".registerKeycode(2. Sheet({ arg f. older method is : KeyCodeResponder.{ }). Sheet({ arg f.focus }). ActionButton(f).Where: Help→Crucial→UncoupledUsefulThings→KeyCodeResponder KeyCodeResponder.postcln }).nil. ActionButton(f).registerChar(0.true.nil.true.postcln }).{ }).register(15. ) This is very useful when using CAPS-LOCK to switch interface modes etc.nil.postcln }).$q.// * whereby that modifier and only that modifier will fire the funtion.register(15. see SCView for modifier values or use this : ( KeyCodeResponder. KeyCodeResponder.{ "shift r".true.nil.register(15.nil.28.

solution: // place this at the top of your performance code to start with a clean slate KeyCodeResponder.Where: Help→Crucial→UncoupledUsefulThings→KeyCodeResponder Gotcha: it is easy to forget that you registered a function with KeyCodeResponder that holds a reference to a large object. Garbage Collection will not remove the object until you have released your reference.clear. 486 .

it passes through unscathed. amplitude detectors or audio functions where you need to ensure that the input is mono. It takes the first channel and discards others. It saves asking the input if its an array or not.ar(input) This is useful for inputs to compressors. If the input is already mono.Where: Help→Crucial→UncoupledUsefulThings→Mono ID: 171 Mono forces the input to a mono signal if needed Mono. 487 .

register(Sample. implements the Notification pattern.postln. 488 . and all functions that were registered for that notification will be excecuted.notify(this. }).Where: Help→Crucial→UncoupledUsefulThings→NotificationCenter ID: 172 NotificationCenter Objects can send notifications to the NotificationCenter. { argpath.\didRecord).\didRecord).Sample. This allows any interested client object to be notified of special events such as the object being saved to disk. path.notify(this.\didSave.postln. except here the model object does not ever know anything about who is dependant on it. //in the following examples this is the interpreter this. // register a function NotificationCenter.soundFilePath). For instance when a Sample is saved it emits a \didSave notification: NotificationCenter(notify.register(this.\didRecord.\didSave.\sampleWatcher. }). { "hello". This is similar to MVC.postln an Interpreter ( // nothing is yet registered // so notify finds nothing to do NotificationCenter. the object recording a sound file version of itself etc. // now it has something to do NotificationCenter.\theRequestingObject. You can listen for this: NotificationCenter.

}). NotificationCenter.\didRecord).postln.unregister(this. (// two symbols NotificationCenter. }). comments.\didRecord.\thingOne.register(this. There can only be one notification per listener. }).’yo mama’]).register(this.postln. but you may use anything for the listener object. thus releasing yourself for GC NotificationCenter.\didRecord. path.Where: Help→Crucial→UncoupledUsefulThings→NotificationCenter hello // unregister.this.\didRecord). NotificationCenter.aiff".postln. { "do this".postln.\theRequestingObject) // theRequestingObject is no longer interested in this notification NotificationCenter.\didRecord.register(this.\didRecord.\thingOne.comments.[":SoundFiles:blurb. NotificationCenter.notify(this.register(this. such as an arbitrary symbol.\thingTwo. { "this will get overwritten by the next registration". It is used to identify the notification and to find it later to remove it when needed. }). an array of arguments can be supplied to be passed into the function NotificationCenter. // after the addressing. ) The listener argument is somewhat unimportant as far as you the client is concerned. do this do this also ) ( NotificationCenter.notify(this.\didRecord.notify(this. { "do this also".aiff yo mama 489 . { arg path.\didRecord.postln. :SoundFiles:blurb.

{ // do things }).this. } 490 .register(model.removeOnClose( NotificationCenter.\didRecord. layout. ).Where: Help→Crucial→UncoupledUsefulThings→NotificationCenter ) You can also remove the Notification registration by getting the layout to remove you when the window closes: guiBody { arg layout.

// 4#1322ff becomes 2 2) }. // 3#1322ff becomes 2 2) }. mixdown) input .the audio signal numChannels .ar([100.0.play ) ( #1322ff { NumChannels.2).100].300]. regardless of the number of input channels.300.ar( SinOsc. NumChannels.200.ar( SinOsc.true/false.ar( SinOsc.2).ar([100.0. whether you want to mixdown or just use the first channel ( #1322ff { NumChannels.200.0.an integer mixdown .Where: Help→Crucial→UncoupledUsefulThings→NumChannels ID: 173 NumChannels ensures the output has the stated number of channels. // 1#1322ff becomes 2 2) }.0.ar( input.0.ar(100.play ) ( #1322ff { NumChannels.play ) 491 . numChannels.0.2).

Where: Help→Crucial→UncoupledUsefulThings→NumChannels mono input is copied multi-channels clumped and if mixdown is true mixed down else first channel used see also [Mono] 492 .

By default this is "/tmp/" for Linux and OSX. Instance Methods fileName returns just the name of the file itself. i. PathName. will be converted to your fully addressed home directory. panded.8 f/Sounds/FunkyChicken").2. It expects a path to a file. myPath = PathName.Where: Help→Crucial→UncoupledUsefulThings→PathName ID: 174 PathName superclass: Object file and directory path utilities PathName is a utility Class for manipulating file names and paths. ( var myPath. myPath.e.2. etc.8 f/Sounds/FunkyChicken").fileName.postln.new("MyDisk/SC 2. as per String-standardizePath. This is used by Buffer. and lets you access parts of that file path. Creation *new(path) path is a String which likely contains one or more / as typical for folder separation.new("MyDisk/SC 2. and "/WINDOWS/TEMP/" for Windows. Symbolic Links will be ex- Class Methods tmp tmp_(aPath) Get or set the global temp directory as a String. ) 493 . everything after the last slash in the full path.

Where: Help→Crucial→UncoupledUsefulThings→PathName pathOnly returns the full path up to the file name itself. ) fullPath returns the full path name that PathName contains.2.2.pathOnly.new("MyDisk/SC 2. ( var myPath. i. myPath = PathName. myPath. ) 494 . myPath. for storing several files in the same folder.8 f/Sounds/FunkyChicken"). myPath = PathName.folderName. myPath. ) isRelativePath isAbsolutePath asRelativePath you MUST have correctly initialized the scroot classvar for this to know what it is relative to ! folderName returns only the name of the folder that the file is in.postln.e.postln.new("MyDisk/SC 2.new("MyDisk/SC 2.8 f/Sounds/FunkyChicken").8 f/Sounds/FunkyChicken"). everything in between the last but one and the last slash. ( var myPath.postln. This is handy e.fullPath. myPath = PathName. everything up to and including the last slash. i.e. ( var myPath.2.g.

noEndNumbers.Where: Help→Crucial→UncoupledUsefulThings→PathName allFolders returns a list of all the folder names in the pathname. ( var myPath. ) endNumber returns a number at the end of PathName.diskName.postln.postln.allFolders.diskName. noEndNumbers returns fullPath without any numbers at the end. ( var myPath.8 f/Sounds/FunkyChicken"). myPath. myPath = PathName.postln.postln. Returns zero if there is no number. myPath = PathName. returns the disk name.new("/MyDisk/SC 2.8 f/Sounds/FunkyChicken"). ) diskName if path is an absolute path.new("MyDisk/SC 2. myPath.2.2. else a blank string.8 f/Sounds/FunkyChicken").endNumber. myPath = PathName.endNumber. 495 . PathName("floating").2. ) ( // note the / at the start var myPath. PathName("floating").noEndNumbers. PathName("floating1").new("MyDisk/SC 2. PathName("floating1").postln.postln.postln. myPath.

Where: Help→Crucial→UncoupledUsefulThings→PathName nextName generates a sensible next name for a file by incrementing a number at the end of PathName. if (ok.postln.postc.postc.fileName.postln. to generate a new filename when you don’t want to overwrite an existing file with the current name.postln.new( { arg ok. and e. This is useful for recording files with consecutive names.nextName.postc.nextName.new(path). myPathName. /* ( GetFileDialog. myPathName. PathName("floating12_3A4X_56. "fileName only/ ". { myPathName = PathName. or by adding one if there is none. PathName("floating34").postln. "path up to file only/ ".nextName. ".postln. "New PathName object/ myPathName. path.postln.pathOnly. Just pick any file to see all the parts of its path.7"). var myPathName. Here is an example that uses many instance methods. 496 . PathName("floating").g.

using its foldername and filename/ ( GetFileDialog. myFile.asSymbol ]. }. a soundFile/ myFile = SoundFile. var myPathName.postln.Where: Help→Crucial→UncoupledUsefulThings→PathName "folder Name/ ". myFile). { Library.postc.asSymbol.put( [ myPathName. if (myFile.").folderName ++ " please.g. { ("Could not read soundfile " ++ path ++ ". } ) } ) ) Choose a soundfile to put into the library. if (ok.new(path). myPathName. } ) } ) ) Save three tables in the same folder: 497 .folderName.postln. // read your file from disk. path.fileName.readHeader(path). } ).postln. myPathName. e.new( { arg ok. ("Check LibMenu/ " ++ myPathName. { myPathName = PathName.folderName.").new.

path. Array.write(myPathOnly ++ "table3"). table3. "table1".asWavetable. 1.0. myPathOnly. myPathOnly = myPathName. table1.write(myPathOnly ++ "table1"). var myPathName. 0. } ) } ) ) */ 498 . PutFileDialog. { arg ok.3]).sineFill(1024. if (ok.rand(64.pathOnly. { myPathName = PathName.newClear. table2.sineFill(1024. table3. table2.Where: Help→Crucial→UncoupledUsefulThings→PathName Note: The file name chosen in the dialog is ignored! The files are always named table1. table2.2.new(path). [1. ( var table1. table2 = Signal. table3 = Wavetable. table1 = Wavetable.new( "Pick a folder for tables1-3/".write(myPathOnly ++ "table2").0)). table3.

// if you were to have something at :Patches:dhalf this would work ( PlayPathButton(nil.Where: Help→Crucial→UncoupledUsefulThings→PlayPathButton ID: 175 PlayPathButton Superclass: ActionButton *new( layout.minx) when clicked. stops. if already playing. path. minx is the minimum x width of the button. loads the object at path and plays it. "Patches/sc3batch1/crazycrazySUnj" ) ) 499 .

true.values functions. false. option.register( 63233 .new. w = SCWindow.false. control. unicode -> function ] ) 500 .focus. // shift-option down arrow k. { "option down".new.Rect(10. register( unicode. ) normal( unicode -> function [. v.keyDownAction = k.false. { "shift option down". v = SCSlider. unicode -> function ] ) control( unicode -> function [. caps. }).false.debug. It matches modifier/unicode combinations and .false. function ) true/false/nil: must be present should not be present doesn’t matter ( k = UnicodeResponder.postln. shift. }).100. // option down arrow k. This is the best way to accurately match the exact modifier combination you want.front.register( 63233.Where: Help→Crucial→UncoupledUsefulThings→UnicodeResponder ID: 176 UnicodeResponder This can be used to replace a function in a view’s keydownAction. unicode -> function ] ) shift( unicode -> function [. v.new(w.true.100)).10.true.

postln. l= SCListView(w. with or without CAPS". 350. { "shift control. l= SCListView(w. 350.normal(63232 -> { "normal arrow".postln }) . nil. true.dup(12)) . w= SCWindow("test").front. w= SCWindow("test").dup(12)) .postln.scramble}. l. 350)) . 350)) .focus 501 . it does nothing else.items_({"eggs". }) .items_({"eggs". ( var w.shift( $A -> { "shift a".postln.focus . }) . 10.shift(63232 -> { "shift arrrow".scramble}. 10.register( 63232.front. unicode -> function ] ) The view in this example is merely to have something to focus on. Rect(10.postln }) ) ) Note that to match shift-a you have to specify "A". true.keyDownAction_( UnicodeResponder. l. }) .Where: Help→Crucial→UncoupledUsefulThings→UnicodeResponder option( unicode -> function [.normal( 97 -> { "normal a". Rect(10. false. not "a" You can also specify with ascii characters ( var w.new .

$B -> { "shift b".postln. }.postln. }. -> { ".normal( $a -> { "a ".". }. $.postln.postln. } ) .new .".Where: Help→Crucial→UncoupledUsefulThings→UnicodeResponder .postln. $" -> { "shift ’". $b -> { "b".keyDownAction_( UnicodeResponder.shift( $A -> { "shift a". }. }. ) ) see also KeyCodeResponder 502 . } ). }.postln. $’ -> { "’".postln.postln. $: -> { "shift .

optionModifier ) == optionModifier you will detect the presence of the options key. but not if only the option key is present ( eg. for shift-option ) 503 .Where: Help→Crucial→UncoupledUsefulThings→UnicodeResponder If you merely check the modifier like so: (modifer &amp.

504 . eg. it will break with large file sizes because it actually writes compilable code and there is a limit to that. (limit: 65536 different strings/symbols maximum) Compresses repeated values (limit: 4294967296 consecutive repeated items) The text archive written by Object. Floats. Supports large file sizes. so your 10000 Events with \degree in them will only need to save the word "degree" once. Strings. This would also let you add or remove fields later without breaking the archives. a Float writes a float to the file. SequenceableCollections and Dictionaries all have support to write to the archive.writeBinaryArchive will break if the instance variables change in any of the classes you have archived. Integers. Strings and Symbols write using a string table. You could also write a Dictionary and then not worry about order. You manually write to the archive and then should read from the archive in the same order you wrote in.writeArchive will store an object and restore all of its internal variables. The binary archives written by Object. Symbols. Compresses strings and symbols using a string lookup table. *write(path) open an archive for writing writeItem(item) this will write a character specifying the class type of the object and then will write the object in the smallest possible format. However. This class is designed for raw data storage that you manually and explictly control.Where: Help→Crucial→UncoupledUsefulThings→ZArchive ID: 177 ZArchive superclass: File A safe binary archive format. All other objects will be saved asCompileString.

4. a. If expectedClass is non-nil. 0.415356 ]) ].2.0) ). (’m’ -> [ ’setVolAt’. a.453).rand). <>version you may set the version number so that your various objects can check the version of the archive. *read(path) open an archive for reading readItem(expectedClass) read an item from the file.writeItem([1.2.5]).3.5]. a. a. a. Its just a convienient variable. 0.3. a. b = \b.4.797).make({ a = \a. Event[ 505 . it will throw an error if the item is of a different class.writeItem([ Event[ (’time’ -> 149.writeItem( Event. }) ). a.writeItem("hello"). you need to store and retrieve the version number yourself. the ZArchive won’t do it automatically.writeItem(1.writeItem([1.Where: Help→Crucial→UncoupledUsefulThings→ZArchive writeClose finish the write session and close the file.choose). ( a = ZArchive.writeItem( Ref(4.0.write("archiveTest"). (’delta’ -> 0.

b.postln.readItem.readItem.readItem.336438 ]) ] ]). 0.728).postln. b. b.readItem. a.postln. 0. ) ( a = ZArchive.Where: Help→Crucial→UncoupledUsefulThings→ZArchive (’time’ -> 150.postln. (’delta’ -> 0.25).writeItem([ IdentityDictionary[ \a -> "b". a.readItem.writeClose. b. 0. 506 .428). b.postln.close.readItem. ) ( b = ZArchive.write("archiveTest"). 0.read("archiveTest"). (’m’ -> [ ’setVolAt’.postln. b. b.37382 ]) ]. Event[ (’time’ -> 150. (’delta’ -> 0.writeItem(5). "b" -> \c ] ]).readItem.postln.postln.readItem.478). b. a. (’m’ -> [ ’setVolAt’. b.

61923). 2. 0. Environment[ (’efxpath’ -> ":Patches:justefx:4subtleDisturb er"). (’m’ -> [ ’setVolAt’. (’delta’ -> 0. (’delta’ -> 5.96291). Event[ (’time’ -> 10. 2. 0.77257). (’m’ -> [ ’setVolAt’. Event[ (’time’ -> 38. 1. Event[ (’time’ -> 35. 2. (’m’ -> [ ’setVolAt’.32508). Event[ 507 . (’delta’ -> 0. (’m’ -> [ ’state_’. Event[ (’time’ -> 29.219667. (’m’ -> [ ’setVolAt’.0219). 0.39474). nil. Event[ (’time’ -> 39. (’delta’ -> 8. 2. Event[ (’time’ -> 29. 2. (’filterObjects’ -> [ nil. 0. (’delta’ -> 2.197701 ]) ].68278). Event[ (’time’ -> 7. (’delta’ -> 0. (’m’ -> [ ’setMixOnVoice’. (’m’ -> [ ’setVolAt’.0359).39474).1706).4539). (’m’ -> [ ’setVolAt’.328532.98). 0.3051).5406). 1 ]) ]. (’m’ -> [ ’selectByPath’.172646 ]) ].71674). Event[ (’time’ -> 10.18991 ]) ]. 0.059). 2. (’delta’ -> 7. 0. ":Patches:riddims2:jRunnin" ]) ].85 ]) ]. 2.1905).144124 ]) ]. ":Patches:twisters:wahfunk".177931. (’delta’ -> 0. (’m’ -> [ ’setMixOnVoice’. Event[ (’time’ -> 10. 0 ]).160138 ]) ].129711 ]) ]. (’m’ -> [ ’selectByPath’. Event[ (’time’ -> 35. 0. 0. 0. nil. (’delta’ -> 2.0898). (’m’ -> [ ’setVolAt’. 0. nil ]). (’subject’ > Environment[ (’subject’ -> Environment[ (’paths’ -> [ ":Patches:splash:chewy". 2.39474). 2. 2.68278).writeItem( [ Event[ (’time’ -> 0). (’amps’ -> [ 0.3483). Event[ (’time’ -> 20. 0.42807.156951 ]) ].7 ]) ]). 2.142683 ]) ]. Event[ (’time’ -> 11. (’delta’ -> 8. 0. 2. (’m’ -> [ ’setVolAt’. nil ]) ]) ] ]) ].4167). (’delta’ -> 0. (’delta’ -> 0.Where: Help→Crucial→UncoupledUsefulThings→ZArchive a. (’delta’ -> 1. (’delta’ -> 0.41796). Event[ (’time’ -> 9. 2. 0. (’mixes’ -> [ 0. ":Patches:riddims:slowrollzghet".5853).75393). (’m’ -> [ ’setVolAt’.36998).177931 ]) ]. ":Patches:riddims:geekslut" ]) ].41796).

39474).4369). Event[ (’time’ -> 64.7559).6954). 0. 0. (’delta’ -> 2. (’m’ -> [ ’setVolAt’. 1. (’m’ -> [ ’setVolAt’.8023). 1. Event[ (’time’ -> 49.7109). (’m’ -> [ ’setVolAt’.673379).161).85606).177). Event[ (’time’ -> 50. Event[ (’time’ -> 41. (’delta’ -> 0.7415). 2. 0. 1 ]) ]. (’delta’ -> 11. Event[ (’time’ -> 65. (’delta’ -> 0. (’delta’ -> 1.129711 ]) ].4707).293). Event[ (’time’ -> 65. (’delta’ -> 1. Event[ (’time’ -> 40.51084). 0. 0. (’m’ -> [ ’setVolAt’. (’delta’ -> 0.3612). 1. (’m’ -> [ ’selectByPath’. (’m’ -> [ ’setVolAt’. ":Patches:clouds:screamspac" ]) 508 . (’delta’ -> 0. (’m’ -> [ ’setVolAt’.8394). (’m’ -> [ ’setMixOnVoice’.44118).8504). 0. 0. 0. (’delta’ -> 2.41796). (’delta’ -> 0. Event[ (’time’ -> 46. 1. Event[ (’time’ -> 49. (’delta’ -> 0. (’m’ -> [ ’setVolAt’. (’m’ -> [ ’setMixOnVoice’. (’m’ -> [ ’setMixOnVoice’.50468).6492). (’m’ -> [ ’setMixOnVoice’.Where: Help→Crucial→UncoupledUsefulThings→ZArchive (’time’ -> 39. Event[ (’time’ -> 50. 1 ]) ].128414 ]) ].160138 ]) ]. 0.4075). ":Patches:clouds:newjetengine" ]) ]. (’delta’ -> 1.346736 ]) ]. 0. 0.8889).144124 ]) ]. (’delta’ -> 4.3068).39474). 0. (’m’ -> [ ’setMixOnVoice’.696599).385263 ]) ]. (’m’ -> [ ’selectByPath’. (’m’ -> [ ’setVolAt’. Event[ (’time’ -> 64. (’delta’ -> 0. 1.522007 ]) ]. (’delta’ -> 1. 2.6784). (’delta’ -> 0.7141).41796). 0.614126 ]) ]. Event[ (’time’ -> 40. Event[ (’time’ -> 44. 0. 0. (’m’ -> [ ’setMixOnVoice’.89325).722501 ]) ].312063 ]) ].85606).85 ]) ]. 1. ":Patches:justefx:pitchCasStereoSprd" ]) ].92726).46286). (’delta’ -> 8. 0. Event[ (’time’ -> 74. (’m’ -> [ ’wakeEffectByPath’. Event[ (’time’ -> 79.37152). 1. 2.11674 ]) ]. 0. 0. (’m’ -> [ ’setMixOnVoice’.1539). (’delta’ -> 0.2435). Event[ (’time’ -> 51. 0.7225 ]) ]. 0. Event[ (’time’ -> 62.

(’delta’ -> 0. 0.06658).1471).95048). 0.115573 ]) ]. (’delta’ -> 1.375). (’m’ -> [ ’setVolAt’. Event[ (’time’ -> 101. 2. (’delta’ -> 0.77). Event[ (’time’ -> 133. 1. Event[ (’time’ -> 91. (’m’ -> [ ’setVolAt’.99692).Where: Help→Crucial→UncoupledUsefulThings→ZArchive ]. 2. 1.118). 0. Event[ (’time’ -> 110. (’m’ -> [ ’setVolAt’. 0. Event[ (’time’ -> 101. (’m’ -> [ ’selectByPath’. 0.614125 ]) ]. (’m’ -> [ ’setVolAt’. Event[ (’time’ -> 121. 0.928799). 2. 1.13007).161). (’delta’ -> 2.280856 ]) ]. 0. 2. Event[ (’time’ -> 123. (’delta’ -> 2.3483). 1.756).185).377151 ]) ]. 0. 2. (’delta’ -> 0. (’delta’ -> 1.320578 ]) ].388).832). (’delta’ -> 0. 2. 0 ]) ]. (’m’ -> [ ’setVolAt’.37152).32508). 2. (’delta’ -> 0.64). 0. (’m’ -> [ ’setMixOnVoice’. (’delta’ -> 6. 0. 2.73695 ]) ].84527). (’m’ -> [ ’sleepVoice’. (’delta’ -> 1. (’m’ -> [ ’setMixOnVoice’. (’delta’ -> 10. 2.443706 ]) ]. (’delta’ -> 10.724).272492 ]) ].41796).227494 ]) ]. (’m’ -> [ ’setMixOnVoice’. Event[ (’time’ -> 111.252771 ]) ]. (’m’ -> [ ’setMixOnVoice’.685). 0. 2.767). 0.208902 ]) ]. (’delta’ -> 0. 1 ]) ].5301). 1. (’delta’ -> 1. 0.55). 1. Event[ (’time’ -> 108.449).0811). (’delta’ -> 0. (’delta’ -> 9.322). 0. (’m’ -> [ ’setMixOnVoice’.39474). Event[ (’time’ -> 107. (’delta’ -> 2.39474). (’m’ -> [ ’setMixOnVoice’. (’m’ -> [ ’setVolAt’. ":Patches:plusefx:musiqueConcrete" ]) ]. Event[ (’time’ -> 104. (’m’ -> [ ’setMixOnVoice’.229792 ]) ].71828). Event[ (’time’ -> 110. 1 ]) ].0898).51).252771 ]) ].338). (’m’ -> [ ’setMixOnVoice’. Event[ (’time’ -> 104. 1 ]) ]. Event[ (’time’ -> 131. Event[ (’time’ -> 102.227). Event[ (’time’ -> 104. (’m’ -> [ ’setVolAt’. Event[ (’time’ -> 81.905). Event[ (’time’ -> 125. (’m’ -> [ ’setMixOnVoice’. Event[ 509 .

0. (’m’ -> [ ’setMixOnVoice’.39).37152). 0. 2. Event[ (’time’ -> 144. Event[ (’time’ -> 140. 2. Event[ (’time’ -> 137.167345 ]) ]. 0. 2. Event[ (’time’ -> 138.671). (’delta’ -> 0.37152). (’delta’ -> 0.3483). (’m’ -> [ ’setVolAt’. 2. 2.321). 2.73996).37152). 0. 0. 2. (’m’ -> [ ’setMixOnVoice’.37152). 2. (’m’ -> [ ’setVolAt’.139). Event[ (’time’ -> 138. 2.37152). Event[ (’time’ -> 141. (’m’ -> [ ’setMixOnVoice’. (’delta’ -> 2. 0. (’delta’ -> 0.3483). (’m’ -> [ ’setMixOnVoice’. 2.082).722501 ]) ]. (’m’ -> [ ’setVolAt’. Event[ (’time’ -> 141.278048 ]) ].253). 0. Event[ (’time’ -> 141. (’m’ -> [ ’setMixOnVoice’. (’m’ -> [ ’setMixOnVoice’. (’delta’ -> 0. 0.3483).37152).156). (’delta’ -> 0.32508). 2.408). 0.614126 ]) ].Where: Help→Crucial→UncoupledUsefulThings→ZArchive (’time’ -> 134. 0. 0. (’m’ -> [ ’setMixOnVoice’.377152 ]) ]. 0.32058 ]) ].8576).39474).801).882). Event[ (’time’ -> 142. 0.41796). (’delta’ -> 0. (’m’ -> [ ’setMixOnVoice’.173). 0. (’delta’ -> 0.336438 ]) ]. (’delta’ -> 0. 2. 2. 0. (’delta’ -> 0.40709 ]) ]. 0.522007 ]) ]. Event[ (’time’ -> 140.370082 ]) ].142243 ]) ]. (’delta’ -> 0. Event[ (’time’ -> 135. (’delta’ -> 0. 0. Event[ (’time’ -> 137. Event[ (’time’ -> 137. 2. 2. (’m’ -> [ ’setMixOnVoice’.231619 ]) ]. (’delta’ -> 60.39474). Event[ (’time’ -> 136. (’delta’ -> 0. (’delta’ -> 1.551).5577).973). (’m’ -> [ ’setMixOnVoice’.3483). (’m’ -> [ ’setVolAt’.492579 ]) 510 . 0.913).196877 ]) ]. (’delta’ -> 0. Event[ (’time’ -> 134. 2.30186). Event[ (’time’ -> 136. 2.447799 ]) ].761). 2. (’delta’ -> 0.443706 ]) ].51). (’delta’ -> 0.3483).85 ]) ]. 0. (’delta’ -> 0.120907 ]) ]. Event[ (’time’ -> 135.272493 ]) ]. 0. Event[ (’time’ -> 134. (’m’ -> [ ’setVolAt’. Event[ (’time’ -> 135. (’m’ -> [ ’setMixOnVoice’. 2.453). (’m’ -> [ ’setVolAt’.305853 ]) ]. 2.756). (’m’ -> [ ’setMixOnVoice’.67). (’delta’ -> 0.018). (’m’ -> [ ’setVolAt’. (’m’ -> [ ’setMixOnVoice’.37152).

1. Event[ (’time’ -> 212.32508). (’m’ -> [ ’setMixOnVoice’. (’m’ -> [ ’setVolAt’. (’m’ -> [ ’setMixOnVoice’. Event[ (’time’ -> 209.32508).Where: Help→Crucial→UncoupledUsefulThings→ZArchive ]. Event[ (’time’ -> 211. 2.149259 ]) ]. Event[ (’time’ -> 215.614126 ]) ].522007 ]) ].85 ]) ]. 1. (’delta’ -> 1. 1. 1. (’m’ -> [ ’setVolAt’.719819).320578 ]) ]. (’delta’ -> 0.624). (’m’ -> [ ’setMixOnVoice’.998). (’m’ -> [ ’setMixOnVoice’.443706 ]) ]. 0.32508).37152).10881 ]) 511 .471). (’m’ -> [ ’setMixOnVoice’. 0. 1.20744). (’delta’ -> 0. 0.1209 ]) ]. 0.37152). (’m’ -> [ ’setVolAt’. (’m’ -> [ ’setVolAt’. 1. Event[ (’time’ -> 215. (’delta’ -> 0.989). Event[ (’time’ -> 214. Event[ (’time’ -> 212. 1.3483).231618 ]) ]. 0. 1. (’delta’ -> 0. (’delta’ -> 1.39474).206). (’delta’ -> 0.18427 ]) ]. (’delta’ -> 0. (’m’ -> [ ’setMixOnVoice’. Event[ (’time’ -> 214. (’delta’ -> 0.063). Event[ (’time’ -> 214. 0.134333 ]) ]. Event[ (’time’ -> 213. Event[ (’time’ -> 213. 0. Event[ (’time’ -> 213. (’m’ -> [ ’setMixOnVoice’. (’m’ -> [ ’setVolAt’. 0. Event[ (’time’ -> 211. (’m’ -> [ ’setMixOnVoice’.48608).37715 ]) ]. 0.37152).90404). (’delta’ -> 0. 0.41796). (’delta’ -> 0. 1. 1.39474). (’m’ -> [ ’setVolAt’.344). (’m’ -> [ ’setVolAt’. 0.272492 ]) ]. Event[ (’time’ -> 208. 0.737). 1.204744 ]) ]. 1. (’delta’ -> 1.176). 0. (’m’ -> [ ’setMixOnVoice’. 1. Event[ (’time’ -> 209.738). Event[ (’time’ -> 205. (’delta’ -> 1. 0.627).37152). 0.39474). 1. Event[ (’time’ -> 206. (’m’ -> [ ’setMixOnVoice’.165843 ]) ]. 1.957). 1.389).828). 0. 0.44118).541837 ]) ].132). Event[ (’time’ -> 209. (’delta’ -> 0.3483). 1 ]) ].548). 2. (’delta’ -> 0. (’delta’ -> 0.255).59602 ]) ]. (’m’ -> [ ’setVolAt’. (’m’ -> [ ’setVolAt’. 0.92726).503). (’delta’ -> 0.7225 ]) ].861). (’delta’ -> 0. Event[ (’time’ -> 215. (’delta’ -> 0. 1.

1.1.1.1.1.1.1.1. 1.1.1.1.1.writeClose.1.readItem.1.1.1. 1.1.1.1. 1.1.1.1. (’m’ -> [ ’setVolAt’.1.1.1. ) ( b = ZArchive.1.1.1.1.1.1.1. b.1. 1.1.1.1.1.1.1. 1.1. 1.1.1.1.1.1.1. 0.1. 1.1. 1.1.1.1.0979286 ]) ]] ). 1. 1.1.1.1.1.1.1.1.1. 1.916).1.1.1.1.1.1. a.1.1.1. 1.1.1.1.writeItem( [ 1.1.1.1.1.1.1. 1.1.postln.1.1.1.1.1.1.1.1.1.1.write("archiveTest").1.1.1.postln.1.read("archiveTest").1.1.1.1.1.1.1.1.1.1.1.1.1.1.1. b.1.Where: Help→Crucial→UncoupledUsefulThings→ZArchive ].1.1. Event[ (’time’ -> 217.1.1.1.1.close.1.1.1. ) Repetition compression identical values or objects that repeat are compressed.1.readItem. ( a = ZArchive.1.1.1.1.1. 1.1.1.1.1.1. 512 .1.1.1.1.1. a.1.1.1.1. 1.1.1. 1.1. 1.1.1.1.1.1.1.1.1.1.1.1. 1.1.1.1. b.1.1.1.1.1.1.1.1.

1.2.1.1.2.1.2.2.2.2.1.2.1.2.2.1.2.1.1. 2. 1. 1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1. 1.2 ]). 1.1.1.1. 2. 1.1.2.1. 1.1.2.1.2.1.1.1.1.1.1.1.1.2.1.1.1.2. 2.readItem.1. 1. 1.1. a.postln.2. 2.1.2. 1.1.1.1.1. 1.1.1.1.1.2.1.1.1.1.1.2.1.2.2.1.1.1.1.1.2.2.1.2.1.2.1.1.1. 1.1.2.1.1.1. 1. ( b = ZArchive.1.1.1.2.1.1.1.1.1.2.2.1.2.2.1.1.1.1.1.1.1.1.1.2.1. 2.1.1.1. ) this is about 42 bytes.1.2.1.2.1.2.2.1.2.1. ) ( 513 .1.1.1.1.2.1.1.2.1.1.1. Identical objects get reconstituted as equal but independant objects.writeClose.1.1.1.1. 1.1.2.1. b.1.2.1.2.close.1.2.1.1.1.1.1.2.read("archiveTest").2.2.2.1. 2.1.2.1.2.1.2.1.1.1.Where: Help→Crucial→UncoupledUsefulThings→ZArchive 1.1.1.1.1.1.1. 1. b.1.1.2.1.1. 1.1.1.2.

4.writeItem( Event.postln.postln. ) ( b = ZArchive.read("archiveTest").write("archiveTest"). a.make({ a = \a. }) ).writeItem([1. a. b. b.rand).readItem.2.2.close. ) asZArchive relative to your Document directory ( a = "archiveTest".writeClose.5]. a. b = \b. // one more b.readItem.3.writeItem("hello").writeItem(1.writeItem( Ref(4.0.0) ). a.writeItem("word").writeItem(nil).4. a. 514 .3. a.writeItem([1. a.readItem. a.choose). b.5]).postln.Where: Help→Crucial→UncoupledUsefulThings→ZArchive a = ZArchive. a.asZArchive.

0. (’delta’ -> 0. (’delta’ -> 0. 0. Event[ (’time’ -> 150. akv. 0.797). // we know the column objects have their own support columns.writeItem([ IdentityDictionary[ \a -> "b". "b" -> \c ] ]). (’m’ -> [ ’setVolAt’. akv.428).Where: Help→Crucial→UncoupledUsefulThings→ZArchive a.fill( akv.415356 ]) ]. } readZArchive { arg akv.writeItem(beats).writeZArchive(akv) }).{ arg i. 0. ) adding support for your custom class SomeClass { writeZArchive { arg akv. a. (’m’ -> [ ’setVolAt’.336438 ]) ] ]). columns = Array. akv. // turn a path into an archive if needed akv = akv. (’delta’ -> 0.do({| c| c.25).478). a.writeItem(columns.writeItem(beatsPerBar).writeClose.453). 0. 515 .writeItem(name).728). (’m’ -> [ ’setVolAt’. Event[ (’time’ -> 150. akv.writeItem([ Event[ (’time’ -> 149.size).readItem(Integer) . 0.37382 ]) ].asZArchive.

readItem(Float).. beatsPerBar = akv. putInt32 etc. 516 .Where: Help→Crucial→UncoupledUsefulThings→ZArchive // call the custom column object read Tracker. This is because any counted repetitions need to be closed off and written to the file before you start manually putting floats etc.readZArchive(akv) }). (methods of File) but you must call saveCount before starting to use any of these methods.readItem(Float).readItem. you can bypass writeItem (which will write a character to specify the class type) and directly use putFloat. name = akv. // could be an Integer or a String ! beats = akv. } When you have large arrays of floats etc.

7 Files 517 .

see also the superclass for further docs.read and write binary "ab" . If the open fails. so this call is only necessary if you are closing and opening the same file object repeatedly.read and append binary "r+" .read only binary "wb+" . pathname a String containing the path name of the file to open.read and append text "rb" .read only text "w" . mode) Create a File instance and open the file.read and write binary "ab+" . isOpen will return false.read and write text "a+" .Where: Help→Files→File ID: 178 File Superclass: UnixFILE A class for reading and writing files.read and append text "rb+" . 518 . mode a String indicating one of the following modes: "r" .read only binary "wb" .read only text "w+" . Not sound files. *new(pathname.read and append binary open Open the file. Files are automatically opened upon creation.read and write text "a" .

// example. even though you can’t see in file load dialogs or in the Finder. use only for good.rtf". close Close the file.getcwd *use(function) open the file.sucessFunc. readAllString Reads the entire file as a String. *openDialog(prompt.{}. *exists(pathName) answers if a file exists at that path. *delete(pathName) deletes the file at that path. never for evil. readAllStringRTF 519 .{}) not yet implemented *getcwd POSIX standard ’get current working directory’. File. When opening the file you must specify the real filename: "filename.Where: Help→Files→File NOTE: it is possible when saving files with a standard file dialog to elect to "hide the extension" and save it as RTF.cancelFunc) *saveDialog("hello". evaluate the function with the file and close it.

postln. { | f| f. ) 4).close. 3. k = File("test2". g. (k.use("test".do({ k. 3.write( FloatArray[1. k.Where: Help→Files→File Reads the entire file as a String. stripping RTF formatting. ) // read it again: ( g = File("test". f. ( 520 .close.write("Doesn’t this work?\n is this thing really on ?\n").2.write("Does this work?\n is this thing on ?\n"). h = File("test2". 2. h.close.length div: k.readAllString.use("test".sqrt] ).readAllString.1.use: File.inspect.postln }) // more file writing/reading examples: ( var h. "wb")."r"). "w". "r". g. }). f = File("test".close. "rb")."w").getFloat.postln. Examples: // write some string to a file: ( var f. }) File. pi. h. { | f| f.3. ) // try the above with File. h. f. g.

close. g."r")."w").getLine(1024).postln. g = File("test3".postln.inspect.getLine(1024).0.postln.getLine(1024).getLine(1024).Where: Help→Files→File var f. 100.do({ g. $d. }).do({ f. "*".postln. g. f.rand).postln. "***"."r"). g.inspect.close.postln. ) 521 . f.putFloat(1.close."wb").readAllString. "**".postln."rb").choose). g. }). 100.postln. g. f.getFloat.postln.do({ f. $e. g. g.inspect. g. g.postln.putChar([$a. g. 100. ) ( //var f. $\n]. f = File("test3". $c. "****".close. $b.close. g = File("test3". g. }). f = File("test3". g = File("test3". f.

Where: Help→Files→File ( //var f. g.getLine(1024).close. ) 522 . f."r"). f = File("test3".postln.inspect. f. f.

getLine. a unix shell command. Do not rely on the garbage collector to do this for you! Note: due to a bug in the current os x (10. // list directory contents in long format // get the first line while({l. "r"). ) // close the pipe to avoid that nasty buildup 523 . // this pipes in stdout from ls ( var p.3) .close. for now one has to quit the server. and returns nil when done.new("ls -l". p = Pipe. or stdout from. l = p. l. }). Pipe treats the shell command as if it were a UnixFILE.A String representing a valid shell command. otherwise sc crashes. l = p. mode . mode) commandLine . // post until l = nil p.quit. Examples // quit the server s.Where: Help→Files→Pipe ID: 179 Pipe superclass: UnixFILE Pipe stdin to. You must do this explicitly before the Pipe object is garbage collected.A string representing the mode.notNil}. close Closes the pipe. Pipe must be explicitly closed. unix commands like pipe do not work when the server is booted.getLine.postln. Valid modes are "w" (pipe to stdin) and "r" (pipe from stdout). See UnixFILE for details of the access methods. {l. *new(commandLine.

notNil}.net".getLine. l = p. ) // close the pipe to avoid that nasty buildup 524 .postln. }). // post until l = nil p.new("ping -c10 sourceforge. {l. p = Pipe.getLine. l.close. "r"). // get the first line // list directory contents in long format while({l. l = p.Where: Help→Files→Pipe A more time-intensive request: ( var p.

f. Soundfile data can be read and written incrementally. Read/Write openRead(inPathname) 525 . See Server-CommandReference. format.wav").openRead("sounds/a11wlk01. ( f = SoundFile. f. You will not use this class for this.new. so with properly designed code. there is no restriction on the file size.close. f. channels etc.inspect.Where: Help→Files→SoundFile ID: 180 SoundFile In most cases you will wish to send commands to the server to get it to load SoundFiles directly into Buffers. ) Creating new Creates a new SoundFile instance. Some manipulation of the sound file data is possible. This class is used to check the size. when the client needs this information about a SoundFile.

Example: ( f = SoundFile. the array will be populated with floating point values.numChannels_(1). with all values between -1 and 1 to avoid clipping during playback. The size of the FloatArray determines the maximum number of single samples (not sample frames) that will be read. You must have already called openWrite. See the method channelPeaks for example.headerFormat_("AIFF"). When you reach EOF. Regardless of the sample format of the file. the size of the array after the readData call will be less than the original size.a String specifying the path name of the file to read. openWrite(inPathname) Write the header of a file. 526 . Answers a Boolean whether the read was successful. The raw array must be a FloatArray or Signal. readData(rawArray) Reads the sample data of the file into the raw array you supply. The raw array must be a FloatArray. sets the numFrames. You must have already called openRead. inPathname . the floats will all be in the range -1.sampleFormat_("int16"). Answers a Boolean whether the write was successful. inPathname .numChannels and sampleRate. Checking the array size is an effective termination condition when looping through a sound file.a String specifying the path name of the file to write. writeData(rawArray) Writes the rawArray to the sample data of the file.1. For integer formats. the array’s size will be 0. does not set the headerFormat and sampleFormat.new. If there are not enough samples left in the file..Where: Help→Files→SoundFile Read the header of a file.

// sawtooth b = Signal. numFrames. The normalized audio will be written into a second file. if not specified. maxAmp. f. outPath.. the header format of the source file will be used newSampleFormat: the desired sample format of the new file. newSampleFormat. Note: While the normalizer is working. startFrame. (1.sineFill(100. newSampleFormat. if not specified.20). chunkSize) Normalizes a soundfile to a level set by the user.aiff"). linkChannels. numFrames.reciprocal). but it will eventually complete the operation. the sample format of the source file will be used startFrame: an index to the sample frame to start normalizing (default 0) 527 .do({ f. maxAmp. It will look like SuperCollider is hung. there is no feedback to the user.close. startFrame. linkChannels. // write multiple cycles (441 * 100 = 1 sec worth) 441. Arguments: path: a path to the source file outPath: a path to the destination file newHeaderFormat: the desired header format of the new file.Where: Help→Files→SoundFile f. ) isOpen answers if the file is open close closes the file duration the duration in seconds of the file Normalizing *normalize(path. newHeaderFormat. newHeaderFormat. chunkSize) normalize(outPath.openWrite("sounds/sfwrite.writeData(b) }).

Instance Variables <path Get the pathname of the file. The default is 1. Sound File Format symbols: header formats: read/write formats: "AIFF". an array to specify a different level for each channel. You may also openRead the SoundFile yourself and call normalize on it. the source path is omitted because the file is already open. . or entire soundfile) maxAmp: the desired maximum amplitude.no header = raw data 528 .0.normalize) will automatically open the source file for you. if desired. linkChannels: a Boolean specifying whether all channels should be scaled by the same amount. The default is true."RIFF" . to take a floating point soundfile produced by SuperCollider and produce an int16 or int24 soundfile suitable for use in other applications).g. If false.MicrosSoft . each channel’s peak will be calculated independently and all channels will be scaled to maxAmp (this would alter the relative loudness of each channel). . or 16 MB) Using the class method (SoundFile. chunkSize: how many samples to read at once (default is 4194304.NeXT/Sun "IRCAM".old IRCAM format "none" . This variable is set via the openRead or openWrite calls. meaning that the peak calculation will be based on the largest sample in any channel.Where: Help→Files→SoundFile numFrames: the number of sample frames to copy into the destination file (default nil. Provide a floating point number or. <>headerFormat This is a String indicating the header format which was read by openRead and will be written by openWrite. The normalizer may be used to convert a soundfile from one sample format to another (e. .Apple’s AIFF "WAV".. In order to write a file with a certain header format you set this variable.WAV "Sun". In that case.

"int24". <numChannels The number of channels in the file. 529 . "float32" not all header formats support all sample formats. "int16". "int32" "mulaw". <>sampleRate The sample rate of the file. Not all header formats support all sample formats. The possible header formats are: sample formats: "int8".Where: Help→Files→SoundFile A huge number of other formats are supported read only. <numFrames The number of sample frames in the file. "alaw". <>sampleFormat A String indicating the format of the sample data which was read by openRead and will be written by openWrite.

An open request can fail if a file cannot be found for example.seek from end of file.one of the following Integers: 0 . See File and Pipe ( docs incomplete ) isOpen returns whether the file is open. 2 . origin .an offset in bytes. This method lets you test that the open call succeeded.Where: Help→Files→UnixFILE ID: 181 UnixFILE superclass: IOStream An abstract class. offset . length Answer the length of the file. origin) Seek to an offset from the origin. 1 . pos Answer the current file position seek(offset.seek from current position in file. 530 .seek from beginning of file.

writes the name of the Symbol as a C string. Symbol . getInt16 read two bytes and return as an Integer. getInt32 read four bytes and return as an Integer.write the bytes from any RawArray in big endian. item . getDouble 531 . getChar read one byte and return as a Char getInt8 read one byte and return as a Integer.Where: Help→Files→UnixFILE write(item) Writes an item to the file. getLine Reads and returns a String up to lesser of next newline or 1023 chars. Char. Color. getFloat read four bytes and return as a Float.one of the following: Float Integer. RawArray .

putChar write a Char as one byte.Where: Help→Files→UnixFILE read eight bytes and return as a Float. putString write a null terminated String. putDouble write a Float as eight bytes. readAllInt16 532 . putInt8 write an Integer as one byte. readAllInt8 Reads the entire file as an Int8Array. putFloat write a Float as four bytes. readAllString Reads the entire file as a String. putInt16 write an Integer as two bytes. putInt32 write an Integer as four bytes.

readAllDouble Reads the entire file as an DoubleArray. 533 .Where: Help→Files→UnixFILE Reads the entire file as an Int16Array. readAllFloat Reads the entire file as an FloatArray. readAllInt32 Reads the entire file as an Int32Array.

8 Geometry 534 .

Testing 535 . Accessing x get the x coordinate value. inY) defines a new point. inY) Sets the point x and y values.Where: Help→Geometry→Point ID: 182 Point Cartesian point Superclass: Object Defines a point on the Cartesian plane. x_(aValue) set the x coordinate value. set(inX. y_(aValue) set the y coordinate value. Creation new(inX. y get the y coordinate value.

* aPointOrScalar Multiplication. hash returns a hash value for the receiver. scale(aPoint) Multiplication by a Point. translate(aPoint) Addition by a Point. . 536 .Where: Help→Geometry→Point == aPoint answers a Boolean whether the receiver equals the argument. rotate(angle) Rotation about the origin by the angle given in radians. Math + aPointOrScalar Addition.aPointOrScalar Subtraction. / aPointOrScalar Division.

trunc(quantum) truncate the coordinate values to a multiple of quantum. rho return the polar coordinate radius of the receiver. theta return the polar coordinate angle of the receiver. transpose return a Point whose x and y coordinates are swapped. dist(aPoint) return the distance from the receiver to aPoint. Conversion asPoint returns the receiver. asComplex returns a complex number with x as the real part and y as the imaginary part.Where: Help→Geometry→Point abs Absolute value of the point. round(quantum) round the coordinate values to a multiple of quantum. asString 537 .

asShortString return a short string representing the receiver. paramsCompileString represent parameters to ’new’ as compileable strings.Where: Help→Geometry→Point return a string representing the receiver. (See Object::asCompileString) 538 .

inRight. setBy(inLeft. inHeight) 539 . inWidth. inTop. newSides(inLeft. inWidth. inRight. inPoint2) return a new Rect defined by the given Points. inTop. inTop.Where: Help→Geometry→Rect ID: 183 Rect rectangle Class methods: new(inLeft. inBottom) set the boundaries to the given values. set(inLeft. inHeight) return a new Rect with the given upper left corner and dimensions. Instance methods: left top right bottom Get the value of the boundary. inTop. inBottom) return a new Rect with the given boundaries. fromPoints(inPoint1. left_(aValue) top_(aValue) right_(aValue) bottom_(aValue) Set the value of the boundary.

rightTop 540 . leftTop return the upper left corner as a Point. height_(aValue) set the height. width_(aValue) set the width.Where: Help→Geometry→Rect set the upper left corner and dimensions. corner return the lower right corner as a Point. origin return the upper left corner as a Point. width return the width. height return the height. extent return a Point whose x value is the height and whose y value is the width. inHeight) set the dimensions. setExtent(inWidth.

moveBy(x. y). y).Where: Help→Geometry→Rect return the upper right corner as a Point. moveTo(x. y). insetBy(x. y) returns a new Rect whose dimensions have been changed by (x. contains(aPoint) 541 . y) returns a new Rect whose upper left corner is moved to (x. insetRight. leftBottom return the lower left corner as a Point. insetBottom) returns a new Rect whose boundaries have been inset by the given amounts. y) returns a new Rect whose dimensions are (x. moveToPoint(aPoint) returns a new Rect whose upper left corner is moved to aPoint. y) returns a new Rect which is offset by x and y. resizeBy(x. insetTop. y). y) returns a new Rect whose boundaries have been inset by (x. insetAll(insetLeft. resizeTo(x. rightBottom return the lower right corner as a Point.

542 . sect(aRect) &amp.Where: Help→Geometry→Rect answers whether aPoint is in the receiver. union(aRect) | aRect returns a new Rect which contains the receiver and aRect. aRect returns a new Rect which is the intersection of the receiver and aRect.

9 Getting-Started 543 .

Needless to say. while they are being read from. b. but 1. and avoids conflicts.Where: Help→Getting-Started→Buffers ID: 184 Buffers Buffers represent server buffers. The actual number of values stored is numChannels * numFrames. you need to allocate memory to them. but before buffers can be used. Their most common use is to hold soundfiles in memory. They can be written to or even changed in size. Luckily with Buffer. you can do almost anything you want with buffer data. which is an asynchronous step. Also like busses. So each frame is in this case a pair of values. and are the usual way of storing data serverside. Like busses. which means a number with a decimal point. Making a Buffer Object and Allocating Memory Making a Buffer object and allocating the necessary memory in the server app is quite easy. Using Buffer takes care of allocating numbers.0 is a float. and the ability to manipulate data in the client app when needed. starting from 0. but without all the elegant OOP functionality. 544 . buffers are numbered. Many of Buffer’s methods have numerous arguments. This is in contrast to integers. for full information see the [Buffer] help file. So 1 is an integer. and by more than one at a time. 2). Server buffers can be single or multichannel. but any sort of data that can be represented by floats can be stored in a buffer. // allocate 2 channels. so in this case there will be 200 floats. b = Buffer. which is to say that they can be accessed by any synth. and 100 frames // free the memory (when you’re finished using it) The example above allocates a 2 channel buffer with 100 frames.alloc(s. 100. and are written without decimal points. A server’s buffers are global. the number of buffers is set before you boot a server (using [ServerOptions]). like 1. You can do it all in one step with Buffer’s alloc method: s. which are positive or negative whole numbers (or zero). which are ordered arrays of floats on the server.boot. ’float’ is short for floating point number.3.free. You can think of buffers as the server-side equivalent of an Array.

0. // read a soundfile b = Buffer. and returns the Buffer’s number for reallocation. PlayBuf.wav"). which reads a sound file into memory. and returns a Buffer object. You should not use a Buffer object after doing this.free.[\bufnum. "sounds/a11wlk01. ) x. but for now lets just concern ourselves with the first three. you can do so like this: b = Buffer.bufnum ]). Using Buffers with Sound Files Buffer has another class method called ’read’. PlayBuf. Take a look at the [PlayBuf] helpfile for details of them all.read(s. b.sampleRate * 8.free. Buffer’s ’free’ method frees the memory on the server. You cannot make this an argument in the SynthDef and change it later. bufnum.ar( 1.ar has a number of arguments which allow you to control various aspects of how it works. PlayBuf.ar( out. bufnum. s. // an 8 second stereo buffer b. Out.kr(bufnum)) ) }). b.kr(bufnum) ) Number of channels: When working with PlayBuf you must let it know how many channels any buffer it will read in will have. BufRateScale. Using the UGen PlayBuf.ar(1. Why? Remember that SynthDefs must have a fixed 545 .Where: Help→Getting-Started→Buffers If you’d like to allocate in terms of seconds. 2).alloc(s. we can play the file.play(s. // now play it ( x = SynthDef("tutorial-PlayBuf". bufnum. rather than frames.{ arg out = 0. used in the example above. // number of channels // number of buffer to play // rate of playback BufRateScale.free.

cueSoundFile(s. [\bufnum.new("tutorial-Buffer-cue". y = Synth. you might not want to load a sound completely into memory. etc.) Rate of Playback: A rate of 1 would be normal speed. So a one channel PlayBuf is always a one channel PlayBuf. What this does is check the samplerate of the the buffer (this is set to correspond to that of the soundfile when it is loaded) and outputs the rate which would correspond to normal speed. which is usually 44100 Hz. Buffers are numbered. More on Instance Variables and Action Functions 546 .wav) actually has a samplerate of 11025 Hz.ar( 1.bufnum]. Streaming a File in From Disk In some cases. This is done at the end of the SynthDef above.aiff". Out. This is useful because the soundfile we loaded (a11wlk01.bufnum."sounds/a11wlk01-44_1. just like Synth-new. y.send(s).b. Instead. but can save memory. using the UGen DiskIn. for instance when working with very large files. If you need versions that can play varying numbers of channels then make multiple SynthDefs or use Function-play.Where: Help→Getting-Started→Buffers number of output channels. Bufffer Number: As noted above. b. DiskIn. and Buffer’s ’cueSoundFile’ method: ( SynthDef("tutorial-Buffer-cue". starting from zero. ) b = Buffer. where it is passed in as an argument to the resulting Synth. But here we see a UGen called BufRateScale.{ argout=0. 1). 0. PlayBuf would play it back using the sampling rate of the server.free. bufnum ) ) }). 2 twice as fast.ar(out. you can stream it in from disk a bit at a time. s). This is not as flexible as PlayBuf (no rate control). You can get a Buffer’s number using its ’bufnum’ method.free. (Note that SynthDef-play allows you to include an array of arguments. With a rate of 1. or four times as fast! BufRateScale thus brings things back to normal.

x = { PlayBuf. Remember that individual Objects store data in instance variables.numFrames). ) x. Now (like with the example using an action function in our Bus-get example.free.numFrames. b.wav".read(s. and has updated the Buffer’s vars. Remember that an action function is just a Function that will be evaluated after the client has received a reply. In the example above. instance variables will not be immediately updated when you do something like read a file into a buffer. which allow you to get or set their values.postln.Where: Help→Getting-Started→Buffers Now a little more OOP.numChannels.bufnum. Some instance variables have what are called getter or setter methods. Buffer has a number of other instance variables with getters which can provide helpful information. It is passed the Buffer object as an argument. which is a getter for its buffer number instance variable. b. "sounds/a11wlk01. For this reason. b. the client sends the read command to the server app.postln. ("numFrames after update:" + buffer. // with an action function // note that the vars are not immediately up-to-date ( b = Buffer.play. b. These can be particularly useful when working with sound files. numFrames. BufRateScale.bufnum. }). b.numFrames). and sampleRate.sampleRate. see [Busses]) because of the small messaging latency between client and server.ar(1. along with 547 . We’ve already seen this in action with Buffer’s ’bufnum’ method. buffer. as we may not have all this information at our fingertips before loading the file.free. b.wav").bufnum)) }. many methods in Buffer take action functions as arguments.read(s.kr(buffer. The ones we’re interested in at the moment are numChannels. // watch the post window b = Buffer.free. action: { arg buffer. // Note that the next line will execute BEFORE the action function ("numFrames before update:" + b. "sounds/a11wlk01.

[\out.bufnum=0.ar(out. playbuf = PlayBuf. Accessing Data Buffer has a number of methods to allow you to get or set values in a buffer. ) // free the record synth after a few seconds x. Buffer-get 548 .Where: Help→Getting-Started→Buffers a request for the necessary information to update the Buffer’s instance variables.bufnum]).play(s. 0. var playbuf. // play it back ( SynthDef("tutorial-playback". It then cues the action function to be executed when it receives the reply.kr(playbuf). \bufnum.bufnum]). and continues executing the block of code.free. // frees the synth when the PlayBuf has played through once Out.[\out.bufnum). ) b.. which lets you record into a buffer. // record some PinkNoise // by default this loops RecordBuf.ar(1. \bufnum. b. there’s a UGen called RecordBuf. s.. // a 5 second 1 channel Buffer // record for four seconds ( x = SynthDef("tutorial-RecordBuf".alloc(s.{ arg out=0. 1). var noise. b. noise = PinkNoise. That’s why the ’Before update.ar(0.sampleRate * 5. See the [RecordBuf] help file for details on all of its options.’ line executes first. }).3). }).free. 0. bufnum). b = Buffer.bufnum=0. playbuf). FreeSelfWhenDone. Recording into Buffers In addition to PlayBuf.{ arg out=0.play(s.ar(noise.

rand2}). b. b.2 }.rand})).alloc(s. and so on.free. 549 .setn(0. index 2 = frame2-chan1.numChannels. 3]).numFrames.bufnum). 2. 44100). ’getn’ takes a starting index. 8.5 b. To overcome this Buffer has two methods.fill(b. Array. {| msg| b.fill(44100. then play it b. the number of values to get. b. ’setn’ takes a starting index and an array of values to set. This is because of a limit on network packet size.postln}).Where: Help→Getting-Started→Buffers and Buffer-set are straightforward to use and take an index as an argument.postln}). index 1 = frame1-chan2. // get them There is an upper limit on the number of values you can get or set at a time (usually 1633 when using UDP. b = Buffer.kr(buf.setn(0. {1. the default). BufRateScale. ’get’ takes an action function. 1). {| msg| msg. ) x. and an action function.getn(0.free. }).ar(buf.bufnum. 0.0. {| msg| // set the first 3 values msg. // fill the buffer with random values b. {1. msg. // set the value at 7 to 0. // get them b. Multichannel buffers interleave their data. b. ) ( // load the FloatArray into b.play.get(7. [1.getn(0. // get the value at 7 and post it when the reply is received b. ’loadCollection’ and ’loadToFloatArray’ which allow you to set or get large amounts of data by writing it to disk and then loading to client or server as appropriate.alloc(s. b = Buffer. ( // make some white noise v = FloatArray.free. action: {| buf| 1) x = { PlayBuf. loop: * 0. buf.16). so for a two channel buffer index 0 = frame1-chan1.alloc(s. b = Buffer. 3.5).0.set(7.loadCollection(v.postln}). The methods ’getn’ and ’setn’ allow you to get and set ranges of adjacent values.numFrames.

Line. this posts ’true’ // the args 0. x.free. // play the contents // this takes one arg: // freed automatically b.kr(0. {| floatArray| b.plot.1. and compare it to v. ( x = play({ Shaper.free."sounds/a11wlk01.ar(300.1]). One example of another use for them is as a lookup table for waveshaping. A FloatArray is just a subclass of Array which can only contain floats.free. If false (the default) the resulting synth is x = b. b.cheby([1. // frees itself // loops so doesn’t free loop.loadToFloatArray(0.ar( b. buffers are also useful for any situation in which you need large and/or globally accessible data sets on the server. 0. b = Buffer.alloc(s.Where: Help→Getting-Started→Buffers // now get the FloatArray back. b.play(true). (floatArray == v).play.wav").postln }). 0. -1. SinOsc.1.read(s.bufnum. 1). -1 mean start from the beginning and load the whole buffer b.5 ) }).0.6)). b. Other Uses For Buffers In addition to being used for loading in sound files. ) 550 . Plotting and Playing Buffer has two useful convenience methods: ’plot’ and ’play’. // see the waveform b = Buffer.1. 512.0.

which are needed for this. You’ll encounter them throughout the documentation. b.free.) Buffer has many similar methods for filling a buffer with different waveforms.free. The method ’cheby’ fills the buffer with a series of chebyshev polynomials. The Shaper UGen performs waveshaping on an input source. Click here to return to the table of Contents: [Getting Started With SC] 551 . For more information see: [Buffer] [PlayBuf] [RecordBuf] [SynthDef] [BufRateScale] [Shaper] ____________________ This document is part of the tutorial Getting Started With SuperCollider. There are numerous other uses to which buffers can be put.Where: Help→Getting-Started→Buffers x. (Don’t worry if you don’t understand all this.

e. if we imagine a server with two output channels and two input channels (i. The remaining audio busses will be ’private’. Sending audio to a private bus will not result in sound in your speakers unless you reroute it later to one of the output busses.) Writing to or Reading from Busses We’ve already seen Out. the former routes audio rate signals and the latter routes control rate signals. In SC this means to or from the audio hardware.Where: Help→Getting-Started→Busses ID: 185 Busses Now a little bit more about busses on the server. with outputs coming before inputs. play out) audio to a bus. which can be an array of UGens (i. stereo in and out) then the first two audio busses (index 0 and index 1) will be the outputs.(See [ServerOptions] for information on how to set the number of input and output channels. but require slightly more explanation. As you’ve probably guessed.e. something that requires further processing before it’s output. They come in two types: audio rate and control rate. and the two immediately following those (index 2 and index 3) will be the inputs. Audio rate busses are similar. a multichannel output) or a single UGen. These are used simply to send audio and control signals between various synths. as well as the number of input and output channels is set at the time the server app is booted. For example.e. and busses. an index.e. and reading audio in from the input busses will get sound into SC for things like recording and processing (providing you have a source such as a microphone connected to your computer’s or audio interface’s inputs). and an output. These ’private’ busses are often used for things like an ’effects send’. i. each one has an index number. These correspond to the first audio busses. The number of control and audio busses available.ar. The control rate busses are fairly simple to understand. Busses are named after the busses or sends in analog mixing desks. Recall that it has two arguments. starting from 0. 552 . which allows you to write (i. A server app will have a certain number of output and input channels. Writing audio out to one of the output busses will result in sound being played from your speakers. and they serve a similar purpose: Routing signals from one place to another. or between different synths.

0.ar(out. 0. Execute the following examples.ar(freq.kr(0. and watch the post window: In.scope. out = 0.boot. {Out. {Out. Out. which will read and write control rate signals to and from control rate busses.kr)}. 1). If the number of channels is greater than one. SinOsc. In and Out also have ’kr’ methods.kr will convert an audio rate signal to control rate (this is called ’downsampling’). ( SynthDef("tutorial-args".internal. filling in the extra values through a process called interpolation. { arg freq = 440. Some will even convert control rate inputs to audio rate if needed. }). ) // both write to bus 1.Where: Help→Getting-Started→Busses To read in from a bus you use another UGen: In. and the number of channels to read in.play. or in other words. there output is summed. SinOsc. Note that Out. than In’s output will be an Array.ar needs an audio rate signal as its second arg. Can’t write a control rate signal to an audio rate bus // This will work as the audio rate signal is downsampled to control rate Server.ar(0.2)). and their output is mixed 553 . 4). // this will return ’an OutputProxy’ In. (This limitation is not universal amongst audio rate UGens however. SinOsc. mixed. and most will accept control rate signals for some or all of their arguments.ar(0.ar(0. so don’t worry about them. You’ll probably never need to deal with one directly.ar)}. In’s ’ar’ method also takes two arguments: An index. // This throws an error.send(s). // this will return an Array of 4 OutputProxies An OutputProxy is a special kind of UGen that acts as a placeholder for some signal that will be present when the synth is running. but that the reverse is not true: Out.) You’ll note that when multiple Synths write to the same bus. just understand what they are so that you’ll recognise them when you see them in the post window and elsewhere.

since we haven’t mentioned these before.2). Well. // Get a two channel control Bus c = Bus. outArray). ["out". Bus has two commonly used creation methods: Bus-audio and Bus-control. Creating a Bus Object There is a handy client-side object to represent server busses: Bus.ar(0. Given that all you need is an In or Out Ugen and an index to write to a bus. Out. "freq". 660]). but first lets look at how to make one. 0.new("tutorial-SinOsc-stereo". You could do this by carefully considering which indices to use. and when you 554 . The encapsulate several adjacent sever-side busses into a single Bus object. SinOsc. 770]). "freq". This turns out to be rather handy. much of the time you don’t.audio(s). and the number of channels. Recall this example from [SynthDefs and Synths]: ( SynthDef. 1. you might wonder what one would need a full-fledged Bus object for. 0. 0. b = Bus.ar(440. allowing you to treat them as a group. These each take two arguments: a Server object. But Bus does provide some useful functionality.2)]. anything besides the input and output channels. ) The truth is that there aren’t multichannel busses per se. We’ll get to that in a second. When you’re working with so-called ’private’ busses (i. all control busses are private) you generally want to make sure that that bus is only used for exactly what you want.play.control(s.Where: Help→Getting-Started→Busses x = Synth("tutorial-args".ar(442. // writes to busses 0 and 1 }). The point after all is to keep things separate. particularly if all you’re doing is playing audio in and out.e. Just as many UGens have ar and kr methods. You should recall that when Out has an Array as its second argument it will write the channels of the Array to consecutive busses. ["out". but Bus allows for this to be done automatically. Each Server object has a bus allocator. but Bus objects are able to represent a series of busses with consecutive indices. 0. outArray = [SinOsc. y = Synth("tutorial-args". 2). 1. { varoutArray. // Get a one channel private audio Bus (one is the default) You may be wondering what a ’two channel’ bus is.

index. 2). But what happens if we later decide to change the number of output channels to 6? Now everything that was written to our private bus is going out one of the output channels! A Server’s audio bus allocator will only assign private indices. since the indices need to be consecutive! This is a good example of the power of objects: By encapsulating things like index allocation. You can find out the index of a Bus by using its ’index’ method. and give the appropriate Out UGen 4 as its index arg. you can guarantee that there won’t be a conflict. Now here’s another advantage when working with private audio rate busses. As we said above. 2. Since the indices are allocated dyamically. (0. This allows them to be reallocated.numChannels // this should be zero // Bus also has a numChannels method c = Bus. s. // a 2 channel control Bus b. b uses 0 and 1 So by using Bus objects to represent adjacent busses. b. If you were simply ’hard allocating’ busses by using index numbers. so if you change the number 555 . it reserves those private indices. c. it’s still there. 1. right? Consider our server app with 2 output and 2 input channels. and will not give them out again until freed. 2). // this will restart the server app and thus reset the bus allocators b = Bus.control(s. b = Bus. all we need to do is add those together.free.index. b. and you’re still guaranteed to be safe. You can’t use this Bus object after that Note that this doesn’t actually make the bus on the server go away. So if we want to use the first private bus. c. they can make your code more flexible. and it can freely reallocate its index. // free the indices.control(s)..numChannels.control(s. You can free up the indices used by a Bus by calling its ’free’ method. 3 . ’free’ just lets the allocator know that you’re done using this bus for the moment. 4!) So we write our code. The first private audio bus is index 4. the first few busses are the output and input channels.Where: Help→Getting-Started→Busses make a Bus object. // the default number of channels is 1 // note that this is 2.reboot. you might have to adjust them all to make room for an extra adjacent channel. you can change the number of channels of a Bus in your code (for instance because you now need to route a multichannel signal).. and providing a layer of abstraction.

after(x. This is more efficient than having two separate control oscillators to control frequency. ( SynthDef("tutorial-Infreq". Again this makes your code more flexible. each of which does different things in a larger process.ar(In. can be very effective in SC. Busses in Action So here are two examples using busses. b.after(x. [\bus.index]). freq)).index. // this will add freqOffset to whatever is read in from the bus Out.free. b = Bus. SynthDef("tutorial-Outfreq". This sort of strategy of connecting together synths. b. 0. z. Both y and z read from the same bus. { arg freq = 400. bus. 556 . b. y.control(s. "tutorial-Infreq".free. 0.ar(0. the latter just modifies the frequency control signal by adding a constant value of 200 to it.kr(bus.5)). ) ( x = Synth.kr(1.Where: Help→Getting-Started→Busses of input or output channels it will take this into account when you execute your code. "tutorial-Infreq". }). which is a kind of delay. \freqOffset. freq/40.free.free. This is the most complicated example we’ve seen so far. 200]). [\bus. Now an example with an audio bus.new("tutorial-Outfreq". These are then reverberated using a chain of [AllpassC]. y = Synth. 0. }). [\bus. SinOsc.send(s).index]).1). SinOsc. ) x. Out. one creating pulses of PinkNoise (a kind of Noise which has less energy at high frequencies than at low). { arg bus. z = Synth. The pulses are created using the UGens [Impulse] and [Decay2]. freqOffset = 0. The code below will use two Synths as sources. and another creating pulses of Sine Waves. The first is with a control rate bus. but should give you some idea of how to start putting all the things we’ve learned together. b.kr(bus) + freqOffset.send(s).

ar). so this makes a stereo reverb 16.do will evaluate it’s function argument a corresponding number of times // {}. source * direct).04. This makes the chain by evaluating the function 16 times.001. // this will be our main output Out. PinkNoise.send(s). as by simply changing the number. direct = 0.ar(Impulse. 0. SynthDef("tutorial-Reverb". See [Integer] for more info on Integer-do.25). source * (1 .dup. }). var input.send(s). direct = 0. // this will be our effects output Out. This is a very powerful and flexible technique..ar(inBus. source * (1 .ar(effectBus.2. }). { arg outBus = 0.direct)). }). and return an Array of the results // The default for n is 2.2.25). { arg outBus = 0.kr(0. I can change the number of evaluations.do({ .ar(effectBus. effectBus. 0.0. // Decaying pulses of a modulating Sine wave.5.ar(input. var source. ( // the arg direct will control the proportion of direct to processed signal SynthDef("tutorial-DecayPink". var source.01.send(s). 3)}).do({ input = AllpassC. source = Decay2. SinOsc. 0. // this will be our main output Out. 110. SynthDef("tutorial-DecaySin". source = Decay2.Where: Help→Getting-Started→Busses Note the construction 16. 440))). 0.. inBus. below. 557 . 0. We’ll add reverb later. // a low rent reverb // aNumber. input). effectBus.04) }.5. Out. We’ll add reverb later. }).dup(n) will evaluate the function n times. { arg outBus = 0. { Rand(0. input = In.ar(outBus. 0.ar(1.direct)).ar(outBus.3.ar(outBus.ar(Impulse. // Decaying pulses of PinkNoise.3. // this will be our effects output Out. source * direct). 1. 0.ar(SinOsc.ar(0. 1).

"tutorial-DecaySin".1)). 1). // only reverberated Sine wave x. b. But by using a private bus. b. 1]). "tutorial-DecayPink". }).set(\direct. b. y = Synth. Note that we could easily have many more source synths being processed by the single reverb synth.free. ) // Now map freq1 and freq2 to read from the two busses x. [\inBus.Where: Help→Getting-Started→Busses b = Bus. b = Bus. [\effectBus. c. [\effectBus. 558 . 0).free. For instance. 1). y. SinOsc. \freq2. and poll values using its ’get’ method.free. You can also write constant values to control busses using Bus’ ’set’ method.set(\direct. ) // Change the balance of wet to dry y.audio(s.before(x. // only reverberated PinkNoise z.set(\direct.map(\freq1. // and make a synth with two frequency arguments x = SynthDef("tutorial-map".1).control(s. 0). 1).set(880).set(\direct. { arg freq1 = 440. b. we’re able to be more efficient.new("tutorial-Reverb". z.index]). Out. // this will be our effects bus ) ( x = Synth. This means you don’t need an In UGen. freq2].ar([freq1. // only direct PinkNoise z. More Fun with Control Busses There are some other powerful things that you can do with control rate busses. you can map any arg in a running synth to read from a control bus. 1).before(x.index.set(884). // only direct Sine wave y. freq2 = 440.control(s.ar(0.index. If we’d built the reverb into the source synths we’d be duplicating effort. b.play(s).index]). b. z = Synth.index).free. ( // make two control rate busses and set their values to 880 and 884. c = Bus. \outBus. 0. 0. c.

kr(b. b. b.index.postln. 1). // free y.get({ arg val. val. SinOsc.control(s. Watch the post window // set the freq2. This concept of things taking a small amount of time to respond (usually called latency ) is quite important to understand.get({ arg val.postln. // just to be sure b.free.kr(1. // execute this altogether ( f = nil. 880))}. so setting c to a different value has no effect c.Where: Help→Getting-Started→Busses // Now make a Synth to write to the one of the busses y = {Out. and b holds its last value y. and it can cause you problems if you’re not careful. f = val.free. f = val. 0. c.free. f / 2). ) 559 . this ’unmaps’ it from c x.free. There are a number of other methods in SC which function this way. // freq2 is no longer mapped. 50. which is passed the value (or Array of values in the case of a multichannel bus) as an argument. }).set(\freq2. // make a Bus object and set its values b = Bus.play(addAction: \addToHead). To illustrate this consider the example below. This is because it takes a small amount of time for the server to get the reply and send it back. x. allows you to do something with the value once its come back.set(880). // use Bus-get to see what the value is. The function. Note that unlike audio rate busses. control rate busses hold their last value until something new is written. b.set(200). f. Also note that Bus-get takes a Function (called an action function) as an argument. }).

as we were only executing a line at a time. so by the time we get around to executing the last line of code f has been set to 880. you may have wondered about things like Synth.) This synth’s output is written to a bus or busses. Getting it all in the Right Order In the examples above. This is a complicated topic. according to its list of running synths. and calculates a block of samples for its first UGen. when you tell it to.postln. 560 . The server then moves on to the next synth in its list. For instance in the audio bus example above it was important that the ’reverb’ synth is calculated after the noise and sine wave synths that it processes. and then moves on to posting f. schedules the Function to execute when a reply is received. but you should be aware that ordering is crucial when interconnecting synths. as fast as it can. and the process repeats. The file [Order-of-execution] covers this topic in greater detail. It starts with the first synth in its list.Where: Help→Getting-Started→Busses // f equals nil. and there are some exceptions to this. as we expected. It then takes that and calculates a block of samples for each of its remaining UGens in turn (any of which may take the output of an earlier UGen as an input. So why was f nil the first time but not the second time? The part of the language app which executes your code (called the interpreter ). But there will be cases where you will need to execute things as a block. when you are connecting synths together using busses it is important that synths which write signals to busses are earlier in the server’s order than synths which read those signals from those busses. So in the block of code between the parentheses above it sends the ’get’ message to the server. does what you tell it. Since it hasn’t received the reply yet f is still nil when it’s posted the first time. until all running synths have calculated a block of samples. and addAction: \addToHead. The important thing to understand is that as a general rule. and the action function technique is very useful for that. In the previous example this wasn’t a problem. but try it again and it’s as we expected! f. It only takes a tiny amount of time for the server to send a reply.after. as the case may be. At this point the server can move on to the next cycle. During each cycle (the period in which a block of samples is calculated) the server calculates things in a particular order.

Methods like Synth-after are simply convenient ways of doing the same thing. ____________________ This document is part of the tutorial Getting Started With SuperCollider. the difference being that they take a target as their first argument. // These two lines of code are equivalent y = Synth. See [Synth] for a complete list of possible addActions. x.Where: Help→Getting-Started→Busses Synth-new has two arguments which allow you to specify where in the order a synth is added. Click here to go on to the next section: [Groups] Click here to return to the table of Contents: [Getting Started With SC] 561 . [\freq.free. When doing so be mindful of their ordering on the server. and the second is an addAction. y. more on that soon). \addAfter). \addAfter). [\freq.after(x. // add a second synth immediately after x y = Synth("default". [\freq. The first is a target. 450]. x. x. "default". [\freq. The latter specifies the new synth’s position in relation to the target. 450]). y = Synth. 450].free. 300]). and an addAction is a symbol. x = Synth("default". For more information see: [Bus] [In] [OutputProxy] [Order-of-execution] [Synth] Suggested Exercise: Experiment with interconnecting different synths using audio and control busses. A target can be another Synth (or some other things.new("default".

34 seconds compile done RESULT = 256 Class tree inited in 0.. The ’enter’ key is the one that is on the number pad. wherever it prints text. you should see this in the post window. If all went well. just keep in mind that this is where SC will send you information. The post window is the one that opened up when you first started SC. or you can hold down the ’fn’ or function key.14 seconds ’/Applications/SC3/SCClassLibrary’ Don’t worry too much about what all that means just now. This just makes the program print the text ’Hello World!’ to well. In SC that’s a place called the post window. To execute it. and press ’return’. It’s also where we’ll get the result of our Hello World program. and a bunch of stuff was printed there which looks something like this: init_OSC compiling class library. Try this now. Note that the ’enter’ key is not the same as the ’return’ key.postln. simply click to place the cursor on the same line as the code and then press the enter key. 562 . NumPrimitives = 587 compiling dir: pass 1 done Method Table Size 3764776 bytes Number of Method Selectors 3184 Number of Classes 1814 Number of Symbols 7595 Byte Code Size 180973 compiled 296 files in 1. On Mac laptops there is usually a separate enter key down at bottom of the keyboard towards the right.Where: Help→Getting-Started→First_Steps ID: 186 First Steps Hello World. which you can see below: "Hello World!". I’m SuperCollider It is traditional when learning a new programming language to start with a simple program called ’Hello World’.

postln. "Ishmael. If we didn’t have a semi-colon between the two lines we would get an error.postln. ( "Call me. Select both lines of text by clicking and dragging over them. . is a kind of Object. and then press enter. The first line.postln. You can apply it to almost anything in SC and get something meaningful back. when you execute code in SC. "Hello World!".. but for now just understand that a String is a way of representing a bit of text. This can be very handy when tracking down bugs in your code. Try it out on the example below.postln. Why did it print twice? Well. "Hello SC!". ) When code is not surrounded by parentheses it is generally intended to be executed one line at a time. "Hello World!". it always posts the last thing executed. More about that later.".Where: Help→Getting-Started→First_Steps Hello World! Hello World! Now let’s take a closer look at the code. Note also that each line of code ends with a semi-colon.postln. it’s your friend. In general when you are meant to execute several lines of code at the same time they will be surrounded by parentheses. This is how you separate lines of code in SC. says ’print me (or a meaningful description of me) to the post window.’ Remember postln. 563 . So in this case we didn’t really need the postln bit. This is convenient as it allows you to select the whole block of code by double clicking just inside one of the parentheses. The second bit. called a String. But in the following example we would. as in the example below. that allows you to control it and send messages to it. An object is basically just a way of representing something in the computer. for instance a bit of text. ’Hello World’ would not have printed if we didn’t have the explicit postln.". The first bit. or an oscillator.

In this case of course. It’s very useful to be able to see it.postln. sometimes the post window becomes full of stuff and hard to read.".postln. The Command key is the one with the and symbols on it. A couple of more notes about the post window. "Ishmael?". The World According to SuperCollider 564 . as it’s how SC knows where to separate commands./. This can be handy for execution. and then press k). With an error of this kind. so that’s where you should look. ) Executing the code above results in a ’Parse Error’. "Call me ". and pressing \. Without a semi-colon above. As well. Usually the problem actually occurs a little before that. ( "Call me?". Using semi-colons it’s possible to have more than one line of code in the same line of text. You can bring it to the front at any time by holding down the Command key.Where: Help→Getting-Started→First_Steps Note that each of the lines within the block of code ends with a semi-colon. By convention this kind of key sequence is written Cmd . • ERROR: Parse error in file ’selected text’ line 3 char 11 : "Ishmael.postln "Ishmael. Here it happens just after "Ishmael. the dot • in the error message shows you where SC ran into trouble."•. This is very important when executing multiple lines of code.". it’s the lack of a semi-colon at the end of the previous line. You can clear it at any time by pressing Cmd-shift-k (hold down the command key and the shift key. but sometimes it can get hidden behind other windows. you would get an error posted.post.postln.

lean. which does the actual synthesis and calculation of audio. Most of the time they will be running on the same machine. nice GUI features and a sophisticated programming language. which are network protocols also used on the internet.. The former is a graphical application with menus. Do this with both blocks of text wrapped in parentheses. For more information see: [How-to-Use-the-Interpreter] [Literals] [String] [ClientVsServer] [Server-Architecture] Suggested Exercise: Open a new window by pressing Cmd-n or selecting ’New’ from the File menu. efficient UNIX command line application (meaning it runs without a nice modern GUI). over either UDP or TCP. or use the Edit menu.Copy some of the posting code from the examples above and paste it into the new document. so we’ll be talking about that in some depth. which is what you’re looking at now. But first let’s have a little fun. Don’t think from this that the two applications must run on different computers (they can. but luckily the language app has lots of powerful objects which represent things on the server and allow you to control them easily and elegantly. (The standard Mac Cmd-c and Cmd-v work for copy and paste. so it’s always a good idea to copy text over before changing it so as to avoid accidentally saving altered files! Experiment with altering the text between the quotes to print different things to the post window. or that they need to be connected to the internet (although it is possible to have clients and servers in diffferent parts of the world communicating!!). which can have definite performance advantages). ____________________ 565 . The two communicate by a protocol called Open Sound Control (OSC).. Understanding how exactly that works is crucial to mastering SC. and the latter is a mean.Where: Help→Getting-Started→First_Steps SuperCollider is actually two programs: The language or ’client’ app. and the ’networking’ aspect of things will be relatively transparent for you. and make some sound. You can only communicate with the server using OSC messages over the network. document windows. and the server. and single lines.) SC will let you edit the help files and documentation.

Click here to go on to the next section: [Start Your Engines] Click here to return to the table of Contents: [Getting Started With SC] 566 .Where: Help→Getting-Started→First_Steps This document is part of the tutorial Getting Started With SuperCollider.

Execute the following lines one at a time and watch the post window: f = { "Function evaluated". Below is a simple example of this. 0. This will always stop all sound in SC. You define a Function by enclosing code in ’curly brackets’: { }. and this is just a simple example to demonstrate Functions and sound.postln. We’ll take it apart a bit below. i.postln.ar(440.. Execute this (after making sure the server is booted).ar(442. Basically it allows me to name the Function I’ve created. That’s in fact what makes it reusable! Otherwise we’d need to type the Function in every time.}. A Function is just a reusable bit of code.2)] }. Not too inspiring? Don’t worry. and when you’re sick of it. it’s what’s called an assignment. A variable is just a name representing a slot in which we can store things. So how do we reuse it? Execute the following lines one at a time and watch the post window: 567 . so commit it to memory. 0. a list.e. Before we get to doing that though..Where: Help→Getting-Started→Functions_and_Other_Functionality ID: 187 Functions and Other Functionality The easiest way to get sound from SC is to use a Function. { [SinOsc. }. (that’s hold down the command key and press the period or fullstop key) to stop the sound. SinOsc. 0. let’s learn a little about Functions in general. This is not an equation in the mathematical sense. The stuff within the curly brackets is what will get executed each time you reuse.2). Here’s an example: f = { "Function evaluated". You’ll be using it a lot. we’re just getting started. f. press Cmd . Both times it should say ’a Function’. such as a Function. a number. }. Now whenever we want to refer to our Function we can just use the letter f.play. f = {.. by storing it in a variable called ’f’. etc. 0. Note that this is written like an equation. or evaluate the Function.

Now this next bit is a little bit tricky. This is an example of sending a message to an object. // Here I make f equal to a number // Post window says: // Still says 3 3. and thus respond to the same message in different ways. 2 + 3.value.) f = 3. Whoah. f. (Everything to the right of the // is a ’comment’. The example below will return the number 5. When you call the method ’value’ on a Function it will evaluate and return the result of its last line of code. they become interchangeable in your code. such as a value or a result. }. as this is pretty important: Different types of objects may have methods with the same name. get that? Read it again slowly.0. f.value. When you ’call’ a method. All objects in SC respond to the message ’value’.Where: Help→Getting-Started→Functions_and_Other_Functionality f = { "Function evaluated". What’s interesting about this is that the actual methods may differ in what they do.postln. A good example is ’value’.. which we have defined and stored in the variable ’f’. Our Function is an object. f. // Here it’s a Function..e it returns itself f = { 3. (i. which means that SC just ignores it.someMessage. it always ’returns’ something.". }.value’ says evaluate this function now.value. 568 .value. Often methods simply return the object itself. f = { "Evaluating. }.rand. Different types of objects may have methods with the same name. This is the case with most objects and the message ’value’. The bit of code that says ’.value. Comments are a good idea to make your code clearer. In a given object. f. f. each message calls (calls means executes) a particular method. i.value. f. The example below demonstrates this. This follows the syntax someObject. The dot must go in between. but as long as they implement a method with that name.postln. and thus respond to the same message in different ways.e a thing that does something or represents something).

) Arguments are declared at the beginning of the Function.rand. // here the arg is a Function. as it’s called for short) just means programming with objects.value(10. f. f. f.Where: Help→Getting-Started→Functions_and_Other_Functionality f. you can pass in arguments. by putting them in parentheses: someFunc. yes? Here’s another short example showing this in action: f = { arga. b. using the keyword ’arg’. This is the same with any method that takes arguments. // 3. a .0.0.value + 3 }.value. which is one of the powerful features of what’s called Object Oriented Programming. The example below demonstrates how this works. f.value(g). ( f = { arg a. // call ’value’ on the arg. huh? // try it again. Simple. a. 2).value(arg1.value(g). // 3. a / b. See if you can guess what the result will be before executing it. f. Object Oriented Programming (or OOP. }.value(3). You can specify different orders by using what are called keyword arguments: f = { arg a. Polymorphism just means that different objects are interchangeable (at least providing they return something sensible for what you’re doing) if they respond to the same message.0 exclusive. // something different // something different This means that by using the ’value’ method Functions and other objects can be interchangeable in your code. f. b.b.value(5. These are values which are passed into the Function when it is evaluated. in order.value. 3). polymorphism awaits! f. arg2). Cool. }. This is an example of polymorphism. // ’/’ means divide // regular style 569 .value = 3. so this returns 3 + 3 = 6 g = { 3.value. You can then refer to them just like variables. different result Start to see how this could be useful? Functions can also have what are called arguments.rand means return a random value from 0 to 3. When you call value on a Function. not just value. }.

You can also have variables in a Function. ( f = { arg a.value(2.value(b: 2. just after the args. which can make writing code a little faster. 570 .value(2).e.g. which is to enclose them within two vertical lines. a: 10). e. }. }.1 (Note that SC has no operator precedence. g. b = 2. }. d. (On most keyboards the vertical line symbol is Shift-\) The following two Functions are equivalent: f = { arg a. 4 + (2* 8) ) Sometimes it’s useful to set default values for arguments. To force an order use parentheses.value(2. 2). symbols (more on these later). it will become clearer as we go on. These you need to declare at the beginning of the Function.Where: Help→Getting-Started→Functions_and_Other_Functionality f. // 2 + 2 Default values must be what are called literals. a + b. so you need to be aware of them. Why have two different ways? Well some people like the second one better and consider it a shortcut. or collections of them. math operations are done in order. and division and multiplication are not done first. finalResult. // keyword style You can mix regular and keyword style if you like. Don’t worry if that doesn’t totally make sense. f. a + b. c:3. i. f. b| f.d }. var firstResult. but the regular args must come first: f = { arg a. There is an alternate way to specify args. SC has a number of syntax shortcuts like this. (a + b) * c . 2). g = { | a. using the keyword ’var’. a + b. Literals are basically numbers.value(2. d: 1). b. // 2 + 4 * 3 . In any case you will encounter both forms. strings. b. b. c. b:4. You can do this like so: f = { arg a.

}. You can also declare variables at the top of any block of code which you execute altogether (i. by selecting it all). For more information see: 571 . You’ve already encountered one of these.e.Where: Help→Getting-Started→Functions_and_Other_Functionality firstResult = a + b.postln. foo. finalResult. The scope of a variable declared in a Function is that Function. This makes them useful for quick tests or examples.e. and why they don’t seem to have any particular scope (i. 3). they keep there values even when executing code one line at a time). f.value("foo"). the variable ’s’. foo. f. }.value. finalResult = firstResult * 2. myFunc = { | input| myFunc. }. and have an unlimited.value("bar"). // this will cause an error as ’foo’ is only valid within f. foo = 3. i. // arg is a String myFunc.e.value(2. The letters a to z are what are called interpreter variables. // throws an error You may be wondering why we haven’t needed to declare variables like ’f’. Execute these one at a time: f = { var foo. myFunc. Execute the block (in parentheses) and then the last line. which you’ll recall by default refers to the localhost server. the area between the two curly brackets. ( var myFunc. ) input. ) // this will return (2 + 3) * 2 = 10 Variable and argument names can consist of letters and numbers. or ’global’. scope. Variables are only valid for what is called their scope. In such a case that block of code is the variable’s scope. but must begin with a lower-case letter and cannot contain spaces. These are pre-declared when you start up SC.

Where: Help→Getting-Started→Functions_and_Other_Functionality [Functions] [Function] [Assignment] [Intro-to-Objects] [Literals] [Scope] ____________________ This document is part of the tutorial Getting Started With SuperCollider. Click here to go on to the next section: [Functions and Sound] Click here to return to the table of Contents: [Getting Started With SC] 572 .

so let’s get back to making noise. The type itself is the object’s class. execute the code below and then press Cmd-. For instance we might have a class called Student. Bob.) This is often the case when using Function-play.2) }. with a few arguments. If you don’t specify a server. It turns out that SinOsc is an example of something called a class. but you know what I mean. or something similar. In a nutshell.play. for instance they might have a bit of data named gpa. an object is some data. 0. Let’s go back to our sound example. and several instances of it. 0. all this work will pay off later. There are other ways of reusing Functions for sounds. All three will have the same types of data. To understand what a class is. In this case we’ve created a Function by enclosing some code in curly brackets. you’ll get the default one. For instance they could have a method called calculateGPA.e. and then called the method ’play’ on that Function. and a set of operations that you can perform on that data..Where: Help→Getting-Started→Functions_and_Sound ID: 188 And What About Functions and Sound? I’ve probably bored you enough with technical details. We’re taking something called a ’SinOsc’ and we’re sending it the message ar. which you’ll recall is stored in the variable ’s’ and is set at startup to be the localhost server. The value of each bit of data could be different however. when you’ve had enough. To Functions ’play’ means evaluate yourself and play the result on a server. as it is useful as a quick way of getting something to make noise. actually you could just execute the same line of code again. We didn’t store the Function in a variable. at least in passing. They would also have the same methods to operate on the data. Check that the localhost server is running. which I assume is why you’re reading this after all. some information. These are called instances.ar(440. { SinOsc. 573 . and believe it or not. You might have many different objects of the same type. (Well. Trust me though. and is often used for testing purposes. Dave and Sue. we need to know a little more about OOP and objects. or rather a slightly simplified version of it. so it can’t be reused. i.. Lets look at what’s between the curly brackets. which are often better and more efficient as we will see. we’ve already covered a fair amount of the basics of the language.

(We’ll get to how I know that in a second. Such methods return an object. and mul. This can save a lot of computing power. You do this through class methods such as ’new’. ’ar’. 0. and some data to be used by all of its instances. All SinOscs are an example of what are called unit generators. SinOsc is a sine wave oscillator. I happen to know that the arguments are frequency. which means control rate. and the arguments affect what its data will be. Audio rate means that the UGen will calculate a value for each sample in the block. an instance. For SinOsc (but not for all UGens) phase is given in radians. All classes begin with upper-case letters. ’kr’. These are objects which produce audio or control signals. This means that it will produce a signal consisting of a single frequency. (You can look at a trigonometry text if you really want 574 . In addition it may define some other methods which only you send only to the class itself. The three arguments to SinOsc-ar given in the example determine a few things about the resulting instance. This means calculate a single value for each block of samples. creating the output signal. Phase refers to where it will start in the cycle of its waveform.) Frequency is just the frequency of the oscillator in Hertz (Hz). or cycles per second (cps).2) This tells the class SinOsc to make an instance of itself. called blocks.Where: Help→Getting-Started→Functions_and_Sound An object’s class defines its set of data (or instance variables as they are called) and methods.tiff"> (don’t worry about the ’index’ and ’value’ stuff. Classes are what you use to make objects. ’ar’ means make the instance audio rate. SuperCollider calculates audio in groups of samples. or. and how it will behave. or UGens.ar(440. it’s not important just now) This waveform loops. just understand that it’s a value between 0 and 2 * pi. phase. 0.tiff" alt="Pasted Graphic. Now take another look at the example in question: SinOsc. in the case of our SinOsc class above. but it’s not fine enough detail for synthesizing audio signals. There’s another method. so it’s pretty easy to identify them in code. A graph of it’s waveform would look like this: <img src="Pasted%20Graphic. These are called class methods and class variables. don’t worry. If you don’t know what radians are. They’re like a template. and is fine for (you guessed it) signals which control other UGens.

This can be quite useful for things like control signals.tiff"> Get the idea? There’s also another similar arg called ’add’ (also generally unexplained in the doc). which means that the signal will oscillate between 1 and -1. this affects the amplitude of the signal. and one with a mul of 0. This is a good default as anything bigger would cause clipping and distortion. A mul of 0 would be effectively silent. The default mul of most UGens is 1. It’s so ubiquitous that it’s usually not even explained in the documentation.25: <img src="Pasted%20Graphic%203.tiff"> So what about ’mul’ ? Mul is a special argument that almost all UGens have. here is a graph of two SinOscs. which (you guessed it) is something which is added to the output signal. 0.tiff" alt="Pasted Graphic 2. or one quarter of the way through its cycle. // frequency of 440 Hz. one with the default mul of 1.Where: Help→Getting-Started→Functions_and_Sound more detail. let’s review our example.tiff" alt="Pasted Graphic 3.5). To make clearer how mul works. or the beginning of the cycle 575 . Okay. with all this in mind. ’add’ has a default value of 0.tiff"> Make sense? Here are several cycles of the two side by side to make the idea clearer: <img src="Pasted%20Graphic%202.ar( // Make an audio rate SinOsc 440.tiff" alt="Pasted Graphic 1. It just means a value or signal by which the output of the UGen will be multiplied. which is why we don’t need to specify something for it. It turns out that in the case of audio signals. the waveform would look like this: <img src="Pasted%20Graphic%201. or how loud it is. as if the volume knob was turned all the way down. or the tuning A // initial phase of 0. with comments: ( { // Open the Function SinOsc.) So if we made a SinOsc with a phase of (pi * 0.

5. a rather good range for mul! The phase of 1.2 // close the Function and call ’play’ on it Some More Fun with Functions and UGens Here’s another example of polymorphism.5 will scale that down to between 0. When creating Functions of UGens. or in this case. SinOsc. and how powerful it is. then a mul of 0. (1 / 0. which if you think about it a bit means that it will complete one cycle every 2 seconds.play. 1. use Cmd-. which if you look at the first graph above you’ll see is the lowest point.5. 0. Now lets look at the first SinOsc’s arguments. }.5 cps.5 * pi) means 3/4 of the way through its cycle. ) // mul of 0.ar(440. to stop the sound.5 = 2) Mul and add are both set to 0. ampOsc).5pi (this just means 1.5. 0. 0.5pi. for many arguments you don’t have to use fixed values. Think for a second about what that will do. ) Try this. Shifting the 576 . 0.Where: Help→Getting-Started→Functions_and_Sound 0. you can in fact use other UGens! Below is an example which demonstrates this: ( { var ampOsc.5.5 and -0.play.2) }. (Again. So its output is being multiplied by the output of the second one.5 to that brings it to between 0 and 1. ampOsc = SinOsc.tiff"> And what we have in the end is a SinOsc that fades gently in and out.) What we’ve done here is plugged the first SinOsc (a control rate one!) into the mul arg of the second one. So the ampOsc SinOsc’s waveform will look like this: <img src="Pasted%20Graphic%204.tiff" alt="Pasted Graphic 4. Frequency is set to 0.kr(0. Adding 0. If by default SinOsc goes between 1 and -1.5).

Where: Help→Getting-Started→Functions_and_Sound phase just means that we start quiet and fade in. see [UGens] or [Tour_of_UGens]. Patching together UGens in this way is the basic way that you make sound in SC. ____________________ This document is part of the tutorial Getting Started With SuperCollider. some of them simpler. or making multi-channel versions of things. For an overview of the various types of UGens available in SC. Click here to go on to the next section: [Presented in Living Stereo] Click here to return to the table of Contents: [Getting Started With SC] 577 . For instance try changing the frequencies of the SinOsc. There are other ways of doing the same thing. but this demonstrates the principal. For more information see: [Functions] [Function] [UGens] [Tour_of_UGens] Suggested Exercise: Experiment with altering the Functions in the text above. We’re effectively using ampOsc as what is called an amplitude envelope.

and press Cmd . a list of some methods. rather than getting it immediately. Most classes have help files. which may take arguments. There are also instance variables. If you select a class by double-clicking on it.) 578 . which are data in common between all instances. (If not you’ll get the main help window. The ones under the headings ’Essential Topics’ and ’Language’ are of particular import. Recall that anything in the code that begins with an uppercase letter is a class. which are objects which have been created from those templates. and instances. Again don’t worry if everything doesn’t immediately make complete sense to you. which are the data specific to each instance. Learning a computer language is sometimes a little like slowly zeroing in on something. it would be a good idea to familiarise yourself with some of these. and some information you can just file away for future reference. We also have class and instance methods. which contains a number of links to other help files.Where: Help→Getting-Started→Getting_Help ID: 189 Getting Help This is probably a good point to stop and explore some methods of finding further information. (Remember that ’mul’ and ’add’ are usually not explained. At some point. Here’s an example: [Help] Clicking on this link will open the main help window. which are like templates for objects. Class methods do things like create instances (as well as some convenience functions that don’t require an actual instance). You’re already familiar with the clickable links that have been used so far in this tutorial. Classes and Methods By now we’ve learned enough OOP theory that we know that we have classes.? (that’s hold down the Cmd key. hold down shift and press ?) the help file for that class will open if it exists.) Try it with this example below: SinOsc You should have gotten a window with a brief description of the class and what it does. and class variables. and a description of their arguments. and instance methods control and manipulate instances.

. SC has numerous other ways of tracking down information on classes. play({ SinOsc. but are good to know about for future use. Mix. 0. etc. Most of these are listed in the main help window. 0. a good place to check is [Syntax-Shortcuts]. which gives examples of most of these. Both of these do exactly the same thing: { SinOsc. If you see something you don’t recognize. etc. A common example is the distinction between Functional and receiver notation.. 0. You may be wondering how to access the helpfiles for Function and Array. so by typing in the following. and there are a number of ones on general topics.. Snooping. You will find numerous other examples of syntax shortcuts throughout SC’s documentation. For more information see: 579 .. Most of these won’t be too helpful for you at this point. including this tutorial!) This is a great way to learn. Function Array Some methods also have helpfiles..ar(440. since they often appear in code as {. They are also named classes. and can serve as starting points for your own work.Where: Help→Getting-Started→Getting_Help Beneath that are some examples of the class in action.} and [.].) vs. 0. methods. anArg).. you can also select and Cmd-? on them. It’s a good idea to cut and paste these to a new window. This means that the notation someObject.. Here’s a concrete example.2) }.)? SC has a number of such shorthand forms or alternate syntaxes.new(. These can be very useful for making it clear exactly what the class does..2) }). Information on these can be found in the files [More-On-Getting-Help] and [Internal-Snooping]. and then play around with modifying them. Syntax Shortcuts Remember the example of Mix(.someMethod(anArg) is equivalent to someMethod(someObject. (Remember that SC won’t stop you from saving any modified files.ar(440.play.

and if you like open up the help files for any unfamiliar classes used in those examples. Click here to go on to the next section: [SynthDefs and Synths] Click here to return to the table of Contents: [Getting Started With SC] 580 . and try opening up the helpfiles for the various classes used.Where: Help→Getting-Started→Getting_Help [More-On-Getting-Help] [Internal-Snooping] [Syntax-Shortcuts] Suggested Exercise: Go back over the examples in the previous tutorials. you’ll be using it a lot. Get used to Cmd-?. :-) ____________________ This document is part of the tutorial Getting Started With SuperCollider. Try out the examples.

To Begin [Introductory Remarks] [First Steps] Making Sound [Start Your Engines] [Functions and Other Functionality] [Functions and Sound] [Presented in Living Stereo] [Mix it Up] [Scoping and Plotting] [Getting Help] Server Abstractions [SynthDefs and Synths] [Busses] [Groups] [Buffers] 581 .Where: Help→Getting-Started→Getting_Started_With_SC ID: 190 Getting Started With SuperCollider by Scott Wilson Table of Contents In OSX click on the links below to take you to the corresponding document.

0.0)). There’s one other type of node: groups. ( // a stereo version SynthDef("tutorial-DecaySin2".04. source * direct). Groups are simply collections of nodes. used here for a random pan source = Pan2. other groups. 582 .04).2.ar(Impulse. 110. As you’ve probably guessed.5. they allow you to easily group together nodes and send them messages all at once.direct)). Like synths they take targets and addActions as arguments.before(g). 1. SynthDef("tutorial-Reverb2". h = Group. h. They are mostly useful in two ways: First they are very helpful in controlling order. 0. 0. which makes it easy to put them in position.Where: Help→Getting-Started→Groups ID: 191 Groups Our discussion about the order of synths on the server brings us to the topic of groups. second. and in the right order. }).0. var input.3.rand2 returns a random number from -1 to 1. Out.ar(effectBus. 2). freq = 440. freq))).send(s). 0. effectBus.free. there’s a handy Server abstraction object to represent group nodes in the client app: Group.ar(Rand(0. source * (1 . and can contain synths. 16.free.0. 1. direct = 0. var source. { arg outBus = 0.001. Groups as Ordering Tools Groups can be quite helpful in terms of controlling order. g = Group.ar(input. inBus. { arg outBus = 0.0.new. Out. This can be very helpful for things like keeping effects or processing separate from sound sources. input = In. SinOsc. 1). 0.kr(0. or combinations of both. Rand(0. 3)}).ar(SinOsc.do({ input = AllpassC. Synths on the server are a type of what are called nodes.ar(inBus. g.ar(outBus.ar(Decay2.3. // 1.125). Let’s reconsider our reverb example from the previous section. Rand(-1.

b. 0. sources). [\effectBus. input). \addToHead and 583 .audio(s. ) // now we create groups for effects and synths ( sources = Group. b. and they are persistent). there is also the (rarely) used \addReplace. b. y. Like the other addActions.index.free. all you need to know about them is that they can be used in the same way as interpreter variables (you don’t need to declare them. so that it will execute first. the latter to the end of the group.free. 0]. If you’re wondering about the names ’ sources’ and ’ effects’. effects = Group. For the moment. y = Synth("tutorial-DecaySin2". [\effectBus. 660]. so that it will execute last. }). all that matters is that all effects synths come after the source synths that they process. All the addActions At this point it’s probably good to cover the remaining add actions. placing a tilde ( ) in front of a word is a way of creating an environment variable.Where: Help→Getting-Started→Groups Out.free. ( The default addAction is \addToHead x = Synth("tutorial-Reverb2". effects). In addition to \addBefore and \addAfter. ) // make sure it’s after // this will be our stereo effects bus // now synths in the groups. \freq. and two add actions which apply to Groups: \addToHead and \addToTail.index. b = Bus. \outBus. z) as well Note that we probably don’t care what order the sources and effects are within the groups. // this frees their contents (x. effects.ar(outBus. z = Synth("tutorial-DecaySin2". 2). \outBus. ) // we could add other source and effects synths here sources.new. sources). b. and they allow for more descriptive names. The former adds the receiver to the beginning of the group.index].after( sources). [\inBus.send(s).

This represents the top of the server’s node tree. which are how the server keeps track of nodes.Where: Help→Getting-Started→Groups \addToTail have convenience methods called ’head’ and ’tail’. You should have seen something like the following in the post window when executing the example above: nodes on localhost: a Server Group(0) Group(1) Group(1000) Group(1001) Synth 1002 When you see a Group printed here. h = Group.free. If you don’t specify a target or pass in nil. called the default group. The first two. h. You may have been wondering why there were four groups posted above when we only created two. 584 . assigning and freeing them when appropriate. // add h to the head of g x = Synth. called the RootNode and the ’default group’. ’queryAllNodes’ and node IDs Server has a method called ’queryAllNodes’ which will post a representation of the server’s node tree. There is a special server abstraction object to represent this. In addition there is another group created with an ID of 1.tail(h. The order of nodes is from top to bottom.free.free.head(g). with the IDs 0 and 1. The Root Node and the Default Group When a server app is booted there is a special group created with a node ID of 0. g. are special groups. "default"). This is the default target for all Nodes and is what you will get if you supply a Server as a target. // add x to the tail of h s. g = Group. // this will post a representation of the node hierarchy x. Normally when working with Server abstraction objects you won’t need to deal with node IDs as the objects keep track of them.queryAllNodes. you will get the default group of the default Server. anything below it and indented to the right is contained within it. The numbers you see are what are called node IDs. called RootNode.new.

or groups contained within it. and not before or after it. a = Synth.scope(1).queryAllNodes.2) }. and instead create a separate source group within the default group. // creates a synth in the default group of the default Server a.ar(mul: 0. When adding an ’effects’ synth. // our SinOsc synth is within the default group (ID 1) // the scope node (’stethoscope’) comes after the default group. The other major use of groups is to allow you to easily treat a number of synths as a whole.internal. Server.. for instance. // Returns a Group object. one should resist the temptation to add it after the default group.group.new(\default). // watch the post window. well.boot.internal.. { SinOsc.default. Server. In general you should add nodes to the default group. so no problems Server.Where: Help→Getting-Started→Groups Server. Note the ID of 1 (the default group) in the post window The default group serves an important purpose: It provides a predictable basic Node tree so that methods such as Server-scope and Server-record (which create nodes which must come after everything else) can function without running into order of execution problems. If you send a ’set’ message to a group.quit.boot. This will prevent problems with scoping or recording.internal. groups. In the example below the scoping node will come after the default group. default group [ source group [ source synth1 source synth2 ] effects synth ] recording synth Groups as. it will apply that message to all nodes 585 .

// turn them all down g. amp). you can automatically get all the functionality of the superclass. Group and Synth are subclasses of the abstract class [Node]. etc. but not all would need a ’herdSheep’ method.free.Where: Help→Getting-Started→Groups contained within it. and all the subclasses which inherit it will be changed too. Pan2. g = Group. and (perhaps more practically important) are documented in Node’s helpfile. You can think of subclasses as being children of a parent class. they just exist to provide a common set of methods and variables to their subclasses.set("amp". 0. such as Terrier. called their superclass.1.rand. Some classes are abstract classes. and some other ones of their own. // make 4 synths in g // 1. and More on Tracking Down Help Now for a little more OOP theory. This way of working has certain advantages: If you need to change an inherited method. which means that you don’t actually make instances of them. Because of this. g.do({ { arg amp = 0. BassetHound. }). however have more than one immediate superclass.play(g). but in general subclasses respond to all the methods of their superclass.005). 586 . some of their methods are defined in Node. their Inheritance. (A class cannot. 1. which has a number of subclasses.0. Inheritance can go back through many levels.) All objects in SC in fact inherit from a class called Object. Both Group and Synth are examples of what are called subclasses.new. 4. 0. All subclasses inherit the methods of their superclass.ar(SinOsc. We might for instance imagine an abstract class called Dog. if you want to extend a class to make your own personal variant or enhanced version.ar(440 + 110.rand2) }. which defines a certain set of methods which all its subclasses either inherit or override. These might all have a ’run’ method. Groups. which is to say that a class’ superclass may also have a superclass. They may override some methods with their own implementation (taking advantage of polymorphism). As well.0.rand2 returns a random number from -1 to 1. you can do so in one place.

// Object-postln. Group. you may need to go to the helpfile for that class’ superclass. or farther up the chain. You can also use the following methods for getting this kind of info and tracking down documentation (watch the post window): Group.superclass.findRespondingMethodFor(’postln’). // Node-set Group. Most classes have their superclass listed at the top of their helpfile.findRespondingMethodFor(’set’).Where: Help→Getting-Started→Groups So if you’re looking at a helpfile and can’t find a particular method that a class responds to. // opens class Object help file For more information see: [Group] [Node] [default_group] [RootNode] [Intro-to-Objects] [Order-of-execution] [Synth] [More-On-Getting-Help] [Internal-Snooping] ____________________ This document is part of the tutorial Getting Started With SuperCollider.superclass. // this will return ’Node’ Group.helpFileForMethod(’postln’). Click here to go on to the next section: [Buffers] Click here to return to the table of Contents: [Getting Started With SC] 587 . Group.openHelpFile.

(I’m assuming here that words like frequency and sample will not cause any confusion.Where: Help→Getting-Started→Introductory_Remarks ID: 192 Introductory Remarks The following text is intended to serve as an introduction to SuperCollider 3. In writing it I have drawn freely upon the general documentation. This document is not intended to replace those (often more detailed) sources. The parts which specifically differ have mostly to do with GUI aspects (Graphical User Interface). You won’t need to have seen and/or fully understood them in order to continue with the tutorial. I should acknowledge that this tutorial is ’by’ me in only a limited sense. that will look something like this: See also:[Some other document] Most of these are meant to expand upon what you have just read.net Links Within the text. This tutorial does not assume a background in computer science.sourceforge. and at the end of each section there might be a list links to other documents. but much of it should apply to linux and windows as well. and may duplicate information which is presented in this tutorial in a more casual form. as well as a basic knowledge of acoustics and digital audio. so don’t worry if everything in them doesn’t immediately make sense. 588 . Some of the linked documents are written in fairly technical language.) The tutorial is written from a Mac OSX perspective. but does assume basic familiarity with your computer and its OS. and refers the reader to them constantly for further information. but some just point you in the direction of further information which you will probably need in the future. Often they are designed as reference documents for people already familiar with SC. which was written by a number of people. an objectoriented language for sound synthesis and digital signal processing (DSP). A full list of those who have contributed to SuperCollider and its documentation can be seen at: #1104ffhttp://supercollider.

You are encouraged to copy the code examples to another window and play around with modifying them. ____________________ This document is part of the tutorial Getting Started With SuperCollider.Where: Help→Getting-Started→Introductory_Remarks Code Examples Code examples within the text are in a different font: { [SinOsc. It’s safest to copy things to a new document before changing them. but if you do so you should be careful not to save them (for instance if prompted when closing them). 0.ar(440. and one that is followed throughout SC’s doc. and have no effect on what the code does. Click here to go on to the next section: [First Steps] Click here to return to the table of Contents: [Getting Started With SC] 589 . SinOsc. 0.ar(442.2)] }. 0. 0. The different colours you’ll see in code are just to make things clearer. This is a time honoured way of learning a new computer language! SC will allow you to mofify the original tutorial documents.play.2). This is a common convention in documentation of computer languages.

ar(660. Watch the post window to see Mix’s results. Saw.ar(442. thus ensuring that the final output will be between -1 and 1.2). however. Saw is another type of oscillator.2). is actually just a ’convenience’ class. The latter is a shorthand for the former. 0.Where: Help→Getting-Started→Mix_it_Up ID: 193 Mix it Up We’ve already seen that multiplication changes the level of something. Note that we use a low value for mul. 0. it just returns the results of its summing. Mix([a.).new(.ar(662.play. // one channel { Mix. Saw.).ar(660. with a waveform that looks like a sawtooth. 0. b]).ar(440.2)].ar(0. 0. b. There’s another handy class called Mix. 0.play.2) }.ar(440. and in the second we get an Array of two BinaryOpUGens.ar(660.2) + Saw. such as the ’ar’ and ’kr’ methods of UGens. Saw.2)].2) + SinOsc.new([SinOsc.. 0. 0.postln.. 0. ) In the first case we get a ’BinaryOpUGen’ (in this case this means the two UGens added together). Note that in the first example we use Mix.2). and doesn’t actually create Mix objects.play. }. 0. 0. ’new’ is the most common class method for creating a new object.) 590 . 0.2)]). 0. b = [SinOsc. // combine two stereo arrays ( { var a.ar(440. but in the second we use Mix(. but what about mixing UGens together? This turns out to be equally simple. which will mix an array of channels down to a single channel or an array of arrays of channels down to a single array of channels. a = [SinOsc. (Mix. and not clip. either a BinaryOpUGen or an Array of them. All we need is addition: { PinkNoise.. In some cases objects have more than one class method for creating objects..postln }.

So if ’n’ is 8 the Function will be passed values from 0 to 7. For more information see: 591 .postln.play. Each time the Function is evaluated it is passed the number of times evaluated so far as an argument. freq = 440 + index.postln. which determines how many times the second argument. we have the tools we need to combine multichannel sources of sound into complex mixes and submixes. you can have vastly different numbers of SinOscs! (Try it!) This sort of approach makes this code extremely flexible and reusable. The mul arg of each SinOsc is set to 1 / n. 1 / n) }) }. By simply changing the value of n. // Look at the post window for frequencies and indices ( var n = 8. in sequence. counting up.fill(n. { Mix. which takes two arguments. { arg index. freq. SinOsc. By declaring an argument within our Function we can use this value.play. The first is a number.0. each time creating a SinOsc with a random frequency from 500 to 1000 Hz (500 plus a random number between 0 and 500). Confusing? Take a look at the following example: ( var n = 8. 0. ) By combining addition and multiplication (or indeed almost any mathematical procedure you could imagine!) with the use of classes like Mix. thus ensuring that the total amplitude will not go outside -1 and 1.ar(freq . var freq.fill(n. The results of the evaluations will be summed.rand. will be evaluated. a Function. 0. 1 / n) }) ) }.Where: Help→Getting-Started→Mix_it_Up Mix also has another class method called fill. { Mix.ar(500 + 500. index. The Function will be evaluated n times. { SinOsc.

or making multi-channel versions of things. ____________________ This document is part of the tutorial Getting Started With SuperCollider.Where: Help→Getting-Started→Mix_it_Up [Mix] [BinaryOpUGen] [Operators] [Syntax-Shortcuts] Suggested Exercise: Experiment with altering the Functions in the text above. For instance try changing the frequencies of the SinOsc. Click here to go on to the next section: [Scoping and Plotting] Click here to return to the table of Contents: [Getting Started With SC] 592 .

ar(442. SinOsc. "bar" is at index 1 a.at(1). but in a different arrangement. 0. 0.at(0). "bar"]. and you will come to learn that they are one of the SC’s most powerful features. and start from 0.play.2)] }. 0. a.ar(440. Arrays also have a special use in SC: They are used to implement multichannel audio! If your Function returns an Array of UGens (remember that Functions return the result of their last line of code) then the output will be a number of channels. by putting objects in between two square brackets. which takes an index as an argument. How many depends on the size of the Array. SinOsc.2). You can make one as we have above. // "foo" is at index 0. You can get the different elements of an Array using the method ’at’. and a SinOsc at 442Hz in the right channel. Collections themselves are Objects.2). a. and each channel will correspond to an element of the Array. unsimplified example? Remember: { [SinOsc. // same as a. with commas in between. as there is no object at index 2 // there’s a shorthand for at that you’ll see sometimes: a[0]. 0. 0.Where: Help→Getting-Started→Presented_in_Living_Stereo ID: 194 Presented in Living Stereo Okay. a = ["foo". 0. but what about our first. which is (you guessed it) a collection of Objects.at(2).2)] }. with a SinOsc at 440Hz in the left channel. between two square brackets []. In addition to being used to hold collections of objects. square brackets define something called an Array. and with a comma in between.ar(442. We could have even more channels of output 593 . 0. and most types of Collections can hold any types of objects. An Array is a particular type of Collection: An ordered collection of limited maximum size. mixed together.play. Just like the curly brackets indicate a Function.ar(440. An Array is a type of Collection. Indices correspond to the order of objects in the Array.at(0). What we end up with is stereo output. So in our example: { [SinOsc. This also has two SinOscs. // returns "nil". 0. including other Collections! There are many different types of Collections in SC.

which means that if you plug an Array into one of a UGen’s arguments. ’choose’ is just a method which randomly selects one of the elements of the Array. { Pan2. 880]. 442]. The position arg goes between -1 (left) and 1 (right). In this case the result may be a single number or another Array. 0. because this next bit involves a little slight of hand.ar(freq. and it has a single argument: mul. This causes something called ’multichannel expansion’. something called PinkNoise. -0. SinOsc. freq = [[660.play. You can of course also used fixed values for the position arg. 0. the left and right or first and second channels.play.Where: Help→Getting-Started→Presented_in_Living_Stereo by having a larger array.ar(0.play.kr(0. 660]. 0. This is just a kind of noise generator. we can rewrite the code for our example like this: { SinOsc. and you’ll get different results. Take a look at this example: { Pan2. 880]. 0. This sort of thing can make your code very flexible.ar(PinkNoise. 1320. Pan2 takes an input and a position as arguments and returns an Array of two elements.2). }.2). but uses a different UGen as the input to the Pan2. SinOsc. [440.2).play. ) Try executing it several times. crossfading it between channels? SC has a number of UGens which do this in various ways. or left to right). // slightly to the left 594 . We’ve replaced the frequency argument with an Array. you get an Array of that UGen instead of a single one. In the case of the latter you’ll get stereo output.ar(0.ar(PinkNoise. But what if you want to ’pan’ something.3) }. Now consider this: ( { var freq.5)) }. but shows another way in which SC makes things very interchangeable.2) }.choose. This uses a SinOsc to control the position (remember it outputs values from -1 to 1. but for now I’ll just introduce you to one: Pan2. Because the arguments for phase and mul are the same for both SinOscs.ar([440. Now watch carefully. monophonic. in the case of the former.

Where: Help→Getting-Started→Presented_in_Living_Stereo For more information see: [MultiChannel] [Collections] [Pan2] Suggested Exercise: Experiment with altering the Functions in the text above. or making multi-channel versions of things. Click here to go on to the next section: [Mix it Up] Click here to return to the table of Contents: [Getting Started With SC] 595 . For instance try changing the frequencies of the SinOsc. ____________________ This document is part of the tutorial Getting Started With SuperCollider.

it will always play on it. like so: Server. but you can set it to anything you want. shows an oscilloscope-like display of the Function’s output.2) + SinOsc.tiff"> or you can do it in code. 0. Function-scope. Since Function-scope only works with the internal server.ar(440. The default is 0.scope. { PinkNoise.tiff" alt="Pasted Graphic. The second method. This can be useful to check what’s happening.ar(660. You can specify some arguments. 0.01 seconds. however.plot(1).2) }.2) }.2) + SinOsc. and stores it in the variable ’s’. and if you’re getting the output you think you’re getting. BTW.ar(660.plot. 0. clicking on the ’-> default’ button on the localhost or internal server’s window sets that server to be the default. unless you specify another one. 0. This only works with what is called the internal server. 0. You can do this using the internal server window <img src="Pasted%20Graphic. This should open a window which looks something like this: 596 .2) + Saw. that will be the server on which all audio is played.ar(0. 0.ar(660. This makes a graph of the signal produced by the output of the Function.ar(0.ar(440. Function-plot: { PinkNoise. So let’s try to scope some audio: { PinkNoise.2) + Saw.ar(0.2) + SinOsc.ar(440. Thereafter. 0. 0. such as the duration.2) }.boot.Where: Help→Getting-Started→Scoping_and_Plotting ID: 195 Scoping Out Some Plots Function has two other useful audio related methods. The first you’ve already seen some results of. so you’ll need to boot that before it will work.2) + Saw.internal. 0.

ar(440.internal). { [SinOsc.tiff" alt="Pasted Graphic 1. 0.Where: Help→Getting-Started→Scoping_and_Plotting <img src="Pasted%20Graphic%201.ar(442. 0. it’s relatively straightforward: The internal server runs as a process within the client app. SinOsc. Server. 0.tiff"> This also works for multiple channels: { [SinOsc. so if the client crashes. Scope also has a zoom argument. 0.2)] }. 0. Like Function-plot.ar(440. 0. 0. so does the server. // you could also use ’s’ if the internal is the default You can do the same thing by clicking on the internal server window and pressing the ’s’ key. The disadvantage is that the two are then interdependent. Local vs.play(Server. Internal If you’re wondering what’s the difference between the local and the internal servers. For more information see: [Function] [Server] [Stethoscope] 597 .2). and to see if you’re actually getting out what you think you are. by calling ’scope’ on it.scope. Higher values ’zoom out’.internal. basically a program within a program.ar(440. which allows for things like realtime scoping of audio. 0. 0.scope.2).2)] }. SinOsc. 0. SinOsc. The main advantage of this is that it allows the two applications to share memory. 0. Scoping on Demand You can also scope the output of the internal server at any time.ar(442. 0.2). Function-scope can be useful for testing purposes.scope(zoom: 10).ar(442.2)] }. { [SinOsc.

Where: Help→Getting-Started→Scoping_and_Plotting Suggested Exercise: Experiment with scoping and plotting some of the Function examples from earlier sections. Try experimenting with different duration or zoom values. Click here to go on to the next section: [Getting Help] Click here to return to the table of Contents: [Getting Started With SC] 598 . or some Functions of your own creation. ____________________ This document is part of the tutorial Getting Started With SuperCollider.

tiff" alt="Pasted Graphic. sampleRate=44100. It should look like this: <img src="Pasted%20Graphic. as opposed to running on a different computer connected by a network. and that the ’Boot’ button has changed to ’Quit’. After a second or two it should look something like this: <img src="Pasted%20Graphic_1. Look for the one that says ’localhost server’.tiff"> Notice that the name has lit up red. notification is on If for some reason it had failed to boot.tiff" alt="Pasted Graphic_1. and let you know that it booted okay: booting 57110 SC_AudioDriver: start numSamples=512. where SC has given you some info. there would be some information indicating that.000000 0 UseSeparateIO?: PublishPortToRendezvous 0 57110 SuperCollider 3 server ready. More about them soon.tiff"> ’localhost’ just means on your local computer. By default you can refer to the localhost server in your code by using the letter s. we need to start or ’boot’ a server application.Where: Help→Getting-Started→Start_Your_Engines ID: 196 Start Your Engines Before we can make any sound.. and some other things which probably aren’t too clear yet. These can be found in the bottom left-hand corner of your screen. or click on the window and press the space bar. You 599 . This indicates that the server is running. To start the server click on the ’Boot’ button. The easiest way to do this is to use one of the server windows which is automatically created by the client app. As well the window provides you with some information about CPU usage. Also take a look at the post window.

You can also refer to the localhost server with the text ’Server. Many examples in the documentation have s.quit. s.boot at the beginning.Where: Help→Getting-Started→Start_Your_Engines can thus send messages to start and stop it like so: s. Click here to go on to the next section: [Functions and Other Functionality] Click here to return to the table of Contents: [Getting Started With SC] 600 . For more information see: [Server] ____________________ This document is part of the tutorial Getting Started With SuperCollider. for example: Server. but in general you should make sure the server is running before using any examples that generate audio.boot. In general the examples in this tutorial assume that the server is running.local.local’.boot. or otherwise access the server. Try this out and then leave the server running.

local and Server. however. or OOP. This is sent in a kind of special optimised form. or produce control signals to drive other synths. Distinguishing between the two can be a little confusing. which the server can deal with very efficiently. This is because each time we execute the code. the Function is evaluated anew. Synth vs. i.Where: Help→Getting-Started→SynthDefs_and_Synths ID: 197 SynthDefs and Synths Now that we’ve covered some basic information we’re going to start looking at server abstractions. which means the results can vary greatly. synth. The first thing we’ll look at is the class SynthDef. or the SC language. Server abstraction objects are simply conveniences.internal (and whichever one is stored in the interpreter variable ’s’ at any given moment) are instances of Server. It wants information on how to create audio output in a special form called a synth definition. and in cases where maximum flexibility is needed. and should not be confused with those parts themselves. and the corresponding aspects of server architecture with lowercase names. A synth defintion is data about UGens and how they’re interconnected. so in general I refer herein to the client-side classes with uppercase names. it’s can very efficiently use it to make a number of synths based on it.e. called ’byte code’. When looking at these it is important to understand that these objects are just client-side representations of parts of the server’s architecture. which is short for ’synth definition’. which are the various classes in the language app which represent things on the server. class Server itself. doesn’t understand Functions. Now it’s time to get familiar with the rest of them. Synths on the server are basically just things that make or process sound. You’ve already met one kind of server abstraction. The server. The objects referred to by Server. This relationship between synth definitions and synths is something like that between 601 . Once the server has a synth definition. This way of working is very useful for quick testing. Meet the SynthDef Up until now we’ve been using Functions to generate audio.

The second is in fact a Function. but for now just be aware that they’re used for playing audio out of the computer. SynthDefs vs. SinOsc. and the necessary byte code is generated and sent to the server. 0. which can be thought of as mixer channels or outputs. We’ll discuss busses in greater detail later.ar(0. SynthDef also has a convenient play method. a multichannel 602 .ar(440. //first the Function { SinOsc. Whenever you use any of Function’s audio creating methods what happens is that a corresponding instance of SynthDef is created ’behind the scenes’. and for reading it in from sources such as microphones. The second is either a UGen or an Array of UGens. usually in the form of a String as above. as it tells the server how to connect together its various UGens. so that you don’t have to take care of this. so we can easily confirm that these two are equivalent. But remember that the server app knows nothing about OOP.2)) }).new("tutorial-SinOsc".2) }. Let’s compare a by now familiar Function based example. So Function’s audio methods provide a kind of convenience for you.Where: Help→Getting-Started→SynthDefs_and_Synths classes and instances. SynthDef-new takes a number of arguments. and to deal with synth definitions in an object oriented way. Like Function. Functions This UGen Graph Function we used in the second example above is similar to the Function we used in the first one. but with one notable difference: It has an extra UGen called Out. 0. Out writes out an ar or kr signal to one of the server’s busses. // now here’s an equivalent SynthDef SynthDef. which on a stereo setup is usually the left output channel. The first is a name. If you provide an array (i. 0.play.e. where a synth is created to play the desired audio. which make is easy to create the necessary byte code and send it to the server. { Out. so to speak. in that the former is a template for the latter. Out takes two arguments: The first is the index number of the bus to write out on.ar(440. and make an equivalent SynthDef. So how do you make a SynthDef yourself? You use its ’new’ method. This argument is called a UGen Graph Function. Luckily for us there are classes in the language such as SynthDef. 0. These start from 0.play.

and so on.play. If you store this object by assigning it to a variable you can control it’s behaviour in various ways.ar(442. In general should use ’send’ unless you’re going to reuse the def all the time. 603 . Such a file will have the extension .ar(0. The difference between these two is that send streams the definition over the network. 0.new("tutorial-SinOsc-stereo".ar(440. The default bus index for this Out UGen is 0.2)]. For instance the method ’free’ causes the synth on the server to stop playing and its memory and cpu resources to be freed. 0. y = SynthDef.ar(0. the second channel on the bus with the indicated index + 1.2)) }).ar(440. SinOsc. Out. // free just x y. x = { SinOsc. { Out. // free just y This is more flexible than Cmd-. which frees all synths at once. 0. SinOsc. The SinOsc with the frequency argument of 440 Hz will be played out on bus 0 (the left channel).play.Where: Help→Getting-Started→SynthDefs_and_Synths output) then the first channel will be played out on the bus with the indicated index. ) When you use Function-play an Out UGen is in fact created for you if you do not explicitly create one. x. 0.scsyndef (so for example tutorial-SinOsc.ar(660. This will remain there until you specifically delete it. due to limits on packet size on the network. a Synth. and will be written into the synthdefs/ directory within the main SC directory.free. outArray = [SinOsc. It is however sometimes necessary to use ’load’ with very large or complicated defs. 0.2) }. outArray) }).scsyndef). Here’s a stereo example to make clear how this works.new("tutorial-SinOsc". and load writes the definiton to disk as a file so that the server can load it. SynthDef has two methods which cause the corresponding byte code to be sent to the server app without immediately creating a synth: send and load. 0.play. which represents a synth on the server.free. { varoutArray. 0. and the SinOsc with the frequency argument of 442 Hz will be played out on bus 1 (the right channel).2).. 0. and will be loaded automatically whenever you boot a server. ( SynthDef. Both Function-play and SynthDef-play return another type of object.

SinOsc.free. // Now with a SynthDef. 0.ar(0. y.) This means that it is somewhat less flexible. You can do this with Synth’s new method.free. but using SynthDef has certain advantages.rand.play. SynthDef.free. { Out. This is because the Function (and thus 200. 604 .new("tutorial-PinkNoise"). No randomness! SynthDef("tutorial-NoRand". f = { SinOsc. Each time you create a new Synth based on the def. Note the random frequency each time ’play’ is called.free. Once you have a def in a server app.free. as well as certain limitations. y = f. { Out. 0. the frequency is the same. which takes a def’s name as its first argument. x.3)) }). Compare these two examples: // first with a Function. y = Synth.send(s).new("tutorial-PinkNoise". x.play. z = f.2)) }). and sending it multiple times. when the SynthDef is created.free. 0.rand) is only evaluated only once. y. 0. x = Synth("tutorial-NoRand").Where: Help→Getting-Started→SynthDefs_and_Synths You can create many.free. z. In many cases this saving in CPU usage is so small as to be largely insignificant. z. This is more efficient than repeatedly calling play on the same Function. PinkNoise. A corresponding limitation to working with SynthDefs directly is that the UGen Graph Function in a SynthDef is evaluated once and only once. as it saves the effort of evaluating the Function. but when doing things like ’mass producing’ synths. x = Synth.2) }.ar(0. z = Synth("tutorial-NoRand"). (Remember that the server knows nothing about the SC language. compiling the byte code. x.ar(0. y = Synth("tutorial-NoRand").rand.ar(440 + 200.play. x = f. this can be important.send(s). y.ar(440 + 200. many Synths using the same Function or SynthDef.free.new("tutorial-PinkNoise"). you can create many synths from it with a relatively low overhead of CPU.

Synth-set takes pairs of 605 . }).2)).send(s).free. This allows you to set different values when the synth is created. Out.send(s). ["freq".Where: Help→Getting-Started→SynthDefs_and_Synths Creating Variety with SynthDefs There are numerous ways of getting variety out of SynthDefs.ar(out.ar(freq. The most common way of creating variables is through putting arguments into the UGen Graph Function. More About Synth Synth understands some methods which allow you to change the values of args after a synth has been created. z = Synth("tutorial-Rand"). such as randomness. One example is [Rand]. ["freq". 660). it works! SynthDef("tutorial-Rand". SinOsc. These are passed in an array as the second argument to Synth-new.ar(Rand(440. y. 0. you may still need to use Functions. The [UGens] overview lists a number of such UGens.2)) }).free. z = Synth("tutorial-args". SinOsc. "out".free. ) x = Synth("tutorial-args"). x. 0. For now we’ll just look at one. 880. The array should contain pairs of arg names and values. or create multiple defs. x = Synth("tutorial-Rand").ar(0. y = Synth("tutorial-Rand"). 660]). ( SynthDef("tutorial-args". This combination of args and UGens means that you can get a lot of mileage out of a single def. z. which calculates a random number between low and high values when a synth is first created: // With Rand. so default values // change freq y = Synth("tutorial-args". 1]). can be accomplished with various UGens. however. y. { arg freq = 440. 0. but in some cases where maximum flexibility is required. // change freq and output channel x.free.free. Some things. { Out. z. // no args. out = 0. 0. ’set’.free.

Some Notes on Symbols. ) s. s. 0. out = 0.free. 660). i. Strings.set("freq". either enclosed in single quotes: ’tutorial-SinOsc’or preceded by a backslash: \tutorial-SinOsc.default = Server.ar(freq. You write symbols in one of two ways. but be aware that this is not necessarily true in general code. whereas with Strings this might not be the case.new("tutorial-args").ar(out. SinOsc. or another kind of literal called a Symbol. x.2)). Out.default. 1). You can test for this using ’===’.send(s).Where: Help→Getting-Started→SynthDefs_and_Synths arg names and values. x. // scope so you can see the effect x = Synth.new("tutorial-args". Like Strings Symbols are made up of alpha-numeric sequences. // this will post false // this will post true In general in methods which communicate with the server one can use Strings and Symbols interchangeably. { arg freq = 440. 0. "out".internal. Server. Execute the following and watch the post window. s = Server.scope. The difference between Strings and Symbols is that all Symbols with the same text are guaranteed to be identical. 880. "a String"=== "a String". x.e. \aSymbol=== ’aSymbol’.boot. ( SynthDef.set("freq". as we’ve seen above. SynthDef and Arg Names SynthDef names and argument names can be either a String. }). the exact same object. // this will post false For more information see: [SynthDef] [Synth] [String] [Symbol] [Literals] [Randomness] [UGens] Suggested Exercise: 606 . "this"=== \this.

Experiment with adding and changing arguments both when the synths are created. ____________________ This document is part of the tutorial Getting Started With SuperCollider. and afterwards using ’set’. Click here to go on to the next section: [Busses] Click here to return to the table of Contents: [Getting Started With SC] 607 .Where: Help→Getting-Started→SynthDefs_and_Synths Try converting some of the earlier Function based examples. adding Out UGens. to SynthDef versions. or Functions of your own.

10 GUI 608 .

0. *blue { arg val = 1.0) create blue. alpha) *new255(red. *new255 takes 8-bit values as arguments. *new(red. alpha) create new color in RGB mode. val. alpha = 1. alpha = 1. *rand(hue. *hsv(hue. alpha = 1.0.0) create red. sat. *black create black. *fromArray(array) create new color in RGB mode from a 3-4dim.0) create yellow.0.0.0) create green. val. *yellow { arg val = 1.5. alpha = 1.blue.Where: Help→GUI→Color ID: 198 Color superclass: Object Creation Each component has a value from 0. *green { arg val = 1.0.blue. array. alpha = 1. *red(val = 1. green. alpha) create new color in HSV mode. *clear create translucent. sat.0 to 1. alpha) create new random color. green. except in new255. *white create white.0) 609 . *grey(grey = 0.

31.new(0.postln.94. Color.9. Manipulating scaleByAlpha uses the alpha-value to scale all other colorsParts.0) create gray/grey Accessing <>red Get the red component.asHSV. <>alpha Get the alpha component.postln.94. 0. Val]. <asHSV returns an Array of [Hue.rand.G. 0.31.red.postln.asArray.postln.new(0. 0.rand.3. 1). alpha = 1. <>green Get the green component. 1).94. Color. <asArray returns an Array of [R. Color. 0. 0. 610 . Color.postln.postln.green. blend) blends two Colors.Where: Help→GUI→Color *gray(gray = 0. 0.31.blue.5. Color.new(0.1.B].47. alpha then is 1. 0. blend(arg that.31.alpha. Sat.47. Color.94.47. lo=0. hi=0. <>blue Get the blue component. 1). alphaVal=0) varies a Color. vary(val=0. 0.47. 1).new(0.

} }. Each call to SCWindow-refresh SCUserView-refresh will ’overwrite’ all previous drawing by executing the currently defined function.rand. Color. 1). rrand(10. [SCUserView]. rrand(0.view. Pen.new.5)).rand.white). and will only be visible once the window or the view is refreshed.choose).width = 3. See also: [SCWindow].0. Color. set sets the stroke and the fill color. 100).setFill.rand ). ( w = SCWindow.red(rrand(0.background_(Color. 1).0.do{ Pen.drawHook = { // set the Color Pen. w.addAnnularWedge( 0@0.Where: Help→GUI→Color GUI drawing The following methods must be called within an SCWindow-drawHook or a SCUserViewdrawFunc function. 30. 2pi. setFill sets the fill color. Pen.blue(rrand(0. 611 . 50). w.0.0.5)). rrand(51.0. 200).perform([\stroke. [Pen] and [String] setStroke sets the stroke color. 0.setStroke. 0. w. \fill].front. 2pi. rrand(0.refresh.translate(200.

’azure3’ -> Color. 238). ’beige’ -> Color. 255). ’BlueViolet’ -> Color. 228. ’BlanchedAlmond’ -> Color. ’aquamarine2’ -> Color.new255(250. 204).new255(118. 255. 255. 223. ’blue’ -> Color.new255(240.new255(255.new255(0. 612 . ’blue3’ -> Color.new255(193. ’bisque3’ -> Color.new255(138. 125.new255(240.new255(250. ’azure2’ -> Color. 235. 255. ’bisque1’ -> Color.Where: Help→GUI→Color ) X-windows colors : ’alice blue’ -> Color. 198). 196). 248. 239. ’black’ -> Color.new255(0. 205. 235.new255(240. 213. ’blanched almond’ -> Color. 228. 255). 215). 226). ’bisque’ -> Color. ’antique white’ -> Color.new255(255. ’blue violet’ -> Color.new255(165. 183). 212). 0. ’blue4’ -> Color. ’azure1’ -> Color.new255(255. ’AntiqueWhite3’ -> Color. 107).new255(127. 0. 212). 192. 43.new255(102. ’AntiqueWhite4’ -> Color.new255(245. ’blue1’ -> Color.new255(138. 205). 196). 0. 0). ’bisque4’ -> Color. 255). 219). 205). ’bisque2’ -> Color. ’AntiqueWhite2’ -> Color. 0.new255(240. 43. 226).new255(205. 220).new255(205. ’azure’ -> Color. 139.new255(0. 235. 255). 235.new255(224. 42). ’aquamarine1’ -> Color. ’brown’ -> Color. 215). 139.new255(69. 245. 139). 238). ’aquamarine’ -> Color.new255(0. ’AntiqueWhite’ -> Color.new255(255. 205. 0.new255(139. 158).new255(238. 120). ’blue2’ -> Color. 238. 255). 205). ’aquamarine4’ -> Color.new255(255.new255(127. 248. 116). ’azure4’ -> Color. ’aquamarine3’ -> Color. 0. 139).new255(238. 176). 170). 183. ’AliceBlue’ -> Color. 205).new255(139. 131.new255(0.new255(131. 255. 255). ’AntiqueWhite1’ -> Color.new255(0. 42. 238.

’CadetBlue2’ -> Color. 35). 248. ’coral1’ -> Color. 160).Where: Help→GUI→Color ’brown1’ -> Color.new255(95.new255(0. ’coral4’ -> Color. 205. 106. 80).new255(139.new255(100.new255(238. 237). ’brown2’ -> Color. 69. 197. ’cyan2’ -> Color. ’CornflowerBlue’ -> Color. 177). 136. ’chocolate3’ -> Color.new255(255. ’chocolate4’ -> Color. ’burlywood4’ -> Color.new255(205. 33). ’brown4’ -> Color. 255.new255(255. 255).new255(102. ’chartreuse1’ -> Color. 197.new255(100. 118. 255). ’chocolate1’ -> Color. 51).new255(255. 158.new255(255. 47). ’chartreuse’ -> Color.new255(0. 158. ’CadetBlue’ -> Color. ’cornflower blue’ -> Color. ’chartreuse3’ -> Color. 120). 205).new255(139.new255(255.new255(205. 145).new255(222. 160). 80). 238). 115.new255(238. ’coral2’ -> Color. 255). 125). 220).new255(139.new255(69. ’coral3’ -> Color. 229. ’CadetBlue4’ -> Color. 127.new255(205. 85). 64). 102.new255(255. 220). 238. ’CadetBlue3’ -> Color. 245. ’cadet blue’ -> Color. ’cornsilk4’ -> Color. ’burlywood’ -> Color. 59). 200.new255(142. 64. 613 . 149. ’cyan1’ -> Color. 0).new255(238. ’cornsilk’ -> Color. 35.new255(0. 29). 211. 184. 255. 105. 91. 0).new255(205. ’burlywood1’ -> Color.new255(139.new255(118. 139. 149. ’cyan’ -> Color. 255. 238).new255(238. ’coral’ -> Color. 0). ’brown3’ -> Color. 59. ’burlywood2’ -> Color. 232. 0). ’burlywood3’ -> Color.new255(205. 155). 0). 255. 62. 248. 135). 170.new255(83. 114. 237). 30). 19). ’chartreuse4’ -> Color.new255(127. 86). 127.new255(122. ’chartreuse2’ -> Color.new255(127.new255(255.new255(210. 205). 139).new255(238. 134. ’chocolate’ -> Color.new255(139. 36).new255(152. ’chocolate2’ -> Color. ’cornsilk2’ -> Color. 238. ’cornsilk1’ -> Color. ’CadetBlue1’ -> Color.new255(95. 69). 51. ’cornsilk3’ -> Color.

’DarkOrange2’ -> Color. ’DarkGreen’ -> Color. ’DarkOrchid3’ -> Color. 47). ’DarkOrange3’ -> Color.new255(0. 139). ’DarkOliveGreen2’ -> Color. 139). 238). ’DarkOrchid1’ -> Color. 112). 255.new255(47.new255(104.new255(191. ’DarkOliveGreen4’ -> Color. ’dark sea green’ -> Color. 139. ’dark salmon’ -> Color. ’dark slate grey’ -> Color.new255(85. 107). 62. ’dark turquoise’ -> Color. ’DarkOliveGreen’ -> Color. ’DarkOrange1’ -> Color. 90). 0). ’DarkOrange4’ -> Color.new255(148. 118.new255(162. 139. 188. 134. 150.new255(0. 100. 134.new255(255. 50. 79. 0). ’DarkSalmon’ -> Color. 183. 139). ’dark violet’ -> Color.new255(189. 107. 50. 185. ’dark olive green’ -> Color. 173. ’DarkKhaki’ -> Color. ’DarkSeaGreen’ -> Color.new255(47.new255(139. ’DarkOrange’ -> Color. 193). 79). 34.new255(72. 104).new255(238. 205).new255(153. 69. 188. ’dark green’ -> Color. 140.new255(205.new255(233.new255(255. ’DarkGoldenrod3’ -> Color. 50. 107. 58. 150. 143). 15). 127. ’DarkGoldenrod’ -> Color. 0. 11). ’dark slate gray’ -> Color.new255(202. ’DarkSeaGreen1’ -> Color. 11). ’dark goldenrod’ -> Color. 0). 8). 107). ’DarkGoldenrod2’ -> Color. 206.new255(184.new255(0. 101. ’DarkOliveGreen3’ -> Color. ’dark orchid’ -> Color. 0). 238. 205). 12).new255(238.new255(193. 61). 204). 149.new255(154. 0). 209). ’DarkGoldenrod4’ -> Color. 143). 79). 614 . 61.new255(153.Where: Help→GUI→Color ’cyan3’ -> Color.new255(255. 47). ’dark orange’ -> Color. 140. ’DarkGoldenrod1’ -> Color. 0).new255(255. 122). 0).new255(205. ’DarkOliveGreen1’ -> Color. 183.new255(110. ’DarkOrchid4’ -> Color.new255(0. 102. 205. 100.new255(189. ’dark slate blue’ -> Color.new255(143. ’cyan4’ -> Color. ’DarkOrchid’ -> Color. 79.new255(0. 255. 14). 205.new255(233. 255).new255(184.new255(143. 211).new255(178.new255(139.new255(85. 204). ’DarkOrchid2’ -> Color.new255(188. 122). 0). ’dark khaki’ -> Color.

10.new255(238.new255(155. 205. 80). 26). 139). 191. 139. ’firebrick4’ -> Color.new255(30.new255(30. 206. 615 . 191. ’DodgerBlue’ -> Color. ’firebrick1’ -> Color. 105). 147).new255(255.new255(205. 105. 105).new255(0. 104. 20. 48). 79). ’DeepPink3’ -> Color. ’DeepPink4’ -> Color. 250. 34. ’DeepPink1’ -> Color.new255(139.new255(205. ’DimGray’ -> Color. 238. 205). 20. 178. ’dodger blue’ -> Color. ’deep sky blue’ -> Color.new255(121. ’DeepSkyBlue1’ -> Color. 255). ’DodgerBlue2’ -> Color.new255(238. 38. 139). 105).new255(141.new255(0. 240). ’deep pink’ -> Color. 255). 205). 26.new255(0. 238). 48.new255(105. ’DodgerBlue1’ -> Color. 255). 205). ’DeepSkyBlue3’ -> Color.new255(0. 105.new255(178. 78. ’DeepSkyBlue2’ -> Color. 205. ’DarkSlateGray2’ -> Color.new255(255. ’DeepPink’ -> Color. 144. 211). 154. ’DarkSlateGray1’ -> Color. 147).new255(82.new255(139. ’firebrick2’ -> Color. ’DarkSeaGreen4’ -> Color. 238). ’DimGrey’ -> Color.new255(16. ’firebrick3’ -> Color. 255). 105. ’DarkTurquoise’ -> Color. ’dim grey’ -> Color. 139. ’DarkSlateGrey’ -> Color. ’DarkSlateGray’ -> Color. 16. 18. 44.new255(72. 191. 255).new255(105. 20. ’DodgerBlue4’ -> Color. 147).new255(24. 155). 105).new255(255. 61.new255(148. ’DodgerBlue3’ -> Color. 139). 255). 238). ’dim gray’ -> Color. 79. ’firebrick’ -> Color. ’DarkSeaGreen3’ -> Color. 44). 105).new255(180. 144. 116.new255(0. ’DeepSkyBlue’ -> Color. ’DarkSlateGray3’ -> Color. 139). 79. ’DarkSlateBlue’ -> Color. 137). 144.new255(28.new255(30. ’DarkSlateGray4’ -> Color. 34).new255(47.new255(255.new255(0.new255(47.new255(255.new255(105. 255. ’DeepPink2’ -> Color. ’DarkViolet’ -> Color. 0. 79). ’DeepSkyBlue4’ -> Color. 118). 180). 209).new255(105.new255(105. 255).Where: Help→GUI→Color ’DarkSeaGreen2’ -> Color. 105.new255(0. 238.new255(151. ’floral white’ -> Color. 134. 38).

new255(41. 48). 43. 255). ’gray27’ -> Color. ’gray11’ -> Color. ’gray2’ -> Color. 56.new255(255.new255(54.new255(71. 28. ’ForestGreen’ -> Color. 193. ’forest green’ -> Color.new255(43. ’gray10’ -> Color. 220). 616 . 46. 248. 26). 64.new255(34. 43). ’GhostWhite’ -> Color. 41). 0. 38. 240).new255(56.new255(51. ’goldenrod’ -> Color. ’gray20’ -> Color. ’gray17’ -> Color. 54.new255(64.new255(59. 220. 105. 201.new255(28. 66. 215.new255(61.new255(5. ’goldenrod1’ -> Color. 255). ’gray0’ -> Color. 61). 165. 0). ’gold2’ -> Color. ’gold4’ -> Color. 0).new255(248. ’gray23’ -> Color. 59.new255(66. ’gray13’ -> Color. 38). 64). ’goldenrod2’ -> Color. 248. ’gray26’ -> Color. 34).new255(255.new255(46. 69. 250.Where: Help→GUI→Color ’FloralWhite’ -> Color.new255(3. 117. ’gray24’ -> Color. ’gray16’ -> Color. 26. 32). 31. ’gold’ -> Color. 255).new255(220. ’gray15’ -> Color.new255(255. 59). 3). ’goldenrod3’ -> Color. 36).new255(34.new255(238. 69). 155.new255(139. ’gold1’ -> Color. 51. 5.new255(38. 71. 139. 190).new255(205.new255(69. 56). 0). 48.new255(255. 255. 0). ’gray22’ -> Color. 71).new255(26. ’gray’ -> Color.new255(0.new255(255.new255(205.new255(31. 0). ’gray14’ -> Color. ’gray18’ -> Color. 173. 31).new255(33. 5). 33). 54).new255(190. 190.new255(248. ’gray100’ -> Color. ’gainsboro’ -> Color. 36. ’gray19’ -> Color. ’goldenrod4’ -> Color. 37). 61.new255(238. 20). 139.new255(36. ’gray21’ -> Color.new255(218. ’gold3’ -> Color. 0). ’gray28’ -> Color.new255(139. ’gray12’ -> Color. 41. 34). 3. ’ghost white’ -> Color. 66). 34). 28). 215. 51).new255(48. 180. 33. ’gray1’ -> Color. 46). ’gray25’ -> Color. 29).

new255(135. 120. 153.new255(158.new255(102. ’gray56’ -> Color. 8.new255(92. 140). 94.new255(133. 150. 10). 99). ’gray46’ -> Color. ’gray45’ -> Color. 163.new255(150. ’gray52’ -> Color.new255(89. 107).Where: Help→GUI→Color ’gray29’ -> Color. 92. 138). 122). 92). ’gray62’ -> Color. ’gray64’ -> Color. 161). 84). ’gray43’ -> Color. ’gray51’ -> Color.new255(8. ’gray3’ -> Color. ’gray34’ -> Color. 138.new255(99. 143. ’gray38’ -> Color. 145. 145). ’gray63’ -> Color. 133. 77). ’gray6’ -> Color. 102. 127. 122. 156). 94). 87. 115. ’gray49’ -> Color. 133).new255(153. 15. 89). 112. 82). 10. 97). ’gray32’ -> Color. 105.new255(112. ’gray58’ -> Color. 8).new255(10. 79. ’gray40’ -> Color. 105). 102).new255(84.new255(122. 156. 115). 125). 163).new255(74.new255(15. ’gray60’ -> Color. 617 .new255(107.new255(156.new255(145. 89. 13). 135).new255(82.new255(143.new255(13. ’gray33’ -> Color.new255(125. ’gray31’ -> Color. 127). ’gray59’ -> Color. ’gray55’ -> Color. ’gray53’ -> Color. 117. ’gray35’ -> Color.new255(79. ’gray48’ -> Color. ’gray50’ -> Color.new255(148. 135.new255(130. 77. 79). ’gray39’ -> Color. ’gray5’ -> Color. ’gray41’ -> Color. 107. ’gray37’ -> Color. 148. ’gray54’ -> Color. 150). ’gray44’ -> Color. 112).new255(161. 99. 87).new255(110. 158). 130. 143). ’gray4’ -> Color. 74. 82.new255(163.new255(117.new255(87. 148).new255(127. ’gray42’ -> Color. 161.new255(97. 153).new255(140. 120).new255(77. 13.new255(94. 84. 110. ’gray36’ -> Color. 140.new255(115. 74). ’gray30’ -> Color. ’gray57’ -> Color. 158. ’gray61’ -> Color. ’gray47’ -> Color.new255(105.new255(120. 15). 130). 125. 110). 97.new255(138. 117).

new255(201. ’gray7’ -> Color. 242. 232). ’gray78’ -> Color. ’gray93’ -> Color. 173). ’gray66’ -> Color.new255(191. 20). ’gray89’ -> Color. 252). ’gray80’ -> Color. 196.new255(173. 168). 176.new255(18. 209). ’gray73’ -> Color.new255(23. 199. ’gray77’ -> Color.new255(227. 168.new255(204. 255.new255(176. ’gray74’ -> Color.new255(20. 219. 252.new255(212. ’gray98’ -> Color. 20. 217. 224). ’gray96’ -> Color. 240). ’gray83’ -> Color. 222). 212). 181. 250). 222. 201). 194).new255(0. 173. 189.new255(219. ’gray84’ -> Color. 204. 204). 229. ’gray72’ -> Color. 214.new255(207. ’green yellow’ -> Color. 47). ’gray71’ -> Color. 179).new255(184. 207. 245. ’gray95’ -> Color.new255(235. 191. ’gray70’ -> Color. ’gray92’ -> Color. 171).new255(199.new255(173.new255(242.new255(224. 247). 191). 23. 186. 212. 186). 237.new255(181. 0). 18). 209. ’green’ -> Color. ’gray79’ -> Color. ’gray8’ -> Color. 166).new255(240. ’gray99’ -> Color. 232. 201. ’gray85’ -> Color. 23).new255(237. ’gray81’ -> Color.new255(171. 618 . ’gray97’ -> Color.new255(245. ’gray75’ -> Color.new255(222. ’gray94’ -> Color.new255(217. ’gray68’ -> Color. 18.new255(179.new255(189. 184). 214).Where: Help→GUI→Color ’gray65’ -> Color.new255(168. ’gray9’ -> Color. 227. 245). 235.new255(186.new255(250.new255(194. 207). 184.new255(196.new255(232. 240. ’gray91’ -> Color.new255(214. 235). 171. 247. ’gray69’ -> Color.new255(252. 229). 189).new255(247. 242). 199). ’gray88’ -> Color. ’gray90’ -> Color. 224. 237). 227). ’gray87’ -> Color. 181). ’gray76’ -> Color.new255(229. 176). 196). ’gray86’ -> Color. 250. 179.new255(166. 219). ’gray82’ -> Color.new255(209. 255. 166. ’gray67’ -> Color. 217). 194.

new255(33. ’grey32’ -> Color.new255(87. 190. 0. 71). 3. 5. ’grey16’ -> Color.new255(84. ’grey22’ -> Color. 61. 0). 59).new255(94. ’grey28’ -> Color. 38).new255(51. 33).new255(41. 41).new255(79. 36. 94. ’grey2’ -> Color.new255(0. 92. ’grey15’ -> Color. 47). 33.new255(69. 190). ’grey25’ -> Color.new255(92. 5). 54).new255(77. ’grey0’ -> Color. 77. 31. ’grey31’ -> Color.new255(36. 0).new255(74. 74. 54. 41. 46.new255(56. 92). ’green4’ -> Color. ’grey20’ -> Color. ’grey21’ -> Color.new255(66. 97.Where: Help→GUI→Color ’green1’ -> Color. 8). ’grey’ -> Color. 43. ’grey24’ -> Color. ’grey19’ -> Color. 66). 87).new255(43. 255. 31). 46). 255). 89). 238. 94). 139. 0). ’grey3’ -> Color.new255(59. ’grey37’ -> Color. 205. 28). 84). ’grey35’ -> Color.new255(64. 0). 26). 89.new255(5. ’grey38’ -> Color. 97).new255(190. 3). 64).new255(38.new255(26. 51. ’grey100’ -> Color. ’grey1’ -> Color.new255(48. 84. ’grey36’ -> Color. ’grey34’ -> Color. 69. ’grey14’ -> Color. ’grey10’ -> Color. 77). 0). ’grey13’ -> Color. 26. ’grey26’ -> Color.new255(54.new255(82. ’green2’ -> Color.new255(173. ’grey30’ -> Color. 64. 56). 619 . ’grey11’ -> Color. 66. ’grey17’ -> Color. ’grey27’ -> Color. 36). 43).new255(3. 87.new255(0.new255(46. 82). 255.new255(71. 255. 74). ’grey23’ -> Color.new255(0.new255(8.new255(0. 82. 59. 38. 69). 28. 51).new255(89.new255(61.new255(255. 79). 61). 71. 79. ’grey12’ -> Color.new255(31. ’green3’ -> Color. 56.new255(28.new255(0. 48). ’grey33’ -> Color. 48.new255(97. ’grey29’ -> Color. ’GreenYellow’ -> Color. ’grey18’ -> Color. 8.

’grey46’ -> Color.new255(125.new255(163.Where: Help→GUI→Color ’grey39’ -> Color.new255(107. 145).new255(179.new255(18.new255(130. 13). 163). 138). ’grey58’ -> Color. ’grey74’ -> Color. 115). 15).new255(13.new255(150. 102. 186. 140). 13.new255(148.new255(184. ’grey73’ -> Color. 127.new255(156. 156). 173. 189). ’grey62’ -> Color.new255(176. 122). ’grey68’ -> Color. ’grey61’ -> Color. 168.new255(189. ’grey59’ -> Color. ’grey60’ -> Color. 184). 143. 102).new255(168. 133). 99. 163.new255(110. ’grey5’ -> Color. 120. 620 .new255(135. 99). ’grey44’ -> Color. 153). 179). ’grey70’ -> Color.new255(143. 122. 112. 173). 161). ’grey69’ -> Color.new255(15. 125).new255(153. ’grey67’ -> Color. 171).new255(173.new255(117. 105.new255(186. ’grey71’ -> Color. 10. 130). ’grey64’ -> Color. ’grey51’ -> Color. ’grey53’ -> Color. ’grey40’ -> Color.new255(138. ’grey55’ -> Color.new255(112. 156. 18). 125.new255(127. ’grey56’ -> Color. 107. 107). 186). 143). 150. 120).new255(10. 110. 184. 10). 138.new255(102. 117.new255(140. 189. 179. 181.new255(145.new255(181. ’grey41’ -> Color. ’grey57’ -> Color. 135). 176. 176). 168).new255(122. 127). 158. ’grey66’ -> Color. 18. ’grey43’ -> Color. ’grey72’ -> Color. ’grey48’ -> Color. 115. 148). 140. 110).new255(99.new255(115. ’grey50’ -> Color. ’grey7’ -> Color.new255(166. 161. ’grey4’ -> Color. 105). 133. ’grey54’ -> Color. ’grey63’ -> Color. 112). 130.new255(171. ’grey42’ -> Color.new255(120. 158). ’grey52’ -> Color. 166). ’grey65’ -> Color. 171. 148. 166. 150). 145. 135. ’grey49’ -> Color.new255(158. ’grey47’ -> Color. 181). ’grey6’ -> Color. 153. 117). 15. ’grey45’ -> Color.new255(133.new255(161.new255(105.

232. 191.new255(201. ’HotPink2’ -> Color. 245. ’HotPink’ -> Color. 255. 255. 217. ’grey98’ -> Color.new255(245. 204. 180). 98).new255(205. 199). ’grey97’ -> Color.new255(229. 209. 23). ’grey92’ -> Color. 237).new255(212.new255(240. 180). 92. 240). 222). ’grey83’ -> Color.new255(20.new255(224.new255(219.new255(255. 199. 237. ’grey79’ -> Color. ’grey81’ -> Color. 224. 92). ’grey95’ -> Color.new255(227.new255(23. 214. ’HotPink3’ -> Color.new255(247. ’grey87’ -> Color. 242).new255(242.new255(240. ’honeydew2’ -> Color. 224). ’grey91’ -> Color. 191). 235). 92). 23. 247.new255(194. 194.new255(196. 242.new255(232. 96. 131). 229). ’grey99’ -> Color. ’grey85’ -> Color. ’honeydew’ -> Color. ’grey78’ -> Color.new255(204. 105.new255(209. ’grey86’ -> Color. ’grey82’ -> Color. ’grey9’ -> Color. ’HotPink4’ -> Color. 144). 58. 106. 222. 235. 110. 105. 212). 207).new255(240.new255(207. 240). ’honeydew4’ -> Color. 207. ’honeydew1’ -> Color. 20). ’grey88’ -> Color.new255(191. 196). 250). 194). 92. 196. ’hot pink’ -> Color. 193). 229. 180).new255(131.new255(255.new255(193. 204). 252.new255(238. ’grey77’ -> Color. ’grey89’ -> Color.new255(205. 20. ’grey76’ -> Color. 212. 247). 201.Where: Help→GUI→Color ’grey75’ -> Color.new255(222. ’grey90’ -> Color. 252).new255(217. 219. 227.new255(250. 621 . 232). ’grey84’ -> Color. ’grey8’ -> Color. 250. 238.new255(224. ’grey96’ -> Color.new255(139. 214). 201). 240.new255(199. 217). 209). 245).new255(214. 167). 240). ’grey94’ -> Color. 205. 139. 227).new255(237. ’IndianRed’ -> Color.new255(252. ’indian red’ -> Color. 219). 224).new255(235.new255(205. ’grey93’ -> Color.new255(255. ’HotPink1’ -> Color. ’honeydew3’ -> Color. ’grey80’ -> Color.

’LavenderBlush2’ -> Color. 193. 206. ’IndianRed4’ -> Color.new255(224. 58). ’light coral’ -> Color. 211. 128). 224). 250). 99). 193).new255(238.new255(230. 240. 238. 240.new255(139.new255(139. ’light cyan’ -> Color.new255(255.new255(124. ’ivory3’ -> Color. ’LemonChiffon1’ -> Color. 0).new255(124. ’LemonChiffon2’ -> Color.new255(255. 224. 85.new255(205. 170). 250. ’ivory1’ -> Color.new255(255. 229). 131. ’lavender’ -> Color. 230. ’LawnGreen’ -> Color. 211. 106. 245). ’light goldenrod’ -> Color.new255(205.new255(32. 230). 250. 78). ’light pink’ -> Color. 205). ’LavenderBlush3’ -> Color. 240). ’lawn green’ -> Color.new255(238. 143). ’LavenderBlush1’ -> Color. 193).Where: Help→GUI→Color ’IndianRed1’ -> Color.new255(255. ’khaki’ -> Color. ’light goldenrod yellow’ -> Color. 250. ’khaki1’ -> Color.new255(255. 230. 233. ’LemonChiffon4’ -> Color. 245).new255(139. ’light salmon’ -> Color. 112). 211).new255(255. ’light blue’ -> Color. 85). 198. 240. 191). ’light sea green’ -> Color.new255(255. 246.new255(173. 137. ’ivory2’ -> Color.new255(255. 205). 140).new255(255. ’light gray’ -> Color. 178. 128. 131). ’LavenderBlush’ -> Color. ’ivory4’ -> Color.new255(240. ’khaki3’ -> Color. 255. 182.new255(205. ’khaki4’ -> Color. 201.new255(250. 115). 245). 99. 205. ’IndianRed2’ -> Color. 255. 252. 130).new255(211.new255(238.new255(135. 134. 165).new255(139. 255).new255(205. 250.new255(255.new255(238. 622 .new255(240. 240). 221. 211). ’lavender blush’ -> Color. 210). ’LavenderBlush4’ -> Color. ’khaki2’ -> Color.new255(238. 106). 134). 216. ’LemonChiffon’ -> Color. 250). 122). ’IndianRed3’ -> Color.new255(255. ’ivory’ -> Color. 252. 197). 205).new255(205. ’light grey’ -> Color.new255(238. ’LemonChiffon3’ -> Color. 255.new255(139. ’lemon chiffon’ -> Color.new255(255. 139. 58. 160. 0). ’light sky blue’ -> Color. 230. 133).new255(211.

160. ’LightPink4’ -> Color. 112). ’LightCyan’ -> Color. ’LightSkyBlue3’ -> Color. 623 . ’LightPink2’ -> Color. 101). ’LightSkyBlue4’ -> Color.new255(176. 139). ’LightGoldenrodYellow’ -> Color.new255(178. 221.new255(119. ’light steel blue’ -> Color. 255.new255(205.new255(211.new255(205.new255(255. 211.new255(139. 255). 140. 205. 211. 206. ’LightBlue1’ -> Color. 122). 98). ’LightSalmon4’ -> Color. ’LightSalmon’ -> Color. 170).new255(122. 87. 223. ’LightGoldenrod1’ -> Color. 255. 193). 211). 130). 190. 128. 130). 238. ’LightSeaGreen’ -> Color. ’LightPink1’ -> Color. 226. 205). 220.new255(205. ’LightGray’ -> Color.new255(224.new255(176. 236.new255(164. ’LightGoldenrod4’ -> Color. 205). 139).new255(238. 139. ’LightSkyBlue’ -> Color. 211. ’LightPink’ -> Color. 230). 95. 153). ’light slate grey’ -> Color.new255(135. 196. 205).new255(238.new255(255. ’LightSalmon2’ -> Color.new255(139.new255(209. 149. ’LightSalmon3’ -> Color. 239.new255(238. 153). ’LightBlue4’ -> Color. 250). ’LightCyan4’ -> Color. ’LightSkyBlue1’ -> Color. 173).new255(139. 160. 112.new255(255. 114). 192. 182. ’LightGoldenrod3’ -> Color. 255.new255(132.new255(255.new255(173. 211). ’LightPink3’ -> Color. ’LightGrey’ -> Color. 128). 216. ’LightGoldenrod’ -> Color. 238). 122).new255(141. 136. 66). 255). 255). 178. ’LightCyan2’ -> Color. ’LightSkyBlue2’ -> Color. 250. 129. ’LightBlue2’ -> Color.new255(180. ’LightSalmon1’ -> Color. ’LightCyan1’ -> Color. ’LightBlue3’ -> Color. 136.new255(119. ’LightCoral’ -> Color. 182.new255(224. 174. 185). 149). ’light slate gray’ -> Color. 238). ’LightBlue’ -> Color. 222).new255(211. 162.Where: Help→GUI→Color ’light slate blue’ -> Color. 139).new255(238. 224).new255(240.new255(191. 238). 210).new255(32.new255(96. 123.new255(255.new255(250.new255(104. 129. 131.new255(255. 255).new255(154. 255). ’LightCyan3’ -> Color. 139). ’LightGoldenrod2’ -> Color. ’light yellow’ -> Color. 76).

139.new255(205. 181. 0. 167). 180).new255(132. 255).new255(147. 238). 205. 123.new255(119. 112. ’lime green’ -> Color. 98). 238).new255(205.new255(50.new255(102. ’maroon4’ -> Color. ’linen’ -> Color. 52.new255(186. 96). 144). ’MediumOrchid’ -> Color. 205. ’LightYellow2’ -> Color. ’MediumOrchid2’ -> Color. ’MediumBlue’ -> Color. 48. 224). ’medium violet red’ -> Color. ’LightSteelBlue’ -> Color.new255(110. 154). ’magenta1’ -> Color. 209. ’LimeGreen’ -> Color.new255(209. ’maroon3’ -> Color. ’medium aquamarine’ -> Color.new255(250. 238). 209). 205. 205).new255(123. ’LightYellow4’ -> Color.new255(238. 41. 28. 136. 624 . 211). 102. ’LightSteelBlue3’ -> Color. 21. 0. ’LightSteelBlue4’ -> Color.new255(0. ’LightYellow3’ -> Color. 238). 0. 255. 240. 205).new255(238. 48. 0. ’medium purple’ -> Color.new255(176. ’MediumOrchid1’ -> Color. 250.new255(60. 211). ’medium spring green’ -> Color.new255(102.new255(255. 139). 225.new255(224. 204). 238. 196. 205. ’medium slate blue’ -> Color. ’magenta2’ -> Color.new255(255. ’MediumAquamarine’ -> Color.new255(139. ’LightYellow’ -> Color. 255). 153).new255(255.new255(139. 139). 50). 170).new255(255.new255(0. 133).new255(186. 179. 0. 255. 255). ’magenta4’ -> Color. 255).new255(119. ’medium orchid’ -> Color. 205). 205). ’medium blue’ -> Color. 153). 95.new255(202. ’LightSteelBlue2’ -> Color. ’magenta’ -> Color. ’LightSlateGray’ -> Color. 85. 170). 113).new255(139. 179). ’LightSlateGrey’ -> Color. 0. 210. 219). ’maroon2’ -> Color. ’LightYellow1’ -> Color. 230).new255(238. ’maroon’ -> Color.new255(188.new255(0. ’maroon1’ -> Color.new255(205.new255(255.Where: Help→GUI→Color ’LightSlateBlue’ -> Color. 255). ’medium turquoise’ -> Color. 224).new255(50. 0. ’magenta3’ -> Color. 50).new255(72. 122). 104. 222). 205. 112.new255(199. 136. ’medium sea green’ -> Color. ’LightSteelBlue1’ -> Color.new255(176. 85.new255(162.

’MediumPurple2’ -> Color. 213. ’NavajoWhite2’ -> Color.new255(179. 179. ’olive drab’ -> Color. 34). 128). ’MediumPurple3’ -> Color. 128). ’MediumTurquoise’ -> Color. 205.new255(255. 0. 142. ’NavajoWhite4’ -> Color.new255(139. 139). 225).new255(137.new255(255.new255(205. ’navajo white’ -> Color.new255(107. 179. 245. ’MediumSlateBlue’ -> Color. 255. 104. 228. ’navy’ -> Color.new255(123. 238).new255(72. ’MediumSpringGreen’ -> Color. 161). 128). 228. 225).new255(154. 625 . ’MediumSeaGreen’ -> Color.new255(25.new255(0. 21. 205). 238). ’navy blue’ -> Color. 139).new255(0. ’NavajoWhite1’ -> Color. 112). ’old lace’ -> Color. ’MediumPurple4’ -> Color. 133).new255(0. ’MidnightBlue’ -> Color. 181). ’misty rose’ -> Color. 209. ’mint cream’ -> Color. ’MediumOrchid4’ -> Color.new255(171.new255(238. 228.new255(180.new255(122. 205). ’MistyRose2’ -> Color. 62). 0. 50). ’MistyRose1’ -> Color. 173). 25. 222.new255(238.new255(205. ’MistyRose3’ -> Color. ’moccasin’ -> Color. ’MediumPurple’ -> Color.new255(60. 125. 250. ’OliveDrab’ -> Color. 181). 113). 139. ’midnight blue’ -> Color. 222.new255(107. ’OliveDrab2’ -> Color. 228. 173). 225).Where: Help→GUI→Color ’MediumOrchid3’ -> Color. 183. 130.new255(255. 71.new255(0.new255(93. ’MediumVioletRed’ -> Color. 230).new255(255. 219).new255(105. 55.new255(139. 238. 255).new255(253.new255(255. 0. ’NavajoWhite’ -> Color. 58). ’NavajoWhite3’ -> Color. 139).new255(25. 255. ’OliveDrab3’ -> Color. 154). ’MintCream’ -> Color. 207.new255(245. 25. ’MediumPurple1’ -> Color.new255(147. 255. 123). 104.new255(159.new255(192. 121. 222. 210). 94). 112. 245. 142.new255(253.new255(245. ’OldLace’ -> Color. 250). 173). 35). 230). 82. 121. 112). 35). ’MistyRose’ -> Color. ’MistyRose4’ -> Color. ’NavyBlue’ -> Color.new255(199. 204). ’OliveDrab4’ -> Color. ’OliveDrab1’ -> Color. 250).new255(255.new255(255.

’orchid’ -> Color.new255(139. 238). 255. ’orchid3’ -> Color. 122. 133.Where: Help→GUI→Color ’orange’ -> Color.new255(205. 0). 139). 232. ’pale goldenrod’ -> Color.new255(152.new255(255. ’OrangeRed4’ -> Color. 121. 214).new255(102.new255(205. ’papaya whip’ -> Color. 205). 90. 170). 152). ’PaleTurquoise3’ -> Color. 159). 131. ’pale green’ -> Color. 0). ’OrangeRed3’ -> Color. 238.new255(84.new255(255.new255(175. 137). ’PaleGreen3’ -> Color. ’PaleGreen1’ -> Color.new255(255. 626 . 64. 112. ’OrangeRed’ -> Color. 171). 238. ’pale violet red’ -> Color. ’orange4’ -> Color.new255(255. ’PaleVioletRed1’ -> Color. 251. 55. ’PaleTurquoise’ -> Color. 185). 124). 69. 0). ’orange red’ -> Color. ’orange3’ -> Color.new255(150. 130. ’OrangeRed1’ -> Color. 71. 255.new255(124. ’PeachPuff’ -> Color. ’peach puff’ -> Color. 0). ’PapayaWhip’ -> Color. 232. 84). 251. ’PaleVioletRed2’ -> Color.new255(219.new255(205.new255(139. 144). 139. 213). 0).new255(238. 233). 218. ’orchid4’ -> Color.new255(152.new255(139. ’pale turquoise’ -> Color. 238). 238. ’PaleVioletRed’ -> Color.new255(238. 152). 239. 250).new255(218. 139.new255(255. 37.new255(205. 0). 69. 255). 93). 170). 185).new255(238. 104. ’PaleGreen2’ -> Color. ’PaleTurquoise4’ -> Color. 105. 147). 238. 147). 165. ’PaleVioletRed3’ -> Color. ’orchid1’ -> Color. 201). 0). 0). 154). 213). 205. 165. 239.new255(174. ’PaleTurquoise1’ -> Color.new255(255. ’PaleVioletRed4’ -> Color.new255(255. 71.new255(144.new255(238. 69.new255(255. 0). 112. 218. ’PaleGreen’ -> Color.new255(139.new255(219.new255(238.new255(175. ’orange1’ -> Color. ’PaleGreen4’ -> Color. 238).new255(187. 0).new255(255. 0).new255(255.new255(238. ’orange2’ -> Color. ’PaleTurquoise2’ -> Color.new255(255. ’OrangeRed2’ -> Color.new255(154. 137). ’PaleGoldenrod’ -> Color. 205. 154. ’orchid2’ -> Color. 112.

155).new255(139.Where: Help→GUI→Color ’PeachPuff1’ -> Color. ’RoyalBlue2’ -> Color. ’PeachPuff2’ -> Color.new255(205.new255(255. 143.new255(205. 139).new255(238.new255(205. 158). 44. ’PeachPuff3’ -> Color.new255(255. ’plum1’ -> Color.new255(72. ’RoyalBlue4’ -> Color. 205). 187. 105). 155. 0. ’red4’ -> Color. ’peru’ -> Color. 230). 205). ’saddle brown’ -> Color. 184). ’purple1’ -> Color.new255(139. 110. 175. ’pink4’ -> Color. 139). 143. 169. ’red’ -> Color.new255(238. ’purple4’ -> Color.new255(65. ’red1’ -> Color. 38.new255(139. 197). 0). 48. 173). ’pink’ -> Color. 238). 150. 193). ’plum3’ -> Color.new255(255. 0). 192. ’pink2’ -> Color. ’red2’ -> Color.new255(85. 145. 0).new255(238. ’red3’ -> Color. 180).new255(139.new255(125. 105. 143). ’purple’ -> Color. 0. ’purple2’ -> Color. 102. ’RoyalBlue3’ -> Color.new255(176. 180. 203. ’PowderBlue’ -> Color.new255(255.new255(67. 64.new255(39. ’RoyalBlue1’ -> Color. 26. 203). ’pink3’ -> Color.new255(238. 224. 218.new255(221. 240). ’RosyBrown1’ -> Color. 221).new255(238.new255(58. 225). 63). 32. 230). 174. 99.new255(205. 193. 238). 255). 139). 69.new255(155. ’plum4’ -> Color.new255(205. 0. 255). 224. 627 . 255). ’plum2’ -> Color. ’RosyBrown4’ -> Color.new255(176.new255(255. 118. 185). 105. 119. 133. 149).new255(188. 105. 143). ’powder blue’ -> Color. ’royal blue’ -> Color.new255(139. ’RosyBrown’ -> Color. 238).new255(205. 0).new255(255. 181. 0.new255(139. ’PeachPuff4’ -> Color. 0. ’RoyalBlue’ -> Color. 108). 95. ’purple3’ -> Color. 160. 101). 225). ’plum’ -> Color.new255(145.new255(188. ’RosyBrown2’ -> Color.new255(255. ’RosyBrown3’ -> Color. 19).new255(160. ’pink1’ -> Color. ’rosy brown’ -> Color. 0).new255(65. 205).

166. 222). 45). 71). ’seashell’ -> Color. 144).new255(139. 139). ’SkyBlue2’ -> Color.new255(112. ’salmon2’ -> Color. ’SkyBlue’ -> Color. ’SlateBlue2’ -> Color.new255(160.new255(238. ’SeaGreen’ -> Color. ’sky blue’ -> Color. ’SkyBlue1’ -> Color. 103.new255(46. 87). ’salmon4’ -> Color. 128. ’SkyBlue3’ -> Color. 76. ’SlateBlue1’ -> Color. ’seashell3’ -> Color.new255(139. 255).new255(78.new255(205. 104. ’SandyBrown’ -> Color.new255(71. ’SlateBlue4’ -> Color. 144). 205). ’sienna2’ -> Color. 628 .new255(198. 90.new255(135.new255(67. 164. 164.new255(238. 139).new255(244. 205). 114). ’sienna1’ -> Color. ’SeaGreen3’ -> Color. 245. ’salmon’ -> Color. ’SlateBlue’ -> Color. ’slate grey’ -> Color. ’sea green’ -> Color. 19). 84).new255(250.new255(106. 144). 57). 112. 238). 128. ’SlateGray’ -> Color. 197. ’SlateGray1’ -> Color.new255(205.new255(131. 82. 238). 206.new255(46. ’SkyBlue4’ -> Color.Where: Help→GUI→Color ’SaddleBrown’ -> Color.new255(255. 87). ’seashell4’ -> Color.new255(205.new255(255.new255(112. 134. 89. 139. ’salmon3’ -> Color. 96).new255(108. ’seashell2’ -> Color. 57).new255(238. 255).new255(112. 98). 245. 148). 235). 130).new255(46. 96).new255(135. 121. ’sandy brown’ -> Color. 90. ’slate blue’ -> Color. ’sienna3’ -> Color. 205). 238).new255(122. ’SeaGreen1’ -> Color. 128. 192. ’SeaGreen4’ -> Color.new255(255. 60. 38). 69. ’seashell1’ -> Color.new255(139. 112. ’sienna4’ -> Color.new255(255. 205. 206. ’SlateBlue3’ -> Color.new255(84. 139. 159). 229. ’sienna’ -> Color. 226. 105).new255(135. 130.new255(126. ’salmon1’ -> Color. 130. 140. ’SeaGreen2’ -> Color. 71. 238). 255). 128).new255(74. 206.new255(139. ’slate gray’ -> Color.new255(244. 255. 66).new255(106. 139.new255(105. 235). 205). 87). 128. 238. 191). 111.

255). 205). 224. 238). 205).new255(0.new255(108. 139).new255(139. 255. ’snow1’ -> Color.new255(64. 71). 201). 69).new255(70. ’SteelBlue2’ -> Color. 148. 154. ’snow2’ -> Color. 144). 139.Where: Help→GUI→Color ’SlateGray2’ -> Color. 238). 92. ’SpringGreen4’ -> Color.new255(139. ’SlateGray3’ -> Color. 238). 250). 99.new255(205. 140). 238).new255(92. 73). 208).new255(112. ’tomato3’ -> Color. ’tan4’ -> Color.new255(0.new255(185. 250. 205).new255(255. ’SpringGreen2’ -> Color. 245. 201. 180. 130. ’tomato’ -> Color. 205. 38). 255.new255(159. 123. ’thistle2’ -> Color. 90. 123. ’tan1’ -> Color. ’snow4’ -> Color.new255(70. ’SteelBlue’ -> Color. 54. ’thistle1’ -> Color.new255(54. ’SpringGreen’ -> Color.new255(0. ’SteelBlue1’ -> Color. 139). 43). 181.new255(0. ’tomato2’ -> Color. 63).new255(255. 184.new255(238. ’SlateGray4’ -> Color. 238.new255(99.new255(255. ’tomato1’ -> Color. ’snow3’ -> Color. ’turquoise’ -> Color. 99. 127). ’SteelBlue3’ -> Color. 233.new255(255. 197. 79). 172. ’SlateGrey’ -> Color. ’thistle4’ -> Color. ’SpringGreen3’ -> Color.new255(139. 250.new255(216.new255(0.new255(0. ’SteelBlue4’ -> Color.new255(79. 629 .new255(238.new255(255. ’tan2’ -> Color. 229. 205). 79. ’tan3’ -> Color. 165.new255(210. 71). ’thistle3’ -> Color. 102). 130.new255(205.new255(205. 137). 250).new255(238.new255(0. ’turquoise2’ -> Color.new255(205. 127). 57). ’turquoise3’ -> Color. 182. 255). 139). 216).new255(0.new255(139. ’tan’ -> Color. 180). 180). 66). ’thistle’ -> Color. 210.new255(255. ’spring green’ -> Color. 225. 127). 137.new255(238. ’snow’ -> Color. 255). 191. ’SpringGreen1’ -> Color. ’turquoise1’ -> Color. 100. 128. 133. 118).new255(0. 233). 211. ’tomato4’ -> Color. ’steel blue’ -> Color. 255.

’white smoke’ -> Color. ’VioletRed2’ -> Color. 255). 139). ’yellow green’ -> Color. 144). ’yellow3’ -> Color. ’wheat’ -> Color. 0). ’VioletRed’ -> Color.new255(255.new255(0.new255(255.new255(154.new255(154.new255(205.new255(255.new255(238. ’violet red’ -> Color. ’VioletRed1’ -> Color. 186). 179). 222. 245. ’wheat3’ -> Color. 144). 32. ’violet’ -> Color. 0). 216. 0).new255(238.new255(205.new255(139. ’wheat1’ -> Color. 139. 255. ’yellow2’ -> Color. ’white’ -> Color.new255(245. 0). 134.new255(208. ’VioletRed3’ -> Color. 140). 32. ’yellow’ -> Color. 102). 174). 126. 130.new255(208. 238. 186.new255(255. 34. 50) 630 . ’VioletRed4’ -> Color. 238). 255. 58. 50. ’wheat2’ -> Color. 245). ’wheat4’ -> Color.new255(139. 205. 205.new255(245. 205. ’YellowGreen’ -> Color.new255(205.Where: Help→GUI→Color ’turquoise4’ -> Color. 50).new255(255.new255(139. 255.new255(238.new255(245.new255(238. 0). 231. 245. 62. 150). ’WhiteSmoke’ -> Color. ’yellow4’ -> Color. 245). 120). 82). ’yellow1’ -> Color. 150).

text.open(path). Document.help.closeAll(leavePostOpen) by default the postWindow stays open. "where are my glasses?"). Document. "this is the text").open("Help/Help. "’hardly see anything"). Document. Document.blue(alpha:0.new("this is the title".allDocuments array where all open documents are stored. ) stringColor_ set the text color of a Document ( a = Document("background". Document. Document. 631 .Where: Help→GUI→Document ID: 199 Document Document(title. isPostWindow). a. background_ set the background color of a Document ( a = Document("background".rtf"). Document. Document.hasEditedDocuments returns true if there are unsaved changes in one of the open Document.background_(Color.8)).closeAllUnedited(leavePostOpen) by default the postWindow stays open.current returns the current Document.

doc.stringColor_(Color. ) syntaxColorize same as command’ ( a = Document.Where: Help→GUI→Document a.red). ) font_(font.syntaxColorize. doc. 1. ) 632 .red(alpha:0.allDocuments.wait. "closing in 2 seconds").wait. a. doc = Document("background".stringColor_(Color.postln.play(AppClock).red).isEdited.at(0). doc.8)).8)). }). rangestart.red(alpha:0.close. rangesize) set font.background_(Color. if rangestart = -1 for the whole document bounds_(Rect) set bounds close close a Document ( Task({ var doc.background_(Color. 1.current. ) isEdited returns true if a Document has unsaved changes unless it is the postWindow ( Document.

current. ) selectRange(start.current.selectRange(doc. doc = Document. 633 . ) selectedString get the currently selected text.Where: Help→GUI→Document selectLine ( Document.string.current.selectedString.current. 10).current. ) selectionStart get the current position in the text ( Document. ) selectionSize get the current size of selection in the text ( Document. 100). ( var doc.selectLine(1). doc.selectionStart.current.selectionStart. length) ( Document.selectionStart-40. ( Document.postln. doc.selectionSize. rangesize) get the text of a document.postln. ) string(rangestart.current.selectRange(Document.postln. If no rangestart is applied the whole text is returned.

) keyDownAction_ register a keyDownAction. doc = Document. \n". txt = "doc. [doc. doc = Document.at(0).keyDownAction_(nil). modifiers].current. txt.current. key. this is useful for macros ( var doc.postln. num. modifiers. key. ) ( Document.front. txt. doc.selectedString_(txt).string_("set a String") ) selectedString_ insert text at the current position ( var doc.current.keyDownAction_({arg doc.allDocuments. doc = Document(string:"").postln }).Where: Help→GUI→Document ) string_(string. if rangestart is -1 (default) the whole text is replaced ( var doc. doc. rangestart. ) front ( Document. ) 634 . rangesize) set the text of a document. doc.

}). q = ProxySpace.").background_(Color(0.toFrontAction_({ if(currentEnvironment == q. a."). out.pop. r = ProxySpace. 1.{r. r. 1. q.{q.ar([400. b.9.0)). 0. q. }). ( Document.0.push.current.toFrontAction_({ if(currentEnvironment == r. s.local.push(r).0. 1.2) }.0. ) ( //need to pop proxyspace from other examples q. "//this is proxyspace q \n x = 0.boot.8.Where: Help→GUI→Document toFrontAction_ called when the window is clicked to front example: associate a proxyspace to two different windows. b.9.pop ) onClose_ register a close . a = Document("proxy r".pop}). ( s = Server. a.play.pop. 0.ar([1400.8)). r. 1500]*0.action. 500]*0. \n out = { SinOsc. 0.play.push(s).background_(Color(1. "//this is proxyspace r \n x = 0.push.2) }.pop}).onClose_({ 635 .pop r. \n out = { SinOsc. out. b = Document( "proxy q".

{ {EnvGen.play.current.play.background_(Color. 0.play(AppClock). }) ) test here and click in front of the number: 17 23 636 .720. if(char == "23".8)).perc.ar(0. Server. Task({ doc. doc = Document("before closing".1.red).kr(Env.5)}. doneAction:2) * SinOsc. Document.ar([600.3.2)}.selectionStart."did you call me?").mouseDownAction_({arg doc.boot. char = doc.choose.rangeText(doc. 2). doc.close.Where: Help→GUI→Document var doc.{ {EnvGen.kr(Env. var char.wait. }). if(char == "17".local. 0.red(alpha:0. }). doneAction:2) * PinkNoise.perc.300]. }) ) mouseDownAction_ ( //add a mouse action to this document: //example: easy button: //when you click in front of a 17 a SinOsc will start up.wait. doc.stringColor_(Color. 0. }). 0.

Task({ var co.02.choose).0.1. doc.9.choose). doc = Document("".at(0).rand)).do({ 1. Task({ 100.0. "| | "). co = co * mul. if(co > 0."-". [7. co)).stringColor_([Color. { co = 0.play(AppClock).do({ 0. }) }). doc. mul.choose). doc.unfocusedFront ) ( var doc. 637 .wait.play(AppClock).01. 1.1 }).0.Where: Help→GUI→Document unfocusedFront_ ( Document.wait.08.do({ 1.selectedString_(["\"\n#".green(alpha: 1.8.rand).blue(alpha: Task({ 1000.play(AppClock).16.99. "--"]. mul = 1.do({ doc. doc.allDocuments.wait.setFont(size: 0.rand)].blue(alpha: }). 100.background_(Color. 1."| | ".wait.24].background_(Color.01.red(alpha: }) }). }) }). Color. Task({ 100. co = 0.

By default the document directory is SuperCollider’s application directory. also converts from OS9 macintosh path format. expand tildes in path (your home directory). }).Where: Help→GUI→Document doc.standardizePath( " /Documents/SC3docs/Patches/newfoots/fastRuckAndTuck" ) Patches/newfoots/fastRuckAndTuck Document. 638 . Document. expand it to an absolute path relative to your document directory.play(AppClock) ) // Utilities and settings for dealing with documents such as super collider code files.standardizePath( ":Patches:newfoots:fastRuckAndTuck" ) /Volumes/Macintosh HD/Users/cruxxial/Documents/SC3docs/Patches/newfoots/fastRuckAndTuck Document. In Main-startUp you can set this to a more practical directory: Document. *standardizePath if it is a relative path.standardizePath( "Patches/newfoots/fastRuckAndTuck" ) Patches/newfoots/fastRuckAndTuck *abrevPath reduce the path relative to your document directory if possible.dir = " /Documents/SuperCollider". resolve symbolic links (but not aliases).close.

Where: Help→GUI→Document 639 .

openAutoComplete Autocompletion will be integrated more tightly into the code editor. and present a list of class methods (not instance methods).3 Usage: To open a text window with the auto-complete feature enabled. Summary: While editing code in an auto-complete code window. Making a selection will insert a method template into your document. Document.Where: Help→GUI→DocumentAutoCompletion ID: 200 SuperCollider autocompletion v0. with the . Your selection will insert a method template into the document.autoComplete (ac is a shortcut for Auto-complete. ( will also match classnames.openFileAutoComplete("*. .sc"). the following keystrokes initiate special actions: ( – attempt to match the preceding identifier to method names containing that string. and display a list of methods with their defining classes. to make it easier to type.) To open a file by pathname: Document. // wildcards are supported To bring up an open-file dialog: Document. execute the following in SuperCollider: Document.openFileAutoComplete("myPath. – attempt to match the preceding identifier to an exact class name. 640 .rtf").new method: Rect( will show you a method template for Rect-*new.

– when you choose a method in a class browser. leaving the text: SinOsc. then the list will contain only: ar(freq. add) 641 . the class from the class browser. a window will be presented with all the class methods (not instance methods) of the class. This allows speedier location of methods inherited from superclasses. If you type ’a’.ar(freq.. and press enter in the method list to insert a method template. otherwise. mul.. Your selection will open a class browser. So. mul. and the method name with all its arguments will be added to your document. the list will reduce itself to the matching entries.Where: Help→GUI→DocumentAutoCompletion ctrl-. the initial class will be put into the document. its class will be compared to the class you chose in the opening list. mul. for example. Special behavior for ctrl-. If the initial class responds to the method. SuperCollider will to check the previous text to see if it refers to a valid class. phase. You can navigate through the class tree to find the method you want. Feature description: When you type a dot. If so. add) Press enter or return. if you type: SinOsc. the window will display the options: ar(freq. Shortcut in the class browser: type ^ in the method list to go to the superclass. If you type the first few letters into the text box. add) buildSynthDef() buildSynthDef_() . – attempt to match the preceding identifier to class names containing the identifier. and present a list of those class names. phase.. phase.

it presents you with all possible options and allows you to choose. Pressing escape or closing the window will cancel the auto-complete.value(’. if you keep typing while the box comes up and you want to ignore it. etc. Type the first few letters of the class name (don’t forget to capitalize) to choose the right one. the text editor has no way to know what kind of object will be contained in func at the time of execution. but by typing ctrl-dot). After you choose from the list. do. Because of the way the document class works. you will be given a list of classes matching the string typed.Where: Help→GUI→DocumentAutoCompletion You can also click on the item you want in the list (or move through the list with the up and down arrow keys). 642 . SuperCollider will display a list of all classes that define this method. I like to exclude the most common flow of control mechanisms (while. the identifiers will not be extracted correctly if the cursor is at the very end of the document. a full class browser will be opened. Text typed into the text box prior to canceling will be added to the document–so.rtf file in a folder called scwork in your home user directory. you may press ^ to go to the superclass. You can define class names and method names to be excluded from the browsers. Quirks and caveats: The auto complete features will be lost from all documents when recompiling the class library. if. When you select a method and press enter. In the case of classes. Further configuration: Place the startup. New: The autocompleter now supports partial string matching for methods (triggered by typing open-paren) and classes (not by typing dot. a method template will be dropped into the current document. Because the class browser does not show methods defined by superclasses. You should leave a couple of empty lines below what you’re typing for the feature to work. This treatment is necessary because variables in SuperCollider are not typed. Similar behavior for method names: when you type an open parenthesis ’(’. So. and then press return. If you enter ’func. your text will not be lost.).

please. you won’t find Array in the list (but you will find its superclass ArrayedCollection). If you’re browsing a method like ’add’. No SPAM! 643 .com.Where: Help→GUI→DocumentAutoCompletion The method browser does not handle inheritance. Comments or questions to jamshark70@yahoo.

a Point giving the width and height of the combined views.boot. then it uses the ControlSpec’s default value. default is 80. controlSpec. the rounding precision for the number box display. The default value for round is 0. numberWidth . dimensions. num- EZSlider(window. dimensions . initVal.Where: Help→GUI→EZSlider ID: 201 EZSlider ber box wrapper class for label.number of pixels width for the label.a String controlSpec . initAction.default = s.the SCWindow containing the views. window . The default is false. numberWidth) EZSlider is a wrapper class for managing a label. slider.the ControlSpec for the value.the value to initialize the slider and number box with.a Boolean indicating whether the action function should be called when setting the initial value. s. The function is passed the EZSlider instance as its argument.internal. numberView Another useful instance variable is round. label. The contained views can be accessed via the EZSlider instance variables: labelView.number of pixels width for the number box. default is 80. initAction . If nil. ) ( // define a synth 644 . action.001 . label . sliderView. Server. action . labelWidth. Example: ( // start server s = Server. labelWidth . initVal . slider and number box.a function called when the value changes.

645 . "note". 75 @ 24).1. { LFSaw. 0.bounds). gate.1. 0.ar(x[0]. w.ar(0.view.1.softclip.black.0.fill(4. }.front. id. // add a button to start and stop the sound.kr(Env.action = {| view| if (view.ar(x.rand(0. // generate a note id. var id. 180)). // make the window w = SCWindow("another control panel". fc = 1000. var balanceControl.rand2}. cmdPeriodFunc.1.1. "window-test". ( var w.sendMsg("/s_new".softclip. x).1.choose. x = RLPF.nextNodeID.1. 400. ampControl. fc.\v]. Rect(20.02) }).Where: Help→GUI→EZSlider SynthDef("window-test".0. x = x * EnvGen. [0.midicps. Color. resonControl. x = RLPF. startButton = SCButton(w.red] ].1. bal).green].background = HiliteGradient(Color. Color.view. 440. noteControl. x = Balance2.white. w.states = [ ["Start". { arg note = 36. amp=0.25. 0.value.load(s). ["Stop". // make window visible and front window. 100. 0.dup).9)).4. 0.0).1. ) 2). startButton.0). id = s. fc. rq). x = Mix. Color. Color. 0.0.cutoff. gate = 1. rq = 0. startButton. w.ar((note + {0. cutoffControl.value == 1) { // start sound s. 0. noteControl. 0. amp). var x.view. x[1]. bal=0. rq. [\h.Color.ar(x.decorator = FlowLayout(w. doneAction: Out. rrand(0. 0] ). startButton.rand(0.

ControlSpec(0. 0. // set start button to zero upon a cmd-period cmdPeriodFunc = { startButton. ez. }.decorator. CmdPeriod. cutoffControl = EZSlider(w. id.decorator. id. 36). id. balanceControl. balanceControl = EZSlider(w.sendMsg("/n_set". {| ez| s. }.value).add(cmdPeriodFunc). ez.value. ControlSpec(200. "bal". "Amp".view. 0).value). ez. 400 @ 24. "gate". id.value.decorator.onClose = { s. 400 @ 24. }.nextLine. "note". }. "Note".value. "fc". {| ez| s.dbamp). w.sendMsg("/n_set". \lin. }.dbamp). {| ez| s.value). noteControl = EZSlider(w. "Cutoff". 400 @ 24. 1). cutoffControl. }. "amp". 5000. 400 @ 24.view. // stop the sound when window closes and remove cmdPeriodFunc. if (view.value.decorator. id). 60.Where: Help→GUI→EZSlider "fc". \exp). ControlSpec(24.decorator. id. ez.value. -6). 0.sendMsg("/n_set".sendMsg("/n_free". w. "Balance".sendMsg("/n_set".nextLine. w. "bal". }.nextLine. "rq". }. "amp". id. w.sendMsg("/n_set". "Resonance".value == 0) { // set gate to zero to cause envelope to release s. "rq". }.2). {| ez| s.view. \bipolar.view.nextLine.1. 646 .value = 0. ez.view. resonControl. w. resonControl = EZSlider(w.7). 1000). ampControl = EZSlider(w. 0). {| ez| s.value). 400 @ 24.nextLine. // create controls for all parameters w.sendMsg("/n_set". \db. ampControl.

}.remove(cmdPeriodFunc).Where: Help→GUI→EZSlider CmdPeriod. ) 647 .

v = SCStaticText(w. "MarkerFelt-Thin " ]. s = SCButton(w. n. "Monaco". SCButton and their subclasses (SCNumberBox. Rect(0. height+2)). 64.bounds.do({ arg name. 56.4). n. 360)). 0. 0. "Helvetica". s.object = pi. size) command-T to look for Font names.Point(4.f. 13). w. SCDragBoth) can set their fonts. spec. height+2)).font = Font(name. 13).Where: Help→GUI→Font ID: 202 Font Font(name. SCStaticText. s. 56. 0. Rect(0. 340.Point(4. v. ( var w. s.view. n = SCNumberBox(w.string = name. v. n. 648 .font = Font(name. 13). "Gadget". p.decorator = f = FlowLayout(w. SCDragView. 140.2)). height = 16.font = Font(name. height+2)).view. SCDragSink. w = SCWindow("Fonts". Rect(0. var v. [ "Helvetica-Bold".states = [[name]]. Rect(128. "Arial".

) ( var w. height+2)).asCompileString. 56. 140.view.{ f. s.nextLine.front. Rect(0. 56.Point(4.view. s. var v. n. spec. 0. n = SCNumberBox(w.4). height+2)).string = name. Rect(128. 0. 64. w. Font. }). n. }. Rect(0.front. font = Font(name. v = SCStaticText(w. w. }). height+2)).bounds.font.f.font = font. ) 649 .13). w = SCWindow("Fonts".font = font.font = font.states = [[name]]. Rect(0. 760)). s. height = 16.2)). if( (i = i + 1) % 3 == 0. s = SCButton(w.object = pi.Point(4.action = { font. }). w.availableFonts. s. p. v.decorator = f = FlowLayout(w. 800.i=0.Where: Help→GUI→Font f. v. 0.do({ arg name. n.postln.nextLine.

Where: Help→GUI→GUI ID: 203 GUI Classes Overview The following GUI classes have individual helpfiles. There are a number of undocumented GUI classes listed in Undocumented-Classes. Color Document Font SC2DSlider SC2DTabletSlider SCButton SCCompositeView SCEnvelopeView SCFuncUserView SCHLayoutView SCMultiSliderView SCNumberBox SCPopUpMenu SCRangeSlider SCTabletView SCTextField SCVLayoutView SCView SCWindow resize 650 .

Color Document Font SC2DSlider SC2DTabletSlider SCButton SCCompositeView SCEnvelopeView SCFuncUserView SCHLayoutView SCMultiSliderView SCNumberBox SCPopUpMenu SCRangeSlider SCTabletView SCTextField SCVLayoutView SCView SCWindow resize 651 . There are a number of undocumented GUI classes listed in Undocumented-Classes.Where: Help→GUI→GUIClasses ID: 204 GUI Classes Overview The following GUI classes have individual helpfiles.

and will only be visible once the window or the view is refreshed. p2) Draw a line (define a path) from p1 to p2.. You will need to call *stroke or *fill to actually draw them. B-Splines. cpoint1.Where: Help→GUI→Pen ID: 205 Pen draw on an SCWindow superclass: Object A class which allows you to draw on a [SCWindow]. The following methods must be called within an SCWindow-drawHook or a SCUserViewdrawFunc function. *lineTo (point) Draw a line (define a path) from the current position to point. See also: [SCWindow]. // *curveTo(point. point is an instance of [Point]. *line (p1. (Splines.. It has no instance methods. Nurbs?) Unfortunately not working for now. cpoint1 is a help-point determining the curves curvature. // *quadCurveTo(point. [SCUserView]. cpoint1. cpoint2) draws an interpolated curve from the current position to point. Each call to SCWindow-refresh SCUserView-refresh will ’overwrite’ all previous drawing by executing the currently defined function. Current position will be p2. and [String] Drawing Methods The following methods define paths. [Color]. point is an instance of [Point]. cpoint1) draws an interpolated curve from the current position to point. cpoint2 are help-points determining the curves curvature. p1 and p2 are instances of [Point]. 652 . *moveTo (point) Move the Pen to point.

outerRadius.new. 10..blue(rrand(0.0. 1).background_(Color.front.0. arcAngle) Draw an annular wedge around the [Point] center. w.addArc((100.refresh. rrand(0. 1). w. radius. Pen. \fill].perform([\stroke. arcAngle) Draw an arc around the [Point] center. w. 2pi.front. Pen. w. radius. from innerRadius to outerRadius 653 .white).drawHook = { // set the Color Pen. } }. 2pi. rrand(10.. 100).do{ Color. startAngle.perform([\stroke.set. Pen. at radius number of pixels. startAngle.. pi).set.addWedge((100. w.0. } }. and are in radians [0.5)).2pi].rand).rand.view.background_(Color.Where: Help→GUI→Pen Unfortunately not working for now. 2pi.do{ Color.rand). at radius number of pixels.translate(100.drawHook = { // set the Color Pen. arcAngle) Draw a wedge around the [Point] center. and are in radians [0.red(rrand(0.. startAngle and arcAngle refer to the starting angle and the extent of the arc. ( w = SCWindow. 0. 100). 0.choose). \fill].rand)@(100. ( w = SCWindow. w. Pen.2pi]. startAngle and arcAngle refer to the starting angle and the extent of the arc. *addArc(center. ) *addAnnularWedge (center. 10.view.translate(100.choose).new.rand.white). 100). startAngle.0. rrand(0.rand). rrand(10.5)). innerRadius.refresh.rand)@(100. 100). ) *addWedge(center.

green(rrand(0..background_(Color. rrand(51.drawHook = { // set the Color Color.background_(Color. Pen.white).addAnnularWedge( (100.translate(100. rrand(10. w.rand ). Pen. Pen.new. 100). ( w = SCWindow.moveTo(200@100). and are in radians [0.set. Pen. 654 . rrand(0. *stroke outline the previous defined path.rand).rand. } }.lineTo(250@200).2pi].. w.refresh.lineTo(300@200).5)). 100). 0.Where: Help→GUI→Pen in pixels.view.new.perform([\stroke.choose). w. 50). ( w = SCWindow. 1). Pen. Unfortunately not working for now. startAngle and arcAngle refer to the starting angle and the extent of the arc.view.front.0. 1000. \fill]. ) // *addRect(rect) adds a rectangle to the drawing. w. 2pi. 2pi..red. w.do{ Color.front.rand)@(100.set.drawHook = { // set the Color Pen.white).0.

w. ( w = SCWindow.refresh. Pen. Pen.Where: Help→GUI→Pen Pen. Pen.background_(Color.lineTo(200@100).drawHook = { // set the Color Color.set.lineTo(100@200). w.lineTo(300@200). ( w = SCWindow("strokeRect". Pen.lineTo(100@200). w.white).refresh. Pen. *strokeRect(rect) Strokes a rectangle into the window.lineTo(150@200).red. Rect(128. w.stroke }.new.fill }.view. Pen. Pen. ) These methods do require separate calls to *stroke or *fill.front. Pen. ) *fill fill the previous defined path. Pen.drawHook = { 655 . w. 64.lineTo(150@200).lineTo(200@250). rect is an instance of [Rect].lineTo(200@100). Pen. Pen.moveTo(200@100).lineTo(200@250). 360)). 360.lineTo(250@200). Pen.

// *drawAquaButton(rect. Pen.0. rect is an instance of [Rect]. v. Rect(128. r.alpha_(0. rect is an instance of [Rect].black. i. y=0) translate the coordinate system to have its origin moved by x. v = h = 300.black. Pen. r. v. }. *translate(x=0. }. ) *fillRect(rect) Draws a filled rectangle into the window. ( w = SCWindow("strokeOval". 100.front.drawHook = { var h.y 656 . 360)).strokeRect(r). w. 100. *strokeOval(rect) Strokes an oval into the window. i.0.8). on=false) Graphics State Methods The following commands transform the graphics state. 64. r = Rect(100. Color.strokeOval(r).e.set. w. These transformations are cumulative. ) *fillOval(rect) Draws a filled oval into the window. down=false. rect is an instance of [Rect]. they effect all subsequent drawing commands. r = Rect(100.set. not the original one.front. each command applies to the previous graphics state.alpha_(0. 80). 360. type=0. 160.8). w. v = h = 300.e.Where: Help→GUI→Pen var h. 160. 80). Color.

Pen.view.moveTo(0@0).do { Pen. w. Pen.blue.refresh. w.100).new.moveTo(0@0).white). ) // cumulative translations ( w = SCWindow.black.translate(10.lineTo(50@100). Pen. w.set.background_(Color.translate(200.view.stroke }.background_(Color.Where: Help→GUI→Pen ( w = SCWindow. w.drawHook = { // set the Color Color.lineTo(-50@100).stroke } }.lineTo(50@350). Pen.lineTo(0@150). Pen.clear).set. w.lineTo(-100@100).lineTo(0@0).drawHook = { // set the Color Color. Pen. Pen. Pen. // 0@0 is now 200@100 Pen.front.front. 0).lineTo(100@100).new. Pen. Pen. // draw 35 lines 35. // shift 10 to the right every time Pen. 657 .

e.green(0.front.100). Pen.. 2 is double size. 2). etc. y=0) Scales subsequent drawing.e.skew(0. 658 . w.white).scale(0. Pen.5.5.set. ) *scale (x=0. w.stroke }. x and y are skewing factors (i.background_(Color.translate(200.view. Pen.. Pen. 0. x and y are scaling factors (i. 1 is normal). Pen. w.front.background_(Color. Pen.8).lineTo(-50@100).100). ( w = SCWindow.drawHook = { // set the Color Color.refresh. Pen.lineTo(-100@100). // you have to set a starting point.2).lineTo(100@100).white).green.moveTo(0@0).new. ) *skew (x=0. ( w = SCWindow.view. y=0) Skews subsequent drawing.lineTo(0@150). Pen.5.Where: Help→GUI→Pen w. 0. Pen.refresh.lineTo(0@0).translate(200.drawHook = { // set the Color Color.set. 1 is normal.new. Pen. w.lineTo(50@100). Pen.). w. Pen.

659 . Pen.2pi].background_(Color..hsv(c. 1)..lineTo(100@100). Pen. Pen.lineTo(0@0).new. 200). w.lineTo(50@100).fold(0. // set the Color for all "real" drawing Color.lineTo(0@150).drawHook = { Pen.lineTo(-50@100).lineTo(100@100).front.set.fill }.view.. Pen. Pen. x=0. 10.refresh.moveTo(0@0). w. // you have to set a starting point. Pen..lineTo(-100@100).do({ Pen.5).lineTo(-50@100).translate(220. Pen.10). Pen. 1. Pen. w. y=0) Rotates subsequent drawing around the Point x@y by the amount angle in radians [0. ) *rotate (angle=0.moveTo(0@0).translate(0.lineTo(0@0). Pen. Pen. Pen.white).lineTo(50@100). 1.lineTo(0@150). c = 0. Pen. ( w = SCWindow. Pen.lineTo(-100@100).. Pen. 0.Where: Help→GUI→Pen // you have to set a starting point.

}. 0.leftBottom.drawHook = { Color. Pen. 660 . name.200. w.view.fromPoints(a = 0 @ 0.1.front. }). x. 0. d. matrix = [1. d = r. // the drawHook w.background_(Color.fill.Where: Help→GUI→Pen Pen. Pen. b. // determine the rectangle to be drawn r = Rect. Pen. y] a zoomX b shearingX c shearingY d zoomY x translateX y translateY ( var controlWindow. // create a controller-window controlWindow = SCWindow("matrix controls".width = 5. var sliders.white).rightTop. d. var r. 10. Rect(400. c. spex. controlWindow. ) *matrix_ (array) transforms coordinate system.red.350. w. w. 10]. b.matrix = matrix. a.refresh. 1.rotate(0. w = SCWindow.2pi).120)).front.new. c = c + 0. c = 180 @ 180). c. b = r.set. array = [a.

(0@6).decorator = sliders = FlowLayout(controlWindow. "B". Pen.drawAtPoint(b .50).0]. Pen. ) var val.0]. *width_(width=1) 661 . 300 @ 14.drawAtPoint(d . Font("Helvetica-Bold". val. 200.refresh. "D".value.asSpec. }. val).put(i.moveBy(50.nextLine. 12)).0]. "C". matrix. // reevaluate drawHook function }.view.line(b. 2.asSpec.1. 6.0].postln.drawInRect(r. Font("Helvetica-Bold". spex[i]. sliders.line(a. translateX. name = #[zoomX. d). Pen.asSpec. { | ez| val = ez.set.Where: Help→GUI→Pen Pen. translateY]. Pen. Font("Helvetica-Bold". controlWindow. 12)). shearingX. [0. 10)). [0. "A". [i.bounds). [0.(0@6).round(10e-4)].asSpec ]. spex = [ [0.asSpec. c).blue. Pen. name[i]. 12)).strokeOval(r).width = 0. zoomY.6.asSpec.drawAtPoint(c .refresh.view. w.6. 12)). matrix[i]). [0. [0. Font("Helvetica". Color. 2.0]. w. Font("Helvetica-Bold".do { | i| EZSlider(controlWindow.0].strokeRect(r). 2.drawAtPoint(a . "a matrix test". 200. }. 2. shearingY.stroke.

Pen.lineTo(-100@100).background_(Color. ) *use (function) Draw function. Pen. This allows you to make complex transformations of the graphics state without having to explicitly revert to get back to ’normal’. w. w. 0.white).drawHook = { // set the Color Color. Pen.lineTo(-50@100). // you have to set a starting point.set. Pen.background_(Color.new. Pen.width = 10.lineTo(50@100)..stroke }.front..translate(200.5).set.refresh. Pen. 0.view.5).front.width = 10. Pen.100). 20. 2pi).lineTo(0@0).Where: Help→GUI→Pen sets the width of the Pen for the whole stroke ( w = SCWindow. w.blue(0. and then revert to the previous graphics state.moveTo(0@0). w.5. ( // modified by an example of Stefan Wittwer w = SCWindow. Pen. Pen. 662 .white). Pen. w.lineTo(100@100).gray(0.view. Pen.addArc(0@0.drawHook = { //paint origin Color.lineTo(0@150). 0.fill.new. Pen. Pen.

}.red(0..do{ Pen.blue.. Pen.skew(0.100). 2pi).5.set.translate(200.blue. width.refresh ) *path(function) make a path.drawHook = { // set the Color Color. 0. and color modifications do not apply Pen. skewing. // now go on with all params as before // translation. (there’s no Meta_Pen-endPath which currently is used in this method) *beginPath Discard any previous path.addArc(0@0.stroke.7. Unfortunately not working for now.moveTo(0@0).translate(100.set.new.. consisting of the drawing made in function. Color.stroke. 1)). 300@120).set.white). Color.100).use { // draw something complex.line(10@120. Pen. Pen.fill. 663 .view. 0. Pen. 10. w. w. Pen.moveTo(0@0). rrand(0. }.width = 0. }..1). w.background_(Color. Pen. Pen.front. Pen. Pen.lineTo(100@0). Pen. 20.8. // incomplete arrow ( w = SCWindow.Where: Help→GUI→Pen Pen.

lineTo(0@150).moveTo(200@100). // now clip Pen. Pen. 664 . Pen.lineTo(-100@100).lineTo(290@110).yellow.400. Pen.white). Pen. // everything else we draw is now clipped Color. Pen. Pen.lineTo(0@0).lineTo(110@240).front. Pen.lineTo(50@100).fillRect(Rect(0.lineTo(-50@100). Pen.moveTo(110@110). w.red.drawHook = { // outline the clipping path Pen. ) *clip Use the previously defined path as a clipping path.refresh.set.400)). Color. Pen.lineTo(290@240).beginPath. w.clip. Pen. Pen.lineTo(250@200). Pen.0.lineTo(100@100).background_(Color. // forget what we just drew Pen.set. Pen.new. Pen.lineTo(110@110). ( w = SCWindow.Where: Help→GUI→Pen Pen.stroke }. w.moveTo(100@100).view.

set.scale(0.fillRect(r).Where: Help→GUI→Pen Pen.lineTo(150@200).lineTo(300@200).rotate(0. Pen.0.rotate(0. Pen.red. w.8).20).0.1pi). 0. repeat Pen.1pi). Color. rinse. Pen.fillRect(r).width = 3.translate(80.black. Color. Color. Pen.use { // use the same rect for everything. // lather. Color. 665 .80).set. ) Examples ( // simple rotating and scaling w = SCWindow("Pen Rotation and Scaling".8).drawHook = { var h.translate(8.set.5).10). v = h = 300. Pen. Pen.yellow(1. Rect(128.8.0.fill. // offset all subsequent co-ordinates Pen. // scale all subsequent co-ordinates Pen.set. Pen. v. 360)). Pen.lineTo(200@250).8. Pen.refresh.scale(0. // rotate all subsequent co-ordinates Pen.200. Pen.strokeRect(r). 360. w.lineTo(100@200). just scale and rotate var r = Rect(0. }. 0. 64. Pen.blue.

rand. Pen. 400. 10.8. w.lineTo(Point(10.stroke.. panel".front..front.fork(AppClock) ) ( var w.beginPath.onClose = { run = false.rand * 80 + 40.do { Pen.view. w.moveTo(Point(10. 10. } }. }.rand * 80 + 40.0. panel". Pen.Where: Help→GUI→Pen Pen.translate(20. 1. 64.rand * 80 + 40)). }. }.. { while { run } { w.view. 500)).background = Color. run = true. 666 . w. 800. 0. Pen. }. w = SCWindow("my name is.drawHook = { Pen.onClose = { run = false.. w. Rect(128.use { Pen.white. Rect(128.2. Pen.1pi). 64.rand * 80 + 40)). w.background = Color.front. Pen.scale(0.rotate(0. w. Pen. }. w.fillOval(r). run = true.refresh. w. ) // redraw at random interval // different every time ( var w.white.wait } }. 800.8). w = SCWindow("my name is.-20). 800)).width = 0.

rand. }.0. // now a slight chance of a new seed or background color if (0. seed.rand. }.coin) { seed = Date. etc.rand. }.5. Rect(40.4) + 0. Pen. 500. w. ( // By James McCartney var w.randSeed = Date.rand(0.seed.fork(AppClock) ) // Animation // Uses random seed to ’store’ data // By reseting the seed each time the same random values and shapes are generated for each ’frame’ // These can then be subjected to cumulative rotation. Pen.seed. Pen.do { Pen. // stop the thread on close w.width = 2.width = rrand(0. w.moveTo(Point(800. Pen. by simply incrementing the phase var.lineTo(Point(800.02.3).drawHook = { Pen. false). // store an initial seed value for the random generator seed = Date. run = true. if (0.006. phase = 0.coin) { w. 1.view. w = SCWindow("wedge".3).0.view. 80.rand(0.stroke. 40.wait } }. w. }. Pen.width = 2. h = 700.rand)). }. { while { run } { w.rand)).0.Where: Help→GUI→Pen w.front.background = Color.onClose = { run = false}.refresh.. 500. h.use { // reset this thread’s seed for a moment thisThread.background = Color. v). // either revert to the stored seed or set the new one 667 .beginPath.use { Pen. v = 700.drawHook = { Pen.seed.

front. thisThread.0.seed. 0.3 * sin(phase * 1.do { var a = 4.rand.beginPath.300).rand. and advance the phase each time { while { run } { w.blue(0. w. // scale the rotated y axis in a sine pattern Pen. Rect(128. 2pi.rand) + 0. if (0. 668 .view. }. panel". v/2).coin) { seed = Date. Pen. var r1 = 230 + (50 * a).refresh.drawHook = { Pen..use { if (0. positive the other Pen.02. a + 50. phase = 0. // rotate the whole image // negative random values rotate one direction.24).rand2 + 2pi.stroke}{Pen. // fork a thread to update 20 times a second.translate(h/2.fill}.seed.. 64.background = Color.0). // create a random number of annular wedges rrand(6. 0.rotate(phase * 1.wait.fork(AppClock) ) ( var w.scale(1.randSeed = seed. 200. 800)).0. run = true.05.white. w. Color.set.rand(0.randSeed = seed.5.alpha_(rrand(0. Pen. }. }.set. w.coin) {Pen.4). phase = phase + 0.} }.onClose = { run = false. a = rrand(60. // the random values below will be the same each time if the seed has not changed // only the phase value has advanced Pen.5 ).01pi.rand2).1. 800. w = SCWindow("my name is.0.rand2. 2pi. }. w.Where: Help→GUI→Pen thisThread.0).do { Color. }.0.rand). seed = Date.rand + (phase * 2.7)).1.addAnnularWedge(Point(0.0.rand2). var b = 24.

thisThread.asPoint + Point(400.4). var r2 = 230 + (50 * (a + 1.width = 0.beginPath. zoom = 0. Pen.2 + 1.refresh. phase = phase + (2pi/(20*24)) } }.01).beginPath. zoomf = exprand(1/1.fork(AppClock) ) ( var w.400)). }.wait. seed = Date.rand2)). w. zoom = 0. w = SCWindow("affines". }. a1). Rect(40. Pen.wrap(0.rand2).23) + phase. } 669 .moveTo(Polar(r1.linrand.rand2)). Pen.do { var a = 4.fold(0.stroke. 1. { while { run } { w.5. Pen. var b = 24.23) + phase. }. w. }. 0.asPoint + Point(400.asPoint + Point(400.7.moveTo(Polar(r1. h = 800.randSeed = Date.3)). var r1 = 230 + (50 * a). v)).7.400)).asPoint + Point(400.400)). var a2 = 2pi / 24 * (b + (3. a2).rand.2 + 1.blue(0. Pen.wrap(0. Pen. var r2 = 230 + (50 * (a + 1. Pen. run = true.drawHook = { thisThread.width = 0. phase = 0.400)).lineTo(Polar(r2. Pen. var a2 = 2pi / 24 * (b + (3. phase = 0.background = Color.coin) { seed = Date.seed. Pen. 40.seed.seed.view.fold(0. var a1 = 2pi / 24 * b + phase.01.0. zoomf = 1. 40.seed.randSeed = Date. w.front. if (0. w.0125. Pen. h.linrand. v = 600.1.lineTo(Polar(r2.onClose = { run = false }.stroke.rand2).rand. a1).Where: Help→GUI→Pen var a1 = 2pi / 24 * b + phase. a2).3)).

neg.rand2 + (h/2). Pen. }.rand2 + (v/2)).1) } ! var xlates = { 8. rots = rots ++ rots. Pen. Pen.scale(xscale.translate(-400.scale(zoom.use { var p1 = Point(20. 1200.rand2 } ! var ylates = { 8. yscales[i]] } ! 4. 400).linrand + 1. xlate.5).neg.randSeed = seed.width = 8. zoom). 2.moveTo(p1). thisThread. #rot. 20.rand2 + (v/2)). rot. ylate.stroke. Pen.beginPath.rand + phase } ! var xform. Pen.rotate(rot. Pen.0. ylate). var p2 = Point(20. Color. -400). yscale = xform. Pen. ylates[i]. Pen.do { var p. xscales = (xscales ++ (1/xscales)) * 1. xform = {| i| [xlates[i]. 2. zoom = zoom * zoomf. 2**0. v/2).1. Pen. xscales[i]. Pen. var xscales = { exprand(2** -0.translate(xlate.Where: Help→GUI→Pen { phase = phase + (2pi/80).neg. }. yscale. var rots = { 2pi. yscale). h/2.grey(1.05.wait.refresh. 2. 2**0.lineTo(p2). } }.1.choose.rand2 + (h/2).fork(AppClock) ) 670 . }.linrand + 1. Pen. xscale.width = 8. { while { run } { w. xscale. }.rand2 } ! 2. 2. xlate. yscales = (yscales ++ (1/yscales)) * 1. xlates = xlates ++ xlates. 20. Pen. ylate. 0.set.1) } ! var yscales = { exprand(2** -0.translate(400. Pen. ylates = ylates ++ xlates. rots[i].

translate() Pen.fill as needed.0] colormode() not necessary use hsv or rgb as needed.moveTo lineto() Pen.moveTo.strokeRect.0.lineTo curveto() not now endpath() Pen. stroke() color.g. Pen.skew push() Pen.b) fill() color.matrix = [0.v) or Color(r. color() Color.line – or use Pen.setFill nofill() use Pen. Pen. SC3 (modified from a mailinglist-post of James McCartney) ————————————————————————————————— —rect() Pen.0.stroke or Pen.fill (paths don’t need to be stored as data because you can compose them functionally).beginPath moveto() Pen. Pen.scale skew() Pen.setStroke nostroke() use Pen.fill beginclip() endclip() transform() – not needed since rotate lets you specify the center point. easy to add. strokewidth() Pen.fillOval line() Pen.stroke or Pen.hsv(h.lineTo arrow() star() beginpath() Pen.0.push // private method??? pop() Pen.stroke.width 671 .rotate scale() Pen.pop // private method??? reset() Pen.stroke.Where: Help→GUI→Pen ————————————————————————————————— —NodeBox vs.s.0.fillRect oval() Pen. drawpath() Pen.strokeOval. Pen. Pen.fill as needed. missing CMYK though.translate rotate() Pen.

drawLeftJustIn.drawCenteredIn.drawRightJustIn image() not yet imagesize() not yet size() – all of these are covered by other mechanisms in SC var() random() choice() grid() open() files() autotext() 672 . string.drawAtPoint textpath() textwidth() string.bounds textmetrics() lineheight() align() use string.Where: Help→GUI→Pen font() Font(name. string.bounds – currently commented out but should work once reenabled. textheight() string. size) text() string. size) fontsize() Font(name.

fixed to right.Where: Help→GUI→Resize ID: 206 resize resize behavior for SCView 1 4 7 2 5 8 3 6 9 1 . fixed to top 2 .fixed to right. vertically elastic 5 .fixed to left. vertically elastic 6 .horizontally elastic.fixed to left.horizontally elastic.fixed to right. vertically elastic 7 . fixed to bottom 9 . fixed to bottom 673 .horizontally elastic. fixed to bottom 8 . fixed to top 4 .fixed to left. fixed to top 3 .

80)) . Rect(20. window. 20.80. 674 . var slider.x_(0.Where: Help→GUI→SC2DSlider ID: 207 SC2DSlider superclass: SCSliderBase ( var window. Rect(100.front. window = SCWindow("SC2DSlider". slider = SC2DSlider(window. ) <>x <>y drag and drop returns and accepts Points. hold command key to initiate a drag. 140 .5).y_(1).140)).100.

buttonNumber. window. 140 .tilty.tilty. buttonNumber.y.deviceID.the view x . slider.view.tiltx.mouseDownAction = { arg view.clickCount]. [view.pressure.deviceID.y.x.pressure. ["down".x. }.setProperty(\clipInBounds. slider = SC2DTabletSlider(window. slider.1 value 675 .1 value action mouseDownAction mouseUpAction all actions are passed the following wacom tablet values: view .front.deviceID.tilty.clickCount]. buttonNumber.y_(1). ["up".mouseUpAction = { arg view.tiltx. var slider.deviceID.140)). window = SCWindow("SC2DSlider".tilty. Rect(20.x. 20.1 value <>y 0.clickCount.pressure.tiltx.0. Rect(100.5).x.x_(0.view.postln.tiltx. buttonNumber.tiltx.action = { arg view.clickCount].y..y.Where: Help→GUI→SC2DTabletSlider ID: 208 SC2DTabletSlider superclass: SC2DSlider a 2D slider with support for extended wacom data ( var window.clickCount.pressure.pressure.0) ) <>x 0.80.postln.postln. slider.tilty.y.tilty.clickCount.x.y.x.. buttonNumber. 80)) . }.deviceID.tiltx. buttonNumber. }.100.pressure.. slider.deviceID.

1.. Out.1... most relevant for the mouseDown.4. c=LFNoise1.kr(Env. ( SynthDef("help-SC2DTabletSlider".0.. ) * int1.0.0. p=Pulse.d.kr(0.ar(0.the wheel on the side of some mice rotation .0.1. This is useful in that you can have a small view in which to start your movement and then go all over as long as you don’t lift the pen.2). the values will exceed this as you drag from inside the view to outside.int2 = -5. but still valid for the dragged and mouseUp absoluteZ . freq * int2.1.[0. var p.1.kr(0.1 where available tiltY .c. triple click .{ argfreq=440.55).midiratio + f .Where: Help→GUI→SC2DTabletSlider y . 1 right.0.rq=0. only on the 4d mice Properties clipInBounds.0.d.will be used to look up if the tip or the eraser is used buttonNumber . f=LFNoise1. 2 middle wheel click clickCount .45. gate) ) }.1.1 value pressure .gate=0.double click.ar(p). hold command key to initiate a drag.1 tiltX .55). d=LFNoise1.0..send(s).2).midiratio .1 where available deviceID .ar(Mix. drag and drop returns and accepts Points. freq. ffreqInterval=0.0.in degrees.ar([ freq [c.c].adsr.0.0 left. RLPF.0.f..1. 676 .rq) * EnvGen.f].midiratio.freq * ffreqInterval.0.0.nil]).1.0..kr(0.1 by setting this to 0. gate.0.45.int1=5.0 or 1 by default the x/y values are clipped to 0.

postln ). v.1). freq = ControlSpec(100.map(x).y.synth. \ffreqInterval.pressure. \gate. v.\linear. rrand(30. 0.3000. }.midicps.map(y).y.front. int = ControlSpec(-48.x.freq.pressure. synth.Where: Help→GUI→SC2DTabletSlider ( var w. w = SCWindow.x. synth = Synth("help-SC2DTabletSlider").action = { arg view. \int2.200. ) 677 . synth.tilty.mouseUpAction = { arg view. v = SCTabletView(w.set( \gate.map(pressure). synth.y. pressure.postln ) }. int.set( \int1.new.int.80).background = Color.tiltx.x.postln ) }.Rect(10. v. pressure. int.pressure.48. v. \gate.white.mouseDownAction = { arg view. int.10.set( \freq .\exp).200)). v.

valueAction = -1. background color ] ( w = SCWindow. // clips to size of states b.action = { arg butt.black].new.Rect(20.white]. butt. // does action if it results in a change of value b.valueAction = 3. b = SCButton(w. w.Color.blue.clear] ].Color.Color.white.value = 2.Color.340. Color.30)). }.postln. ) Failure to set any states at all results in an invisible button.red.Color. ["the path to cessation of creating suffering".Where: Help→GUI→SCButton ID: 209 SCButton each state: [ name. ["cessation of creating suffering".states = [ ["suffering".valueAction = 3.20.black.Color. b. ["origins of suffering". // floats no problem b.value.front. b. // does not do action b.Color. text color.red]. 678 .3.

black.20.red] ].Where: Help→GUI→SCButton ( w = SCWindow. b.Color.red.front. // new state doesn’t take effect until . b = SCButton(w.30))..refresh..states = [ ["suffering". //or the view itself is refreshed b. w.black] ]. ) 679 .refresh.Color.new.Color.Color. //window is refreshed w.340. b.Rect(20.states = [ ["cessation of suffering".

100)).Rect(100.0.Where: Help→GUI→SCCompositeView ID: 210 SCCompositeView A view that contains other views.100.100.100. b = SC2DSlider(c. c.100)).100. w.front.Rect(100.rand).0.100)). a = SC2DSlider(c. b = SC2DSlider(c.rand).new. a = SC2DSlider(c.background = Gradient(Color.rand.front.Rect(0.300)).Rect(0. ) keydown bubbling 680 .100)).new. c = SCCompositeView(w.Rect(0.rand. c = SCCompositeView(w.300)).300. w.Rect(50. not relative to the origin of the composite view (as in other gui frameworks). c.100.background = Gradient(Color.0.300.Color.100. grouping by background color ( w = SCWindow.0. ) Coordinates are the same as that for the window. ( w = SCWindow.Color.

// adding views to b automatically use the decorator // no need to use parent.new.100. ( w = SCWindow.decorator = FlowLayout(b.100.100. //d is on window w.100. decorators a ’decorator’ object can be set to handle layout management.100)).Where: Help→GUI→SCCompositeView Note that the keyDown action is assigned to the composite view.0. not on composite view c d = SC2DSlider(w.0. c = SCCompositeView(w. all views added to the composite view will now be placed by the decorator.Rect(0. }.0. the event is passed to b.200. ( a = SCWindow.100)).postln. a = SC2DSlider(c.keyDownAction = { "keydown bubbled up to me".Rect(200. ) 681 .front.100)).place c = SC2DSlider(b. b = SC2DSlider(c.0.Rect(0. b = SCCompositeView(a.Rect(100. c.decorator.Rect(0.500)). the parent.500.bounds).Rect(0. ) click on the different views and hit keys on the keyboard. b.100.500.500)). // size matters d = SC2DSlider(b.100)).Rect(0.0.front.100)).100. // origin doesn’t a. w. If c and d do not have keyDown actions themselves.new.

value).y = 1. ) removing ( 682 .0.front. b = SCCompositeView(a.visible = false.100. p.100. d.new.25. d = SC2DSlider(b.Rect(0.Rect(0. [i.rand.0. c = Array.rand.{ arg i.160. e.300)).Rect(0.asString.fill(q.decorator = FlowLayout(b. p = c. q = 3.at(butt. e.visible = true.x = 1.at(0). b. p = c.action = { arg butt.Color.fill(q.{ arg i.0. }.100)).states = Array. // show first one a.bounds).visible = false.Where: Help→GUI→SCCompositeView hiding / swapping ( a = SCWindow.visible = true. b }).black. b.20)).300.white] }).Color. e = SCButton(a.0. c.0. // previous p.Rect(0. p.100)). c = SC2DSlider(b.

resize = 2.Rect(0.front.Rect(0.new.Rect(0. c = SCCompositeView(w.refresh.Color. c.resize = 5. c.100)).100)).Rect(0.300)).Rect(100.300)). resize contraints resize the window to see how the contents behave ( w = SCWindow. // up to a point b. ) (bug: composite view should get limited by it’s contents’ limitations) 683 .rand). a.300. w.100.setProperty(\maxWidth.200). c. b.rand).0.100.Rect(100.new.rand.0. b = SC2DSlider(c.resize = 1. c = SCCompositeView(w.0. w.100.30).Color.0.100.background = Gradient(Color.rand.100. // x elastic b.100.front.Where: Help→GUI→SCCompositeView w = SCWindow. ) a.background = Gradient(Color.100)).setProperty(\minWidth. a = SC2DSlider(c.remove.300.100)). c. // elastic a = SC2DSlider(c. // fixed b = SC2DSlider(c.

if the index is -1 set the size for all points thumbSize_(size) set the size of all points setThumbWidth(index.Where: Help→GUI→SCEnvelopeView ID: 211 SCEnvelopeView value_([times. size) set the size of a point for the specified index.1 value [times. if the index is -1 set the width for all points thumbWidth_( width) set the width of all points setThumbHeight(index. width) set the width of a point for the specified index..1 action function is passed the view index the current or last moved node drawRect_(boolean) set wether to show the points or not drawLines_(boolean) draw lines between the point setThumbSize(index. heigth) set the height of a point for the specified index. if the index is -1 set the height for all 684 .values] where times and values are all 0..values]) where times and values are all 0.

color) set the point color fillColor_(color) set the color for all points setString(index. string) give a point a string connect_(index.decorator = FlowLayout(a. arrayofpoints) connect a point to others and do not use the standart connection scheme use as envelope view ( //use shift-click to keep a node selected a = SCWindow("envelope". 80)) .drawRects_(true) .resize_(5) 685 .Where: Help→GUI→SCEnvelopeView points thumbHeight_(heigth) set the height of all points setEditable(index.selectionColor_(Color. 230.view. 0.red) . Rect(200 . a. 450.view. b = SCEnvelopeView(a.bounds). 100)).drawLines_(true) . Rect(0. boolean) makes a specified point unmovable editable_(boolean) makes all points unmovable selectionColor_(color) set the color of the point when selected setFillColor(index. 250.

wait. 20. 1.abs).drawRects_(true) .view.decorator = FlowLayout(a.false).thumbSize_(5) .0]]).0.8.rand. b = SCEnvelopeView(a.5.red) . b.0. 686 .0].fillColor_(Color. }). 100)) .setEditable(0. 0.0.drawLines_(true) .1.0)]) a.x_(1.thumbSize_(5) .index. 150)).. Rect(0.view.1. 450. 0.select(-1). 1.bounds). ) ( //use shift click to select/unselect the points a = SCWindow("test".action_({arg b.value_([(0. })..0). .0.Where: Help→GUI→SCEnvelopeView .1 .rand.selectionColor_(Color.1.1 . 0. 0.green) .front. b. a. a. [b.0.0. 350.value_([[0.front.0.do({ arg i.abs). (0.abs). b.rand. ) ( //make the first point unmoveable b. ) ( r = Routine({ var j = 0.setEditable(0. Rect(200 .value].select((b. 1.size -1). 0.[0.b. 0.postln}) . 450.false).y_(1.1. b.0.

0.0.1.0. 0. 0. Color.1.0) .connect(3. 450. ) c = b.red) .Where: Help→GUI→SCEnvelopeView AppClock. "is". 440. ["this". //b. 0.front.0]). a. 440)) . Rect(200 . ) the text objects can be connected: ( b.thumbWidth_(60.5. b. "fun"].7]]).[2.0]). }). b.1.9.2.play(r).green].3].1.view. ) 687 . [2. //show boxes with a string in it: ( a = SCWindow("text-boxes".view.drawLines_(true) .setString(i.value_([[0.drawLines_(true).yellow.at(i)).choose).decorator = FlowLayout(a.do({arg i. [0.0) .3.thumbHeight_(15.setFillColor(i. Color. b.4. 0.xvalues. 450)). a. 0.true).connect(0.0. 0.bounds).0.0. Rect(0.drawRects_(true) . 4.selectionColor_(Color. b = SCEnvelopeView(a. 450.white. b.setStatic(0. "so much".[Color.

100. b = SCFuncUserView(a. ) 688 . a.new(0.new.Rect.100)).0. b.drawFunc = { }.front.Where: Help→GUI→SCFuncUserView ID: 212 SCFuncUserView not working yet ( a = SCWindow.

value_(i / q) }).75)).1).Where: Help→GUI→SCHLayoutView ID: 213 SCHLayoutView ( q = 10.fill(q. h.fill(q.value = i / q.red(alpha:0.20. elastic arg i.new.Rect(0.{ var s. h = SCHLayoutView(w.Rect(0. w. s = SCSlider(h.front ) elastic ( q = 10. w = SCWindow.0. w = SCWindow.front ) Contents are elastic ( 689 .300. Array.300)).20.0.75)).new.{ arg i.background = Color. SCSlider(h. // Array. h = SCHLayoutView(w.Rect(0.300. w.300)). s.0. h.Rect(0. s }).0.resize = 5.

if(i < 2.300.resize = 5. // elastic s. // Array.{ s. h = SCHLayoutView(w.Rect(0. w.20.300)).new. h.fill(q. }.20. s. // some elastic s.background = Color.resize = 5.value = i / 5. h. s. s }).Rect(0.resize = 1.0.resize = 5. h. arg i.new.fill(q. h = SCHLayoutView(w. w = SCWindow.front ) 690 . s = SCSlider(h.Rect(0.front ) set minWidth on contents ( q = 5. w. // some not elastic }).{ s.{ var s.value = i / q.resize = 5.20).0. // elastic Array. s }). s = SCSlider(h.Where: Help→GUI→SCHLayoutView q = 10.0. elastic arg i.{ var s.Rect(0.2).75)).setProperty(\minWidth.red(alpha:0.75)).300. w = SCWindow.0.300)).

s. w.300)). h = SCHLayoutView(w. s.setProperty(\minWidth.resize = 5.resize = 5.setProperty(\minWidth. s. s.0.0. // elastic Array. h.80).40).0.{ var s. w = SCWindow. s. h. s }).new.20). s = SCSlider(h. arg i.{ var s.setProperty(\maxWidth.300.resize = 5.string_("abcdefg").value = i / 5. s.Where: Help→GUI→SCHLayoutView ( q = 5. w = SCWindow. SCStaticText(h.Rect(0.front ) Text flows ( q = 5.300)). h = SCHLayoutView(w. s = arg i. 691 . // elastic Array.10).new.20.fill(q. // not working s.75)).fill(q. s.setProperty(\maxWidth.10).120@20).Rect(0.setProperty(\maxHeight.Rect(0.resize = 5.300.

s }).20.front ) 692 . s.75)) }).0. w.0).10).300)). Array.setProperty(\spacing. w.white.300.background = Color. w = SCWindow.new.setProperty(\minHeight.Where: Help→GUI→SCHLayoutView s.front ) spacing ( q = 10.Rect(0.{ SCSlider(h. h = SCHLayoutView(w. h.0.Rect(0.fill(q.

v."relative"."relative"."relative". ) v.50)).at(sbs. // . l.value.value returns the integer }. "absolute". [sbs."relative".background_(Color. "absolute". "absolute". "absolute"."relative" ].new.items = l.postln. v. v = SCListView(w. "absolute". "absolute".Rect(10. "absolute"."relative"."relative". l = [ "absolute"."relative".value = 16.rand 693 . v.10.180."relative".Where: Help→GUI→SCListView ID: 214 SCListView ( w = SCWindow.value)]. "absolute".action = { arg sbs.front.white).

// backwards m. 150.mov and mpg. // random-pick a tiff from the Help folder m.rate_(0.rate_(1).front.action_({ File. 0.gotoEnd.playSelectionOnly_(true).loopMode_(1).mov"). and image files like jpg. // or point it to a movie (you may have that one too): m. Rect(0. // loopModes: m. m.start.choose). // select a range on the controller and play it m.start.2). b = SCButton(w. (currently.20. ( w = SCWindow("mov").rate_(-1).) This is basically a wrapper for a Cocoa Quicktime view. { | path| m = SCMovieView(w.360. //rate m. it gets stuck on picts. 260)).path_("/Library/Application\Support/iDVD/Tutorial/Movies/Our\First\Snowman. // only one direction 694 . Rect(0.pathMatch.states_([["pick a file"]]) .path_(path) }) }). ) m.openDialog("".stop.Where: Help→GUI→SCMovieView ID: 215 SCMovieView can play movies such as .path_("Help/*/*/*.start. // thank god m. tiff and others. 20)) . png. // playback m.muted_(true).tiff".

10. // back and forth m.editable_(true).start. // poll current frame pos 695 .frame_(frame).75). m. // single steps m.postln. // select with shift-drag. m. length m.setSelection_(20. copy paste between movieviews or quicktime player m.stop.resizeWithMagnification(0. true).Where: Help→GUI→SCMovieView m.stepBack. // not there yet.gotoBeginning. m.stepForward. m. 15). //goto time (in seconds) m.loopMode_(0).currentTime_(1). but would be nice to have: // startFrame.stepForward.do { m. // jump to frame m.showControllerAndAdjustSize(true.frame. }. // resize compared to image size: m.

350.01). // spacing on the value axis b. b. a. 696 .Where: Help→GUI→SCMultiSliderView ID: 216 SCMultiSliderView isFilled = true looks like a candlestick graph ( //use as table var size.add(0. 150)). a.decorator = FlowLayout(a. 0. 390)). ) flip by 90 degree ( b. 100. c = Array.bounds_( Rect(10. 450. 450.new.bounds_(Rect(200 .reverse. c = c. Rect(200 .indexThumbSize_(2. 150. 450. size = 350 / 6. 430)). 0. a. b = SCMultiSliderView(a. a = SCWindow("test".view. b.view. 100)). // width in pixels of each stick b.gap_(4). size. Rect(0.bounds). c = c.value_(c). b.isFilled_(true).do({arg i.front.indexIsHorizontal_(false).0). }).

// value axis size of each blip in pixels b.background_(Color. 450. Rect(200 .white). b. }). 697 . // index axis size of each blip in pixels b.postln}. b = SCMultiSliderView(a.gap = 1. b.index ++" value: " ++ xb. a. b.bounds. b. a = SCWindow("test". b.strokeColor_(Color.black).isFilled = false. c = c.thumbSize_(12.strokeColor_(Color. b. 10 + (size * 17))). 10 + (size * 17). b. size * 17.indexThumbSize_( b.view.0). 0.add(i/size).0). Rect(0.blue). b.action = {arg xb. b.blue).decorator = FlowLayout(a.front. a.bounds).Where: Help→GUI→SCMultiSliderView b.size ). size = 12.new.width / c.xOffset_(5). size * 17)).fillColor_(Color. c = Array. b. size. ) isFilled = false individual squares for each point ( //use as multislider var size.white). b.view.gap = 0.valueThumbSize_(15.value_(c).do({arg i.fillColor_(Color.currentvalue). ("index: " ++ xb.

0.selectionSize.choose.do({ arg i. used like a cursor b. ) Note: this forces the entire view to redraw at each step and will spend a lot of CPU. }). 698 .1.0.{j = j + 1}. 20. ( //use it as sequencer b. 20.1.Where: Help→GUI→SCMultiSliderView a.index_(b.wait.index_(j). AppClock.do({ arg i.wait.size.rand). if (j < 11 .index. r = Routine({ var j = 0. 0. ) read only mode ( b. b.index = 4. // show an area as selected.setProperty(\showIndex.{j = 0}). ) b.selectionSize = 1. // move the selection index b. b.1.front. true). }).play(r).readOnly = true.2]. [0.showIndex = true. }). // 1 item wide b.wait. b.

0. b. 0.thumbSize_(1). a = SCWindow("test".do({arg i. b. 50)). 699 .decorator. a.indexThumbSize_(1). e = SCMultiSliderView(a. size * 17.add(i/size). b = SCMultiSliderView(a.getProperty(\referenceValues.drawRects_(true).nextLine. maxval. b. a. Rect(0. 0. b. file. 450.drawLines_(true). b. c. var size. c = Array. ) c = Array. size * 17.drag. 50)). size * 17. Rect(200 .front.xOffset_(18).view. b.view. }).bounds). b.valueThumbSize_(1). ( //press shift to extend the selection //use as waveView: scrubbing over the view returns index //if showIndex(false) the view is not refreshed (faster).Where: Help→GUI→SCMultiSliderView drawLines ( //use as multislider II with lines var size.value_(c).new.newClear(12). b. //e = SCDragBoth(a . size = 12. Rect(0. c = c. a.decorator = FlowLayout(a. size. Rect(0. 50)).blue). 450. //otherwise you can make a selection with shift .view.newClear(12)). minval.size. Array. b.strokeColor_(Color. 150)).

}). if(fi > maxval.numFrames.decorator. f = f.new. {minval = fi}). file = SoundFile.setProperty(\xOffset. 140.value * 4) + 1 )}.openRead("sounds/a11wlk01. a. c. Rect(0. minval = 0. maxval = 0. 50)).add((1 + minval ) * 0.reference_(d).Where: Help→GUI→SCMultiSliderView size = 640.nextLine. 12)).decorator = FlowLayout(a.view.5 ). maxval = 0.view.postln. d = Array. a = SCWindow("test". (ex. Rect(200 . if(i % 256 == 0. b. }).5 ).action = {arg ex.new. if(fi < minval.do({arg fi. b = SCMultiSliderView(a.{ d = d. d = Array. //file. e. 650. file. minval = 0. file. Rect(0. size. a. i. file. 0.new.new. //f.readData(c).close. e = SCSlider( a.postln. //this is used to draw the upper part of the table 700 .wav").newClear(65493). 0. c = FloatArray. b.bounds). f = Array. file. {maxval = fi}). b.inspect.readOnly_(true). 150)). size.view.add((1 + maxval ) * 0.

//b. Rect(200 . c = Array. size.0)).black.view. " ++ xb. Rect(0.index). ("index: " ++ xb. setting selectionSize will set that selection area.add(i/size). c = c.1.decorator = FlowLayout(a. b. 701 .value_(c). 12)).index ++" value: " ++ xb. this dispay may also be used to look like an index as in the above sequencer example. b.postln}. ( var size. ex. b. b.thumbSize_(1). a. ("index: b. size * 17)).colors_(Color. b. b.selectionSize_(10). a = SCWindow("test". 450.currentvalue). b.do({ arg i.action = {arg ex. size = 12.front. Color.showIndex_(true).setProperty(\startIndex.postln}. shift click and drag will select an area.drawRects_(false).blue(1. 10 + (size * 17). b. e = SCSlider( a. size * 17. b = SCMultiSliderView(a. b.action = {arg xb.value *f.new. e.gap_(0).bounds).action = { arg xb.Where: Help→GUI→SCMultiSliderView b.size )}.value_(f). 10 + (size * 17))).0. 0.isFilled_(true). b. size.drawLines_(true). }). ) the "index" is also the "selection" setting showIndex = true will allow selections. a. b. b. Rect(0.view. 0.enabled_(false).index_(10).

blue). b.strokeColor_(Color. b.front.valueThumbSize = 100 702 . the y-dimension b.thumbSize_(12.index_(4).xOffset_(5). b.showIndex = true.blue). a.drawLines(false).0). b.indexThumbSize = 40 // not the selection size // value pixels. b.Where: Help→GUI→SCMultiSliderView b. ) // this means the x-dimension size in pixels b.fillColor_(Color. b.

60)). 20)).Color.value = rrand(1. 400.15). b. Rect(100. w.decorator = FlowLayout(w.front ) b. b. b.bounds).action = {arg numb.\center).value.postln.Color. b.Where: Help→GUI→SCNumberBox ID: 217 SCNumberBox superclass: SCStaticTextBase ( w = SCWindow("SCNumberBox Example". 500.setProperty(\stringColor. }.15). b = SCNumberBox(w.grey). 100.white). 10. //w.view.value = rrand(1. Rect(150. 703 .setProperty(\align. b.setProperty(\boxColor. numb.view.

sbs.Where: Help→GUI→SCPopUpMenu ID: 218 SCPopUpMenu The 8-fold noble path ( var sbs.20)). sbs. // starting with a "3 relative".background_(Color."right concentration". [sbs.value)]. w = SCWindow.postln. // fore ello aft 704 .Rect(10.white). l = [ "right view".front.value returns the integer }.divider line ( var sbs.front. "-replaced by a divider". w = SCWindow. "4 fore <= aft".items = l. "right action".10."right speech". sbs.new. ) The underlying OS X graphics system gives special meanings to some characters . sbs = SCPopUpMenu(w.at(sbs. // fore aft ( <= disappears ) "5 fore <hello aft"."right mindfulness". l.new."right diligence". // ."right livelihood" ].value.action = { arg sbs."right thinking". l = [ "1 absolute".180.

// item still greyed out "12 something [else]".value.20)). // ok "13 something {else}". sbs.) "9 fore -<hello aft". // fore hello aft "8 fore —-hello aft". ) also these: < = ( 705 .items = l.Where: Help→GUI→SCPopUpMenu "6 something -> else". sbs.10. // ok "14 something | else" // ok ]. // item greyed out "11 something \(else)".value)]. l. sbs.action = { arg sbs. [sbs.180. // ok "7 fore —hello aft".Rect(10.white).at(sbs.value returns the integer }. // . // fore ello aft "10 something (else)". sbs = SCPopUpMenu(w.postln.background_(Color. // fore -hello aft (one .

Where: Help→GUI→SCRangeSlider ID: 219 SCRangeSlider modifier keys: command begin drag control move whole range shift move lo point alt move hi point normal set value 706 .

2.red. Rect(200.new.gridOn = true. 800. 60)). a. a. f = SoundFile. a.numFrames).timeCursorColor = Color. a. f. a = SCSoundFileView.gridResolution = 0. f.openRead("sounds/a11wlk01. 400)).front.new("soundfile test".wav").elasticMode = true.read(0.timeCursorOn = true.drawsWaveForm = true.inspect. a. a.new(w. a. w. f. a.20.timeCursorPosition = 2050.Where: Help→GUI→SCSoundFileView ID: 220 SCSoundFileView ( w = SCWindow.soundfile = f. ) 707 . 200. a. Rect(20. 700.

bounds = Rect(5. ) // adjust bounds a. a = Array.scramble) .extent. 20)). font_(font) set the font. 16)) .rand. 10.extent.new. w.bounds.front.font_(Font([ "Helvetica-Bold".fill(20. {SCStaticText(w.front. "Monaco".string_("Rolof’s Rolex". 100.Where: Help→GUI→SCStaticText ID: 221 SCStaticText A non-editable textfield string_(string) set the text.rand.rand) .bounds. Rect(10. 100. " Arial".stringColor_(Color. 5. a.x.y.string = "Rolof’s Rolex". Rect(w.new. Examples ( w = SCWindow. stringColor_(color) set the color of the string. 20) ///// dynamic ( w = SCWindow. a = SCStaticText(w. "Helvetica". 708 . 100. "Gadget".

bounds.defer.extent. }}.Where: Help→GUI→SCStaticText "MarkerFelt-Thin " ]. }.stop 709 . ) r = {inf.001).bounds.1.wait.fork r.extent.bounds = Rect(5+w.do{| i| thisThread.01)).do{| item| {item. 100.rand * sin(i*0.abs.y.randSeed_(1284). 16)) }). 20)}.x.choose. 0.rand * (cos(i*0. a. w.

rather than subpixel floats. It can also be used with a nor- action .0.0.double click.0 left. but still valid for the dragged and mouseUp absoluteZ . mal mouse but with less resolution.. it is possible to drag from inside to outside the view. 0 for mouse up.the view x . Properties clipToBounds .in degrees.subpixel location in view pressure . it set to 0. and the x y values will exceed the bounds accordingly. 710 . Wacom stylus devices have higher resolution than the screen.. triple click .1 deviceID ..subpixel location in view y .dragging the mouse inside the view mouseDownAction mouseUpAction Each of the three actions are passed the following wacom tablet values: view . only on the 4d mice If using a mouse (even a wacom) rather than a pen.by default the x y values are clipped to the bounds of the view. 2 middle wheel click clickCount . 1 right. the x and y will be integer pixel values.the wheel on the side of some mice rotation .1 tiltY .0. Pressure will be 1 for mouse down.Where: Help→GUI→SCTabletView ID: 222 SCTabletView superclass: SCView An otherwise featureless view that receives extended wacom tablet data.will be used to look up if the tip or the eraser is used buttonNumber ..1 tiltX .. most relevant for the mouseDown.

Where: Help→GUI→SCTabletView ( w = SCWindow.clickCount.absoluteZ.tilty.y.deviceID.absoluteZ.action = f. w.x. ["up".x. ["down". t.absoluteZ.300)).tilty.Rect(40.tilty.tiltx.rotation].pressure.clickCount.background = Color(x / 300.absoluteZ.pressure.tilty.y.y. t.absoluteZ.300.tiltx.40.tilty.new. t.postln. buttonNumber.y.front.tiltx.rotation. ["dragging".deviceID.deviceID.mouseDownAction = { arg view.tiltx. t. buttonNumber.pressure.y.absoluteZ.white.pressure.background = Color(x / 300. }.deviceID.x. ) Assign the same function to each action ( w = SCWindow.tiltx. buttonNumber. t.postln.tiltx.clickCount.y.clickCount. }.postln. t.tiltx.40.clickCount.x.Rect(40. t. 711 .background = Color.tilty.tiltx.deviceID.tilty.pressure).postln.deviceID.clickCount. x.y / 300.tilty. buttonNumber.x.pressure.pressure).y / 300. buttonNumber.300.300)).y.tiltx.tiltx.deviceID. t = SCTabletView(w.action = { arg view.clickCount.deviceID.pressure. buttonNumber.white. [x. t.clickCount]. }.rotation]. buttonNumber.mouseUpAction = { arg view.y.rotation.front. buttonNumber.x.rotation].pressure. }.mouseDownAction = f.pressure. w.new. t.background = Color. f = { arg view. t = SCTabletView(w.rotation.

48.1].0. [[-48.0.int2 = -5. freq * int2.freq.midiratio + f .nil.2).1]].[ nil.\linear.\linear.1]].55).45. * int1.mouseUpAction = f. ’loose’ ]. KrNumberEditor(0.0.kr(gate.rq) * EnvGen.topGui(f).0. f=LFNoise1.kr(0.rq=0.Where: Help→GUI→SCTabletView t.\linear. int = [-48. 712 .0.2). p = Patch.48. c=LFNoise1.0.int. var v.48.int1=5.1.nil. ffreqInterval=0.3000.1.48.midiratio.\linear.ar([ freq [c.midiratio . [[-48. d=LFNoise1. p.c]. Sheet({ argf.kr(0.kr(Env.4. Latch.freq * ffreqInterval.nil.nil. gate. freq = ControlSpec(100.ar(p).1]] ]).0.45. p=Pulse. [[-48.{ arg freq=440.f.kr(0.\loose].\gate) // override the default control ]).\exp). ) An example using crucial library ( Instr([\minimoog.55).adsr.gate)) }. RLPF. var p. freq.asSpec.d.d.f].#[ nil.ar(Mix.new([ ’minimoog’.c.1.gate=0.

pressure. ) move the box ( buggy ) ( w = SCWindow. }.changed.30)). v.map( x / 200 ) ).value_( rrand(30. t.left = b.y.b.tilty.mouseDownAction = { arg view.0. //b.x. v. p. p.30.value_( pressure ). b.pressure.x.args.action = { arg view.80).front.tiltx.200)).top = y .changed.Where: Help→GUI→SCTabletView v = SCTabletView(f. var b.200.changed. }.top.at(0). b = t.at(2).changed.Rect(0.mouseUpAction = { arg view. }).args.midicps ). p.new.bounds.at(5).value_( int.changed.y.x.pressure. }.changed.x.value_( int.background = Color.map( pressure ) ).map( y / 200 ) ). ) 713 . t.Rect(40. v.at(1). t.value_( 0.y.at(5). p.action = { arg view.args.0 ).background = Color.40.white. v. p.y. t = SCTabletView(w. w.bounds = b.left + x.white.value_( int.at(3).args. p.args. }.args.

b.setProperty(\stringColor. field. Does not handle composed character sequences ( é ø etc.\center). b = SCTextField(l.grey).Rect(0. b. ) option-e appears to freeze it ? 714 . } }).Where: Help→GUI→SCTextField ID: 223 SCTextField superclass: SCNumberBox Sheet({ argl. b.postln.white).Color.150.30)). // does not do the action b.setProperty(\boxColor. b.string = "hi there".value = "yo".0.Color.setProperty(\align.action = {arg field.value. b.

300.new. string_ set the text string get the text setString(string. txtv = SCTextView(win.Rect(0. rangesize) set text into a range selectedString get the selected text only selectionStart get the current position in the text selectionSize get the current size of selection in the text stringColor_ set the color of the whole text setStringColor(color.view. size) autoHideScrollers_ hasVerticalScroller_ hasHorizontalScroller_ textBounds_ font_ usesTabToFocusNextView_ enterInterpretsSelection_ //examples ( var win. win = SCWindow.Where: Help→GUI→SCTextView ID: 224 SCTextView superclass: SCView see also: Document a text editor *new(window. size) set the color of a selection of text setStringColor(color. bounds).view.front.decorator_(FlowLayout(win.bounds)). win. start. start.0. rangestart. txtv.200)) 715 .

Where: Help→GUI→SCTextView .hasVerticalScroller_(true) .focus(true).autohidesScrollers_(true) . ) 716 .

new("select this window and type something"). 70).view. This function will be passed four arguments: the View.unicode. ( var func. }. and the unicode value.bounds).focus.char. func = {| me| 717 .g. etc. ( // select the window. c.postln. and [String] keyDownFunc_ Set the function which should be evaluated if the view is in focus and a key is pressed.drawFunc = { char. w. the key pressed as a Char. See also: [SCWindow].front.). c = SCUserView(w.keyDownFunc = { arg view.5)) }.modifiers. See [SCView] for more details.refresh. Font(" Gadget". [Pen].w.drawAtPoint(180@150.Where: Help→GUI→SCUserView ID: 225 SCUserView superclass: SCView user-definable view SCUserView is a user-definable View intended mainly for use with Pen and drawHooks. alt. This happens every time the whole window is refreshed (manually by calling SCWindow-refresh or e. [char. unicode]. c. modifiers. type something and watch the post window w = SCWindow. 0. [Color]. c. w.blue(0. by selecting the view or resizing the window). ) drawFunc_ Set the function which should be evaluated if the view is refreshed.asString. modifier keys (shift. Color.3.

top)).bounds.exprand(2))@(100.width@me.bounds.width@me.top)) + (0@me. Pen.top)).lineTo(((me.drawFunc = func.left)@(me. 100.left)@(me.left)@(me.top)) + (me. // draw background Color.height)). }.set. 100).height)).bounds.left)@(me. 10.Where: Help→GUI→SCUserView Pen.fill.bounds.moveTo((me.width@0)). Pen.0.bounds.5)).height)).left)@(me.bounds.refresh.clip.left)@(me.use{ // clipping into the boundingbox Pen. Pen. rrand(10. 3.addArc((400. 100).lineTo(((me.translate(100. Pen. 718 .bounds.bounds.top)) + (me.set.0.bounds. 100.left)@(me. 100)).left)@(me.bounds.view. w.lineTo(((me.choose).height)). Pen.white).bounds.do{| i| v = SCUserView(w.bounds. Rect(20+(i*120).bounds.bounds.gray(0.top)).top)) + (me.bounds.width@0)). Pen. w.red(rrand(0. Pen.bounds.new("DrawFunc Examples"). pi).lineTo((me. \fill]. Pen.front.lineTo(((me.bounds.rand.moveTo((me. v. Pen.top)) + (0@me. rrand(0. Pen.bounds.rand).5). Pen.lineTo(((me.bounds. Pen.bounds. 2pi. 1). Pen.top)).left)@(me. Pen.left)@(me.bounds. w = SCWindow. 0.lineTo(((me.bounds.bounds.do{ Color.bounds.bounds.bounds.lineTo((me.background_(Color.bounds.perform([\stroke. } } }.top)) + (me.bounds.

top)).left)@(me.height)).lineTo((me.moveTo((me.gray(sat).lineTo(((me.lineTo(((me. and keyboard modifiers. trackFunc. x coordinate.bounds. This function will be passed four arguments: theView. y coordinate. ( var drawFunc. Pen.bounds.set.lineTo(((me.left)@(me.bounds.bounds. Pen. sat = 0.height)).left)@(me.bounds. mouseTrackFunc_ Set the function which should be evaluated if the mouse is tracked.moveTo((me. y coordinate. x coordinate.left)@(me.lineTo(((me. endTrackFunc. Pen. Pen. This function will be passed four arguments: theView.left)@(me.bounds. This function will be passed four arguments: theView. y coordinate. beginTrackFunc.bounds.bounds.left)@(me.bounds. absX. and keyboard modifiers.top)) 719 .clip.Where: Help→GUI→SCUserView ) mouseBeginTrackFunc_ Set the function which should be evaluated if the mouse is at the beginning of tracking (mouse-down). Pen.width@0)).left)@(me. and keyboard modifiers.bounds. Pen.bounds.use{ // clipping into the boundingbox Pen.bounds.width@me. mouseEndTrackFunc_ Set the function which should be evaluated if the mouse is at the end of tracking (mouseup).bounds. // draw background Color.top)). drawFunc = {| me| Pen.top)) + (0@me.bounds.top)).bounds.bounds.top)) + (me.top)) + (me. x coordinate. Pen.bounds.bounds.

rand. Pen.background_(Color. // not affecting anything. mod| absX = x.do{| i| v = SCUserView(w.refresh. \fill].refresh. 0.bounds. rrand(0. 100)).bounds.perform([\stroke. x.translate(100.front.lineTo(((me.mouseTrackFunc = trackFunc.white).height)).choose). y.top)) + (me. y.red(rrand(0. Rect(20+(i*120). Pen.view.background_(Color.bounds. w = SCWindow.bounds.bounds. Pen. beginTrackFunc = {| me. 100.0.do{ Color. me. pi). 100).width@0)). (absX-x)) x=%\n". 1).Where: Help→GUI→SCUserView + (me. rrand(10.drawFunc = drawFunc. 10. w. Pen. x.bounds.exprand(2))@(100.left)@(me. Pen..bounds.absX).new.left)@(me. endTrackFunc = {| me. mod| postf("end path: }.left)@(me. 100).top)). //v. v. x.width@me.5)).0. v. v.top)) + (0@me.. y.fill.white).bounds. 3. mod| sat = ((absX-x)/100). }.bounds.addArc((400.mouseBeginTrackFunc = beginTrackFunc. Pen. 2pi. w.lineTo(((me. } } }. 100. trackFunc = {| me.height)). Pen.lineTo((me.bounds.rand). v.mouseEndTrackFunc = endTrackFunc. }. postf("begin path: }.set. ) 720 . (absX-x)=%\n".

stroke.do{ | p. v = SCUserView(w. tmppoints = []. 340.moveTo(p). all.add(tmppoints. tmppoints.y| tmppoints = tmppoints.do{| p. tmppoints = []. }{ Pen. Pen. 0. txt. 340.mouseEndTrackFunc_({| v.x. i| if(i == 0){ Pen.lineTo(p). } }. w. }. Pen.do{| points| points. }.drawHook_{ Pen.lineTo(p). 64. w = SCWindow("draw on me". } }.x. tmppoints.refresh.add(x@y). i| if(i == 0){ Pen. 360)).y| all = all.moveTo(p). 721 . Rect(128.use { Pen.Where: Help→GUI→SCUserView // draw on the view ( var w.copy). w. }{ Pen.mouseTrackFunc_({| v.beginPath.width = 1.Rect(0. all. }. }) . 360)) .

refresh.front. }). w.Where: Help→GUI→SCUserView w. ) 722 .

vertically elastic 5 .horizontally elastic. which has its own documentation. fixed to bottom 9 . vertically elastic 7 . Currently this system is OSX only.fixed to right.fixed to right.fixed to left. SCUM. fixed to top 4 . This is illustrated graphically below: 1 2 3 4 5 6 7 8 9 1 .fixed to right.fixed to left.horizontally elastic.Where: Help→GUI→SCView ID: 226 SCView superclass: Object SCView is the abstract superclass for all SC GUI widgets. 723 . resize_(int) This setting controls how the widget will behave when it’s window or enclosing view is resized. fixed to top 3 . keyDownAction_(aFunction) Register a Function to be evaluated when a keystroke is received and this view is in focus.horizontally elastic.fixed to left. fixed to top 2 . On Linux there is another GUI implementation. vertically elastic 6 . fixed to bottom resize Return an Integer corresponding to the current resize behaviour (see above). fixed to bottom 8 . Several key methods and variables are defined in SCView and inherited in its subclasses.

possibly unprintable. type something and watch the post window w = SCWindow. the first one blank ( ). There are default keyDownActions for some views.modifiers.Where: Help→GUI→SCView ( // select the slider. the event will bubble up to the parent view which may then respond. You can examine individual flag settings using the C bitwise AND operator.Rect(0. It will continue to bubble up unless something responds or it hits the topView of the window. which will be overridden when you set a keydown action.char.modifiers.keycode. char .30)). [char.unicode. or you have no function registered. When called. You may register a function in the window’s topView to respond to all unhandled events for the window.postln.0. 65536 NSAlphaShiftKeyMask Set if Caps Lock key is pressed.An integer bit field indicating the modifier keys in effect. ) If you return nil from your function.100.new. }.unicode. c. 524288 NSAlternateKeyMask 724 .The receiving instance of SCView. 262144 NSControlKeyMask Set if Control key is pressed. w.keycode]. This will also vary depending on the nationality the keyboard is set to.The character pressed. the second one is the unmodified character (e). 131072 NSShiftKeyMask Set if Shift key is pressed. c = SCSlider(w. the function will be passed the following arguments: view . Character sequences (for example é) get passed as two characters.front. modifiers .keyDownAction = { arg view.

keycode . and so on) and the navigation keys in the center of most keyboards (Help.Where: Help→GUI→SCView Set if Option or Alternate key is pressed. Home. End. identical to the char. 1048576 NSCommandKeyMask Set if Command key is pressed. Page Up. and the arrow keys).B. For various reasons these don’t make it through cocoa: most command modifiers cntl-tab cntl-escape tab and shift tab are currently trapped by SC itself for cycling the focus through the views. but is useful for building musical interfaces using the computer keyboard. 2097152 NSNumericPadKeyMask Set if any key in the numeric keypad is pressed. 8388608 NSFunctionKeyMask Set if any function key is pressed.The unicode integer. Page Down.: Function key modifier may change the keycode. N. In order to play little melodies. 4194304 NSHelpKeyMask Set if the Help key is pressed. arrow keys have an extra modifier value of 10485760 so for a shift arrow key do a bitwise ’or’ with the shift mask: 10485760 | 131072 = 10616832 // this is the mask for shift arrow key unicode . this code will identify which key you consider to be special. This will vary from machine to machine.The hardware dependent keycode indicating the physical key. The numeric keypad is generally on the right side of the keyboard. F2. (we could change this) keyDownAction 725 . The function keys include the F keys at the top of most keyboards (F1. Forward Delete.

30))..Rect(0.red]].black]].new.Rect(0..Rect(0. ) // won’t display change. This forces a redraw.red.new.100.Color. See keyDownAction_ for details.100. ( w = SCWindow.close. otherwise return nil.Color.black.Where: Help→GUI→SCView Return the current keyDownAction function for this view if there is one. d. ( w = SCWindow.red]]. c = SCSlider(w.front.focus. c = SCButton(w.Color. w.Color.0. d = SCButton(w. w.front. ) c.black.Color. 726 .30.0.30)).30. d = SCSlider(w.100.30)).focus.states = [["a". refresh Under certain circumstances a view will not automatically update its appearance. *globalKeyDownAction_(func) A function that is evaluated for every keyDown event on every SCView.states = [["b".states = [["a". focus Brings this view into focus. c. c.Rect(0. d.Color.100. w.30)).

doesn’t redraw whole thing) c.return the object you wish your view to export by dragging aView.Where: Help→GUI→SCView d. for lists it is the currently selected numeric index etc. //needs separate refresh d.close. After receiving the drag. w.refresh.Color.currentDrag is set to nil. simple text labels do not accept drags etc.currentDrag Each view subclass has a defaultCanReceiveDrag method that determines if the current object being dragged is possible for this view to accept.states = [["a".black]].red.refresh. someList[ theView. beginDragAction(theView) .currentDragString and the results of attempting to compile that as sc code is in SCView. the SCView. drag and drop Each view subclass has a default object that it exports when dragged from.currentDragString as a compile string.Color.Color. // in some cases might be better to refresh the whole window // which does refresh on all damaged areas (it keeps track. By setting the canReceiveDragHandler and receiveDragHandler you can make any view 727 .refresh. By setting the beginDragAction handler you can return a different object based on the context and your application.black.currentDrag. and a defaultReceiveDrag method for actually receiving the drag.red]].beginDragAction = { arg theView. Sliders accept numbers. For sliders its the value of the slider. w. Text dragged from other applications is in SCView.Color.value ] } The current dragged thing can be found in the classvar SCView. //until c.states = [["b". Objects dragged from within SuperCollider are also in SCView.

receiveDrag = { SCView.accept the drag.states = [["Drop stuff on me"]]. b.items[ listView.receiveDragHandler = { b.new.20)).front. c = nil.currentDrag. }.200.canReceiveDrag = { SCView. listView. Here a list view is made to export a string.postln }.Rect(0.currentDrag]]. leave me alone aView.currentDrag.beginDragAction = { arg listView. (Note: currently not possible for SCStaticText) canReceiveDrag(theView) .currentDrag. ( f = SCWindow.200. b.return true/false if you are willing to accept the current drag.Where: Help→GUI→SCView accept and receive objects based on the context and your application.items = ["eh?".debug("begun dragging").states = [[SCView. // no.action = { c.isString }. a = SCListView(f.postln. aView. c = SCView. a.canReceiveDragHandler = { SCView. }. a."bee!". b = SCButton(f.value ].currentDrag. aView. } The default drag object from a list view is the currently selected integer index."].canReceiveDrag = false. receiveDrag(theView) . b. b. ) 728 .100@100)."sea.isString }.

fill(q. w.10. v. SCSlider(v.Where: Help→GUI→SCVLayoutView ID: 227 SCVLayoutView ( q = 10. ( q = 10..0.new.20)).10..20)).300.Rect(10. s.300)).Rect(0.{ var s.front ) ( q = 10.300)). v = SCVLayoutView(w.75.value = i / q. w. Array.75. w = SCWindow.Rect(0. s = SCSlider(v.resize = 5. s }).{ arg i.new.0. // Array. elastic arg i.value_(i / q) }).front ) elastic resize the window .fill(q. 729 .300. oooh v = SCVLayoutView(w. w = SCWindow.Rect(10.

730 .Rect(0. if(i < 2.300)).20)). s }).resize = 1. // elastic Array.{ var s. elastic arg i. arg i. w. s.300.300.resize = 5.front ) ( q = 5. v = SCVLayoutView(w. // some elastic s. w.10.Rect(0.value = i / 5.fill(q. }.new. // Array. v.setProperty(\minHeight. s = SCSlider(v.Rect(10.new.300)). s }).resize = 5.75. // some not elastic }).0.75. v = SCVLayoutView(w.{ s.{ var s. w = SCWindow.resize = 5.20)).front ) ( q = 5. // elastic s. s.20).resize = 5.0.{ s.Rect(10.value = i / q.fill(q.Where: Help→GUI→SCVLayoutView w = SCWindow.10. v. s = SCSlider(v.

setProperty(\maxHeight.{ var s. arg i.fill(q. // elastic Array. s.new. s = SCSlider(v.300)).0). v = SCVLayoutView(w.Where: Help→GUI→SCVLayoutView w = SCWindow. w = SCWindow. v = SCVLayoutView(w. s }).front ) spacing ( q = 10.300)). Array. s. w.0.20)).new. s.75.fill(q.value = i / 5.Rect(10.{ SCSlider(v. s.300. v.resize = 5.setProperty(\spacing.300. v.75.front ) 731 . w.10.20).Rect(0.Rect(10.0.resize = 5.40).setProperty(\minHeight.20)) }).Rect(0.10.

Rect(128. height ) *closeAll closes all windows *allWindows a list of all windows fullScreen fullscreeen mode. width. bring it to the front. panel"..Where: Help→GUI→SCWindow ID: 228 SCWindow user interface window *new(name. bounds: a Rect( distance from left. resizable. 360)). border).. 64. so don’t forget the button endFullScreen end the fullscreen mode userCanClose_ if set to false.. 340.1) bounds_ set the bounds to a Rect onClose_ can be set to a function //examples //how to add views ( var w. window is uncloseable close close the window front display the window. distance from bottom. no way to close it then. bounds.. refresh sometimes this has to becalled so the views are updated alpha_ tranparency channel value (0. 732 . w = SCWindow("my name is.

Color.view. Rect(rrand(20.front.states = [["Start "++i. w.decorator = FlowLayout(w. 75. ["Stop "++i. w. b = SCButton(w.states = [["Start "++i. Rect(rrand(20.background = Color(0.Where: Help→GUI→SCWindow 32. Color.black. w. 75.6.front.red]]. 24)).8). 64.0.8. 340. Rect(128. }).. b. which contains all the other views. Color.300). Color.do({ arg i.view.300).white.black. ( var w. w = SCWindow("my name is.rrand(20.300). panel".front. w. 32.rand]. Color.bounds). ["Stop "++i.0. Color. Color. b.rand]. ) view every window has an SCTopView instance.red]].. 24)). }).new. ) bounds_(aRect) set the bounds of the window ( x = SCWindow. w.white.front.300). 360)). Color. x.view.do({ arg i. 733 . b = SCButton(w.rrand(20.

new(border:false). w. This is the usual desired behavior. if you check the bounds in the same chunk of code.bounds = Rect(50. w. userCanClose_(boolean) Set this to true to prevent command-w from closing the window. border argument SCWindow.close will still close it.closeAll. w.new("test").front.10. the SCWindow will not yet have it updated.1). as it has no buttons.bounds_(Rect(10.height) Changes the size of the window while keeping the top left corner fixed.front. //can’t be closed. SCWindow.30)). // next application event cycle setInnerExtent(width.defer(0.postln.postln. also cmd-w not.100. nil }.bounds. Thus. onClose get the current onClose function. 50). 50. { w. window. 734 . but quick draw and Rect have flipped coordinate systems.bounds. // execute this all at once w = SCWindow. and it will still close on recompiling the library. 50. ) Note that the setting of the bounds doesn’t happen until the application finishes its current application event cycle.Where: Help→GUI→SCWindow x.

new(\default) }). x.new.alpha = 0. //close the window and the synth plays ( x = SCWindow.Where: Help→GUI→SCWindow onClose_ set a function that will be evaluated when the window is closed.front. ) 735 .8. x.onClose_({ Synth.

zoom. control) L one channel forward O jump to first hardware output channel and adjust numChannels to hardware I jump to first hardware input channel and adjust numChannels to hardware space run. index. if not running anyway.Where: Help→GUI→Stethoscope ID: 229 Stethoscope scope window a graphical interface to navigate on buses works only with internal server the scope window can be controlled by the following keys: J one channel back K switch rate (audio vs. . (period) stop.scope: 736 . view) returns a new instance of Stethoscope. M toggle screen size + / .zoom horizontally * / _ zoom vertically S change style between parallel and overlay shift S change style to lissajou (use only with fast computer and small buffer size) shift A allocate buffer size so it fills the screen (to next power of two) (this can be dangerous. might crash) instance creation: *new(server. rate. bufsize. numChannels. by the message.

free the buffer numChannels_ change the number of channels displayed index_ change the offset index rate_ change the rate (\audio or \control) size_ set the window size (default: 222) zoom_ set horizontal zoom setProperties( numChannels. stores it in the server instance var scopeWindow aBus. zoom. like { }.scope(bufsize. // examples: ( 737 . returns synth object. rate ) any of these given will adjust the scope accordingly: e. bufsize. rate) opens a scope window for the server. index. index.scope(numChannels. zoom) plays a function and shows output in scope. x.Where: Help→GUI→Stethoscope aServer. zoom) displays buffer channels in scope aFunction. bufsize. fadeTime. bufsize. zoom.setProperties(zoom:8) will only zoom.scope(numChannels. outbus.play instance methods: allocBuffer(size) (re)allocate the buffer to a given size run start it if not playing anyway free end it.g.

scope.scope only changes the properies explicitly given: s. ) // server.default = Server.ar([225. c = Bus. 2.) 738 .scope(index:0).kr doesn’t work yet. 1) ) }.size = 600.0.index). s = Server. a. a.1].ar( LFPulse.scope(numChannels:5). s.2). c.dup(4)) }.2) + LPF.audio(s. s.Where: Help→GUI→Stethoscope Server. 450. 0. // note that scoping control rate buses shows block size interpolation (this is due to the // fact that ScopeOut.0.scope(zoom:4).default.ar(226 * [1.kr(20.scope.size = 222. // scoping buses: a = Bus.[0. s.ar(0.2. 0.scopeWindow. c. s.play(s. ) ( { SinOsc. s.play(s.boot.kr(1.kr) }.internal. { WhiteNoise. 4).control(s.scope.scopeWindow. 3).index).0. 10000. { WhiteNoise. MouseX.2.1.dup(4) * MouseX. s.scope(index:12). 5]. 900]. 0.

Rect(20.decorator = FlowLayout(w. view:w. c = Stethoscope.new("my own scope".view. // don’t forget this w.front.view).onClose = { c. 400. w = SCWindow.free }.new(s. w.bounds). 500)).view. w. 20. 739 .Where: Help→GUI→Stethoscope external use: you can pass your own view in to add a stethoscope to it.

11 Help-scripts 740 .

size. doc. nameString = item.fileName.asSymbol.Where: Help→Help-scripts→Show_All_Documented_Classes ID: 230 // trolls the help extension help directories and compiles a doc with links var path. heading. extensionFunc. titleString. end.do({| item| var nameString.fullPath.tab. undocIndex = result. undocIndex. extensionsRoots.findAll("\’8"). thirdParty.at(0). // fix accent acute (remove it) currentFileString.readAllString. currentFileString. currentFileString = currentFile. var extensions. // this func trolls the directory and harvests the descriptions addFunc = {| folderPathName| var classFiles. PathName("Help/JITLib")].nl ++ Char. underlineRanges. sorted by directory.nl. // put included third party libraries at the end excluded = [PathName("Help/crucial"). headingIndices = List. titleString = "A Generated List of all Documented Classes". headingIndices. "r").nl ++ "Below is an automatically generated list of all documented classes. extensionsFolders. extensionsIndex. result = result ++ undoc ++ Char. headingFont. path = PathName. { currentFile = File(item. result = titleString ++ Char.). undoc = "*Show All Undocumented Classes". excluded.reverseDo({ | i| 741 .notNil. folderPathName. currentFile. lastSpace = 0.split($. For a list of undocumented classes click here:"+ Char. classFiles = "". if(nameString.nl ++ Char. var removeIndices.files. nameIndex. var underlineStarts.new. removePairs.asClass. addFunc. thirdPartyIndex. result.new("Help/"). spaceIndices. var undoc.

// strip RTF gunk currentFileString = currentFileString.) | | (currentFileString[nameString. // remove commas.size] == $-)}. "\t"). currentFile. if( end.copyFromStart(end).Where: Help→Help-scripts→Show_All_Documented_Classes currentFileString = currentFileString. classFiles = classFiles ++ Char. // remove tab stops currentFileString = currentFileString.1.copyToEnd(i+2). if(classFiles.size] == $.close. hyphens.notNil.size > 0.insert(nameString. { currentFileString = nameString. currentFileString = currentFileString. "["). }).reject({| item| item == $\t}). }).copyToEnd(nameString. end = currentFileString. } ).insert(0.size.size > nameString.size] == $) | | (currentFileString[nameString.notNil. if(currentFileString. { end = end .size + 1). "]"). and spaces while({(currentFileString[nameString. } ).nl.copyFromStart(i-2) ++ currentFileString.copyFromStart(nameString.drop(nameIndex).}. // add square brackets currentFileString = currentFileString. { 742 . nameIndex = currentFileString.stripRTF. if(nameIndex. { currentFileString = currentFileString. }).size. currentFileString = currentFileString. {currentFileString = currentFileString.size.insert(nameString.find(nameString).size -1) ++ currentFileString. { currentFileString = currentFileString.tab ++ currentFileString ++ Char.find("\n"). }). }).

}).nl.nl + Char.nl.do({| item| extensionFunc. extensionsRoots. 743 . item.size]).any({| item| item.foldersWithoutCVS.if({ extensionsFolders = List.nl ++ classFiles ++ Char.} ).fullPath.fileName.fileName. }). addFunc.folders.detect({| item| {addFunc. }). }. }).add(item)}. result = result ++ "\n------------------------\n\n".isNil. extensionsRoots.size. PathName(" /Library/Application Support/SuperCollider/Extensions")]. extensionsIndex = result.new. heading.}). // Check for Extensions Folders and add if they exist extensionsRoots = [PathName("/Library/Application Support/SuperCollider/Extensions"). extensionsFolders.value(folder).{ extensionFunc. folderPathName.value(item).fullPath.value(item).do({| item| addFunc.value(item). result = result ++ extensions + Char. extensionFunc = { | path| path. }. }).if({ extensionsFolders. result = result ++ heading ++ Char.}). heading = folderPathName.Where: Help→Help-scripts→Show_All_Documented_Classes //heading = folderPathName.pathMatch.nl ++ Char.size > 0 }).size. headingIndices.do({| folder| if(excluded. extensions = "Extensions:". }).do({| item| item.value(path).containsi("help").add([result.fileName == folder.

doc. underlineStarts. 16). thirdParty = "Included Third Party Libraries:".findAll("["). undoc.reverse + 1.size).do({| item| doc. doc.size. doc.rtf").open(File.string. underlineStarts = doc. titleString. //doc = Document. // set the fonts doc. 12)). headingIndices.size).nl + Char.}). 14).size).string = result.}).setFont(Font("Helvetica-Bold". 16). }).do({| item| addFunc. underlineRanges[i]). excluded. 0.do({| item. // find the underlines for help links.string.setFont(Font("Helvetica-Bold". i| doc.reverse .nl.selectRange(item. Apparently faster than storing them above.setFont(Font("Helvetica".underlineSelection.Where: Help→Help-scripts→Show_All_Documented_Classes // Third Party Libraries result = result ++ "\n------------------------\n\n". extensions. thirdPartyIndex.setFont(Font("Helvetica-Bold". thirdParty.new("Documented Classes").getcwd ++ "/"++ "Help/help-scripts/tab-template.if({ doc.setFont(headingFont. underlineRanges = doc. extensionsIndex. // this sets basic tab stops and line spacing doc = Document. doc. result = result ++ thirdParty + Char.notNil.value(item).underlineStarts. extensionsIndex. headingFont = Font("Helvetica-Bold". 744 .underlineSelection. *item)}). doc. thirdPartyIndex = result. result = result ++ "\n------------\n\n".findAll("]"). doc.title = "Documented Classes".size). doc.selectRange(undocIndex. 18).

defer(0. 745 .selectRange(0.001). doc.editable_(false).00001) }.removeUndo. {doc.}.defer(0.mouseDownAction = { {doc.Where: Help→Help-scripts→Show_All_Documented_Classes doc. // keeps window title as it should be! doc.}.0).title = "Documented Classes".

currentFileString = currentFile. excluded. // this func trolls the directory and harvests the descriptions addFunc = {| folderPathName| var classFiles. nameString = item.at(0). result = titleString ++ Char. extensionsRoots. temp. result = result ++ undoc ++ Char. headingIndices = List. undocIndex. currentFile. nameIndex.tab. doc. thirdParty. path = PathName.size. // fix accent acute (remove it) 746 . classFiles = "".fileName. addFunc.nl ++ Char.Where: Help→Help-scripts→Show_All_Documented_Extension_Classes ID: 231 // trolls the help extension help directories and compiles a doc with links var path. PathName("Help/JITLib")]. undoc = "*Show All Undocumented Classes".new("Help/").nl. titleString = "A Generated List of all Documented Extension Classes".files. extensionsIndex. "r").nl ++ "Below is an automatically generated list of all documented extension classes (i. headingIndices. or those whose class and help files are in /Library/Application Support/SuperCollider/Extensions /Library/Application Support/SuperCollider/Extensions). titleString. end. var undoc. // put included third party libraries at the end excluded = [PathName("Help/crucial"). sorted by directory. underlineRanges.asClass.\n\nFor a list of un- documented classes click here:"+ Char. var extensions.fullPath.e.new.do({| item| var nameString.split($. heading.notNil. result. if(nameString.readAllString. folderPathName. currentFileString. thirdPartyIndex.). var underlineStarts. headingFont.asSymbol. extensionFunc.nl ++ Char. undocIndex = result. extensionsFolders. { currentFile = File(item.

size + 1). if(nameIndex.1. { currentFileString = nameString.notNil.size] == $-)}.insert(nameString. // remove commas.copyFromStart(end).copyFromStart(nameString.notNil. } ). { end = end .size > nameString. nameIndex = currentFileString. // strip RTF gunk currentFileString = currentFileString.stripRTF.find("\n"). }). { currentFileString = currentFileString.find(nameString).findAll("\’8").copyToEnd(i+2). hyphens.tab ++ currentFileString ++ Char.reverseDo({ | i| currentFileString = currentFileString.size. end = currentFileString. if( end.size.}. // add square brackets currentFileString = currentFileString.Where: Help→Help-scripts→Show_All_Documented_Extension_Classes currentFileString. currentFileString = currentFileString.size] == $.insert(0.size. and spaces while({(currentFileString[nameString. currentFileString = currentFileString.drop(nameIndex).) | | (currentFileString[nameString.nl.reject({| item| item == $\t}). {currentFileString = currentFileString.copyFromStart(i-2) ++ currentFileString. }).size -1) ++ currentFileString. classFiles = classFiles ++ Char. if(classFiles. { currentFileString = currentFileString. currentFile. "]"). }). } ).copyToEnd(nameString.size > 0. // remove tab stops currentFileString = currentFileString. { 747 . "[").close. }).size] == $) | | (currentFileString[nameString. }).insert(nameString. "\t"). if(currentFileString.

// result = result ++ "\n------------------------\n\n". // Check for Extensions Folders and add if they exist extensionsRoots = [PathName("/Library/Application Support/SuperCollider/Extensions").{ extensionFunc. }.foldersWithoutCVS.folders.} ). 748 . extensionFunc = { | path| path.}).do({| folder| if(excluded. extensionsRoots.add(item)}.value(path).nl. }).any({| item| item. //addFunc.nl.fullPath.detect({| item| {addFunc.containsi("help").size > 0 }).nl + Char.do({| item| addFunc.nl ++ classFiles ++ Char.fileName.value(item). // extensionsIndex = result. // extensions = "Extensions:".fileName == folder.size. PathName(" /Library/Application Support/SuperCollider/Extensions")]. }).fileName.if({ extensionsFolders = List.Where: Help→Help-scripts→Show_All_Documented_Extension_Classes //heading = folderPathName. folderPathName. }). extensionsRoots. heading = folderPathName. extensionsFolders. }).value(item).isNil.if({ extensionsFolders.pathMatch.value(item). result = result ++ heading ++ Char.nl ++ Char. // result = result ++ extensions + Char.size]). }).fullPath. headingIndices. }).new. }. extensionFunc.do({| item| result = result ++ "\n\n".value(folder).size.}). item.add([result.do({| item| item. heading.

Where: Help→Help-scripts→Show_All_Documented_Extension_Classes // Third Party Libraries //result = result ++ "\n------------------------\n\n".title = "Documented Extension Classes".notNil.size). doc. // set the fonts doc.underlineSelection.open(File. 16). doc.setFont(headingFont. }).selectRange(item. 12)). headingFont = Font("Helvetica-Bold". underlineRanges[i]). Apparently faster than storing them above. 16).}). // this sets basic tab stops and line spacing doc = Document. doc.size).setFont(Font("Helvetica-Bold". extensions. doc.nl. doc. //doc = Document. underlineStarts.size.nl + Char.getcwd ++ "/"++ "Help/help-scripts/tab-template. i| doc.size).underlineStarts.size).do({| item| doc.new("Documented Classes"). underlineRanges = doc.reverse . *item)}).string. 0.findAll("]").do({| item. result = result ++ "\n------------\n\n".setFont(Font("Helvetica". doc.}). extensionsIndex. undoc. //thirdPartyIndex = result. // find the underlines for help links.string = result. 14). 749 . thirdParty.rtf").underlineSelection. thirdPartyIndex.setFont(Font("Helvetica-Bold".if({ doc. titleString.value(item). // //excluded.string.selectRange(undocIndex. underlineStarts = doc. extensionsIndex.setFont(Font("Helvetica-Bold".findAll("["). //doc.reverse + 1.do({| item| addFunc. // //result = result ++ thirdParty + Char. // //thirdParty = "Included Third Party Libraries:". headingIndices. 18).

750 .Where: Help→Help-scripts→Show_All_Documented_Extension_Classes doc.00001) }. doc.removeUndo.0).editable_(false).}.selectRange(0.}.defer(0. // keeps window title as it should be! doc.defer(0. {doc.001).mouseDownAction = { {doc.title = "Documented Classes".

Nev- Note that some of these classes are covered in overviews.Where: Help→Help-scripts→Show_All_Undocumented_Classes ID: 232 // Generates a list of all classes for which there are no help files. infoString = "Below is an alphabetical list of all classes which have no help files.files.nl ++ infoString. PathName(" /Library/Application Support/SuperCollider/Extensions")]. var documented.containsi("help"). etc. var paths. doc.at(0).asSymbol. { documentedClasses.nl ++ Char. from CRUCIAL-LIBRARY. var titleString. undocumentedClasses. JITLib.size. 751 . tutorials. result. or currently non-functioning or vestigial classes (such as the image synthesis classes from SC3d5). For a list of documented classes click here:\n\n". paths = [PathName("Help/"). documentedIndex. This includes classes Note that many of these are either private classes not intended for direct use. classesStartIndex. // compile list of documented classes and compare with master class list // WAY faster than searching for individual files addFunc = {| folderPathName| folderPathName. var documentedClasses.nl.asClass.new.split($.).asClass). documentedClasses = List.asSymbol. abstract superclasses (such as Clock). nameString = item. documentedIndex = result.nl ++ Char. documented = "*Show All Documented Classes". if(nameString.notNil. result = result ++ documented ++ Char.if({ folderPathName. and other third party libraries you may have installed.fullPath. titleString = "A Generated List of all Undocumented Classes". addFunc. infoString.\n\nClicking on any of the Class Names below will open a Class Browser. PathName("/Library/Application Support/SuperCollider/Extensions"). ertheless this is a good place to look for undocumented functionality. result = titleString ++ Char.do({| item| var nameString.add(nameString.fileName.

// weed out metaclasses name.isMetaClassName. doc.size. paths. 18). name = item.string = result. }). classesStartIndex = result. doc. 752 . undocumentedClasses = Class. }).nl.new("Undocumented Classes").selectRange(documentedIndex. //doc = Document.do(addFunc).asString. result = result ++ Char. }.nl ++ name.allClasses. documented.name.difference(documentedClasses).underlineSelection.rtf"). doc.title = "Undocumented Classes".not. titleString.if({ result = result ++ Char. }).do({| folder| addFunc.mouseDownAction = { arg document.open("Help/help-scripts/tab-template. 12)).size).value(folder).do({| item| var name. doc. doc. doc = Document. }).setFont(Font("Helvetica-Bold". // Click on name opens class browser doc.foldersWithoutCVS.setFont(Font("Helvetica". //doc. 0.Where: Help→Help-scripts→Show_All_Undocumented_Classes }).size). undocumentedClasses. folderPathName. }).

defer(0. line = document. if((document. { (line ++ ". (line. }.selectRange(0.size > 0).currentLine. doc.}.Where: Help→Help-scripts→Show_All_Undocumented_Classes var line. 753 .1).&amp.removeUndo.0). {doc.browse").selectionStart > classesStartIndex) &amp.interpret }). doc.editable_(false).

Where: Help→Help-scripts→Tab-template ID: 233 754 .

12 JITLib 755 .

1 Environments 756 .12.

localPut. *new(envir) create new redirect. put. pop. keysValuesArrayDo. findKeyForValue. 757 . push. which it can replace where needed: *push. envir return the source environment envir_ replace the source environment Overriding the following methods. *pop.see[Public]. keysValuesDo. choose. do. This is done for example in[LazyEnvir] and [ProxySpace]. one can redirect where objects go when they are assigned to the space: at. EnvironmentRedirect implements some of the interface of [Environment]. clear. removeAt. if envir is given it is used.Where: Help→JITLib→Environments→EnvironmentRedirect ID: 234 EnvironmentRedirect superclass: Object base class for environment redirects Environment that redirects access (put) and assignment (at). a dispatch function can be supplied . doesNotUnderstand Networking: EnvironmentRedirect and its subclasses can be used to dispatch assignment over a network. To do this. <>know. sortedKeysValuesDo. use. make.

// defaults to 2. put(key. c. val) sets the value of the reference at key at(key) returns a reference to the object at key. 758 . // examples l = LazyEnvir.0. calculations can be done with nonexisting objects which can then be assigned later.rand }. // defaults to 1 // operations on placeholders ( c = a + b.value.push. the default value is returned (integer 1) Consequently. If none is present. ) // variables can be assigned later ( a = 800. c. b = { 1. a. // default objects are created on access a.Where: Help→JITLib→Environments→LazyEnvir ID: 235 LazyEnvir lazy environment superclass: EnvironmentRedirect Environment with deferred evaluation and default values.value.value.

c.rand }.Where: Help→JITLib→Environments→LazyEnvir ) // variables can be exchanged later ( b = { 1000.value. ) 759 .

The rate is determined in a lazy way from the first object put into this environment. Once it is created it can only be set to a function that returns the same rate and a number of channels equal to the intial one or smaller. which in this case is something playing on a server that writes to a limited number of busses. something). see [the_lazy_proxy] if the ugen function’s number of channels is smaller. the outputs will wrap around and mix accordingly. currentEnvironment. the offset in ’put’ can be used to offset the ugens if the number of channels is larger. #a3925a #a3925a #a3925a 760 . usually in any order.put(\out. a proxyspace can be created when its server is not running and played later. (this can be for example a synth or an event stream) When accessed. // note that the two expressions are equivalent: out = something. #a3925a #a3925a #a3925a Note: The following examples can be executed line by line. ProxySpace returns a[NodeProxy].Where: Help→JITLib→Environments→ProxySpace ID: 236 ProxySpace an environment of references on a server superclass: LazyEnvir Generally a proxy is a placeholder for something. code that should be evaluated together is set in parentheses.

default key: \out record(key. note that on remote computers the clock must be in sync name: a symbol.To have multiple levels of proxy spaces. clock) replace the currentEnvironment with a new ProxySpace and clear the current one. use pop and then push a new one. sampleFormat) returns a RecNodeProxy that records the NodeProxy at that key ar(key.new. name. clock) server: a Server object. headerFormat. *pop restore the previous currentEnvironment instance methods play(key) returns a group that plays the NodeProxy at that key. path.push. numChannels. *push(server. the proxy space is stored in ProxySpace.all under this name. if it is a ProxySpace (this is to avoid piling up proxy spaces in performance). if a name is given. clock: for event-based or beat-sync playing use a TempoClock. name.Where: Help→JITLib→Environments→ProxySpace #a3925a class methods *new(server. offset) 761 . In order to move to another ProxySpace while keeping the current. use .

e. to be used within a function used as input to a node proxy wakeUp when the proxyspace is created without a running server this method can be used to run it (internally this is done by play(key) as well. then clear. if none are passed in. offset) returns a NodeProxy output that plays the NodeProxy at that key. fadeTime_ set the fadetime of all proxies as well as the default fade time clock_ set the clock of all proxies as well as the default clock. all proxies that are monitoring (with the .e. If a fadeTime is given. *clearAll clear all registered spaces "garbage collecting": clean(exclude) free and remove all proxies that are not needed in order to play the ones passed in with ’exclude’. this frees all buses. reduce(to) free all proxies that are not needed in order to play the ones passed in with ’to’. first fade out. free also the groups) release(fadeTime) release all proxies (i. if none are passed in.play message) are kept as well as their parents etc. numChannels.Where: Help→JITLib→Environments→ProxySpace kr(key. free(fadeTime) free all proxies (i. all proxies that are monitored (with the play message) are kept as well as their parents etc. keep the groups running) clear(fadeTime) clear the node proxy and remove it from the environment. 762 .

p = ProxySpace. 0. 0. 30. out = { SinOsc. 437] * Lag.push(s). out = { SinOsc.kr(1. 1.3).1 + x.boot. 1)) }.ar([400. out = { SinOsc.play.2) }. 0. 0.9.2) * x. This does not allow open functions as proxy sources.local.ar([400. p. 437] * 0.kr(0. 0. 437] * 0. 763 .3]) }.2) * x }.9. 0.ar([400.ar([400.3] * MouseX.Where: Help→JITLib→Environments→ProxySpace storing document(keys) creates a new document with the current proxyspace state.kr([1. 437] * 1.2) * x. out = { SinOsc.9.1.2) * LFPulse. ) out.value }.kr(2) }.fadeTime = 5. 0. 407] * 0. 0. 0. 1. see: [jitlib_asCompileString] keys: list of keys to document a subset of proxies for more examples see: [proxyspace_examples] [jitlib_basic_concepts_01] // examples ( s = Server. x = { LFPulse.kr([1. 0. out = { SinOsc. s.ar([400. 0.

end(8). // remove all. move out.pop. // end all in 8 sec. 764 .clear.Where: Help→JITLib→Environments→ProxySpace p. p.

2 Extras 765 .12.

forward) store the history as one compileString *saveStory(path) store in a file. 450). in historical order as individual code snippets // example History.free. 766 .2) }. Since it records everything that is interpreted.Where: Help→JITLib→Extras→History ID: 237 History keeps a history of interpreted lines of code History keeps track of all code lines that are being executed.set(\freq. (adc 2006) *start / *stop start/stop adding interpreted code to history *clear remove all items from history *enter(obj) add an entry by hand *document post the history in a new document *drop(n) drop the newest n lines from history. 0.ar(freq. drop the oldest n lines *keep(n) keep only the newest n lines from history. to easily reuse earlier versions. a = { | freq=440| SinOsc. a. there is only one instance of History. or to store and reproduce a performance. a. if n is negative.start. keep the oldest n lines *saveCS(path.play. 0. in order to forward them to other players. if n is negative.

Where: Help→JITLib→Extras→History History. // stop collecting // removing and adding lines History. // do some things p = ProxySpace. 1 + 2. // drop the newest memory // more examples History. // code line gets stored (nil+ 2).drop(-1).stop.enter("2 + 2").push. 767 . // drop the oldest memory History. // make a simple entry by hand.document. empty lines not: s.start.drop(1).makeWin. // error lines are ignored // comment-only is kept. // create a document with all the changes History.boot.postln. // gui window History. History.

1. ) test = { Blip..postDoc(0).stop. // start over with a clean slate.02].ar(50 * [1. 500).1 }. test. // post most recent line History. // clear last 4 lines History.saveStory.kr(3 ! 2. 8)) * 0. // save as compilestring for reloading.saveCS.keep(4).. test.1). 500). // clear last line History.postDoc(4).kr(3 ! test = { Blip. 5.removeAt((0.3)).clear. test.1 }. // keep newest 4 History. // save with special name.saveCS(" /Desktop/testHist. 768 .1 }. with given filename. // write all to file in historical order History. History. // go back 4 lines History. test.saveStory(" /Desktop/myTest. // .document.clear.playN.sc"). 8) * 0. 2. 200.stop.txt". History.Where: Help→JITLib→Extras→History ( test = { Blip. 200. History. History..kr(5 ! 2.ar(LFNoise1. History. 4) * 0. History.vol_(0. in forward time order.removeAt(0). LFNoise1.ar(LFNoise1. forward: true).

Where: Help→JITLib→Extras→History // To Do: // History Reloaded .sc"). // History. // History.sc").saveScript(" /Desktop/histScript.. 769 .saveScript.loadCS(" /Desktop/testHist.autoSave_(true). // with given filename. // auto-save by appending to a file . // History..from a saved file: // History. // save as one runnable task/script.

// fulfil stopTest // Typical use: SkipJack updates a window displaying the state // of some objects every now and then.20)) . a = 10. and use defer only where necessary.align_(0).. // use stopTest: a = 5. 0.verbose = true. Rect(i * 100. \b].yellow).5.postln. default is AppClock. Rect(0..5. d = (a: d.stop.". 770 . "test")..Where: Help→JITLib→Extras→SkipJack ID: 238 SkipJacka utility for background tasks that survive cmd-. b: 24).stop. d. updateFunc. *new(name. stopTest) updateFunc the function to repeat in the background dt the time interval at which to repeat stopTest a test whether to stop the task now name is only used for posting information clock the clock that plays the task.background_(Color. name: SkipJack. w = SkipJack({ "watch. // now try to stop with cmd-.60)).start. If you need more precise timing. w. }.0. }. ( // example is mac-only 12. 0. w. you can supply your own clock.stop. // post stop/wakeup logs "test").200. : SkipJack always restarts itself.win. thisProcess. }. w. w = SkipJack({ "watch. { a == 10 }.collect { | name. i| SCStaticText(d. dt.string_(name).views = [\a..".0. so SkipJack can call GUI primitives.front.postln.win = SCWindow("dict".96.

string_(name ++ ":" + d[name]) } }.isClosed }.close. ) d.new("dict". SkipJack stops. 0.". // when window closes.20)) .60)). ) // I prefer this ’lazy’ gui idea to a dependency model: // Even when lots of changes happen fast. d = (a: d.views[i].. Rect(0. }. [\a.win.postln.do { | name.win. 771 . you don’t choke your // cpu on gui updating.yellow).views = [\a.string_(name).front. w = SkipJack({ ".0. "showdict" ). you still see some intermediate states. d.new(d.do { | name. d.5.win = GUI(\window).a = 123.postln.string_(name ++ ":" + d[name]) } }.win. { d.background_(Color.200.0.5. b: 24).align_(0).Where: Help→JITLib→Extras→SkipJack w = SkipJack({ ". but written in x´cross-platform gui style: 12. Rect(i * 100. i| d. ( // the same example. i| GUI(\staticText). \b]. // updates should be displayed d. { d. \b].views[i]. [\a.. \b].win.".96. 0.collect { | name. i| d..b = \otto.. "showdict" ).isClosed }.

.Where: Help→JITLib→Extras→SkipJack // if you need to get rid of an unreachable skipjack SkipJack({ "unreachable. // reach it by name and stop 772 .stopAll // do this to stop all. SkipJack.postln }. name: "jack").". SkipJack. unkillable.stop("jack")..

3 Miscellanea 773 .12.

this library attempts to extend. These two aspects of space corresponding to inclusion and reference. mainly by providing placeholders(proxies) that can be modified and used in calcuations while playing. Just in time programming (or: live coding <sup>1</sup>.Where: Help→JITLib→JITLib ID: 239 Just In Time Programming "Passenger to taxtidriver: take me to number 37. on-the fly-programming. There is some specific networking classes which are made to simplify the distribution of live coding activity. if none is given. but a dynamic construction process of description and conversation . SuperCollider. Jitlib consists of a number of placeholders (server side and client side) and schemes of access. then to be productive. being a dynamic programming language. punctuality is your personal responsibility though." (an austrian math teacher’s joke) Disclaimer: there is no time. simplify and develop them. they can be used in a certain set of contexts and they have a certain default source. provides several possibilities for modification of a running program .writing code becomes a closer part of musical practice. really.here the placeholders are like roles which have a certain behaviour and can be fulfilled by certain objects. This means a program is not seen as a tool that is made first. Tutorial: Interactive Programming with SuperCollider and jitlib 774 . depend on their context . interactive programming <sup>2</sup>) is a paradigm that includes the programming activity itself in the program’s operation. I’ll give you the street name when we are there. It is useful to be aware of the three aspects of such a placeholder: a certain set of elements can be their source.

. object) sets the source and returns the proxy.push out = { . for server side NodeProxies. internally the former use these as base classes. [Pbindef] server side: [Ndef] • Another way. content: placeholders in sc [jitlib_basic_concepts_01] referencing and environments [jitlib_basic_concepts_02] internal structure of node proxy [jitlib_basic_concepts_03] timing in node proxy [jitlib_basic_concepts_04] Overview of the different classes and techniques: • One way or style of access is the ’def’ classes (Pdef. the rest of the behaviour depends on its use. [Tdef].. client side: [Pdef] [Pdefn]. such as server messaging and pattern proxies which are not covered in tutorial form presently. Ndef etc. 775 . see [jitlib_basic_concepts_02] • there is also direct access without using the access schemes: NodeProxy. There are many possibilities.} helpfile: [ProxySpace] for the use together with other environments. TaskProxy etc. is an environment that returns placeholders on demand: ProxySpace.) it binds a symbol to an object in a specific way: Pdef(\name) returns the proxy Pdef(\name. provide it.Where: Help→JITLib→JITLib This tutorial focusses on some basic concepts used in JITLib.

note that the client id should be set. [TaskProxy]. as long as it notifies the client and has a correctly initialized default node. stable: [BroadcastServer] [OSCBundle] tutorials: [proxyspace_examples] [jitlib_efficiency] [the_lazy_proxy] [jitlib_fading] [jitlib_asCompileString] [recursive_phrasing] [jitlib_networking] live coding without jitlib: [basic_live_coding_techniques] storage: [NodeMap] storing control setting [Order] ordered collection 776 . groups of participants can interfere into each other’s composition by sharing a common server. [public_proxy_space] how to distribute a ProxySpace [Client] simplifies client-to-client networking. [PbindProxy]. [RecNodeProxy] • in remote and local networks thanks to sc-architecture node proxies can be used on any server. using the network classes.Where: Help→JITLib→JITLib client side: [PatternProxy]. [Pdict] server side: [NodeProxy]. using SharedNodeProxy and exchanging code and comments in a chat (see Client) networking classes: experimental: [Public] distribute environments over networks. [EventPatternProxy].

org/wiki/Dynamic_programming_language #a3925a RECENT CHANGES: 2005 october node proxy: developments with alberto de campo: added playN method for larger multichannel setups 777 .Where: Help→JITLib→JITLib unconnected other classes: UGens [TChoose] [TWChoose] for suggestions / comments contact me Julian Rohrhuber. rohrhuber@uni-hamburg.org [2] dynamic programming would have been a good term.wikipedia.de Thanks a lot for all the feedback and ideas! [1] see for example http://toplap.org/wiki/Dynamic_programming http://en.wikipedia. but it is in use for something else already compare: http://en.

and take functions as arguments as well. not play control object control rate proxies now crossfade really linearly. there is also an .mapEnvir([\a. b. 778 . Tdef/TaskProxy take also a pattern as argument (for time streams). c].] = [ a. the respond to set / map now. defaults now end (no looping by default) nodeproxy. \c) instead of .) may pattern proxies: added de Campo suggestion: pattern proxies have now an update condition. but multiple arguments (.at now returns source.. if stuck. march pattern proxies: all can have an environment.endless method that will embed the proxy endlessly.mapEnvir(\a..have a fadeTime argument now nodeproxy / nodemap: mapEnvir now takes not an array of keys. expands into 3 channels x[0. c]. node proxy multichannel expansion with arrays of numbers works now more like expected x = [ a. NodeProxy (BusPlug) can be passed a parentGroup now. added a Dispatcher class [Public] that does the same for any EnvironmentRedirect. reset method. \b.group = .clear and proxyspace.. also ProxySpace can play in a given group (proxyspace. \c]) febuary improved network classes. \b. expands into 3 slots (mixing the inputs) april networking: removed PublicProxySpace. Tdef . b.Where: Help→JITLib→JITLib getKeysValues and controlKeys september node proxy: unset works (not tested for setn) nodeproxy.fork: fork a thread. PublicProxySpace added envir variable to pattern proxies.

old ones changed. october fixed a bug in Tdef/Pdef where the clock wasn’t passed in (. see BroadcastServer helpfile.Where: Help→JITLib→JITLib january nodeproxy. experimental network classes added.source now returns the sources added tutorial 2004 december fixed a bug when loading node proxy if the server is fresh. to allow ressource freeing in future (mainly cx players) nodeMap_( ) fixed (unmaps synth now) filter method for node proxy 779 . offset] networking: removed Router class. (not by arrays of keys anymore!) some small efficiency improvements july Pdef/Tdef: pause and resume are now beat quantized embedInStream is more efficient now.mapn expands to multiple controls. NodeProxy is more efficient in building SynthDefs. Pdef: quant can now have the form [quant.play) properly when it was set before. node proxy now removes its synthdefs from the server. fadeTime is only applied for transitions added recursive phrasing event corrected Client bundle size calculation NodeProxy remove/stop now differentiated. ProxySynthDef can be used independent of NodeProxy now september refactored Pdef: new subclasses improvements in NodeMap and NodeProxy added role scheme (helpfiles to come) august nodeProxy.

Where: Help→JITLib→JITLib june removed N / Debug class to reduce number of classes. the proto slot is used to store the tempo proxy. ProxySpace has a parent.5] = { . } Pdef: added fadeTime Pdefn default is 1. NodeProxy more tolerant) simplified object wrapping added monitor class. monitorGroup. readability improved. . bugfixes: SynthDef-hasGateControl fixed InBus static float index works now bugfix in Order-detect fix unset/unmap bug supplementNodeMap also works for non functions. which is safer for use in time patterns.. NodeProxy/ProxySpace: wrapForNodeProxy improved (Bus works now. april 780 .clear when using patterns fixed group order added crossfade support for Patterns (EventStreams) added crossfaded input offset (using e..send now sends all if no index is given refactoring. vol slots are removed (monitorGroup. separated monitoing from BusPlug channel expansion works with . avoid occasional duplicate notes when changing pattern Tdef is more error proof. added XIn Ugens lineAt. may loading large proxyspaces now works .0 now. vol is in monitor) node order in multi object node proxy works more efficiently multiple put: a[2.no late messages anymore fixed bug in NodeProxy.ar(1. xlineAt messages work now fixed the read example in [jitlib_efficiency] nodeProxy. offset)) removed Channel ugen..play now (converting number of channels) removed toggle method.g. onClear.

allow multichannel mapping in patterns added possibility to use \offset key in event streams to have offset index in multichannel proxy fixed bug in lazy init 2003 nov Pdef. NodeProxy-releaseAndFree is replaced by . Sfin etc. jan Pref / Prefn are tested. I’m thinking of merging them with Pdef. update properly.rate returning \stream) new version of Pdef/Pdefn/Tdef experimental: added .Where: Help→JITLib→JITLib fixed bug on ProxySpace-reduce that caused infinite recursion in some cases fixed bug in BinaryOpPlug (account for function. see [jitlib_asCompileString] march fixed Pattern support for NodeProxy/ProxySpace due to change in Event implementation fixed Prefn removed Penvir. (removed classes can be found on sc-swiki) simplifications feb added garbage collector to ProxySpace fixed unmap control rate proxies do not wrap channels anymore. .document methods for ProxySpace. also with NodeProxy. oct symbol input is assumed to represent a synthdef that has a gate and frees.storeOn. functions and synthdefs are searched for their inner envelopes and the appropriate 781 . Ensemble etc. fixed bug in load when no server is present embed control proxies in streams as bus index. Tdef work now.end. fixed wakeUp bug in NodeProxy.

read([b.Where: Help→JITLib→JITLib method of freeing / releasing is chosen accordingly. might change) a. lag can be set by name a. ar and kr take a second argument for the channel offset within the proxy checked all helpfiles put now has a different arg order! a.read(b) or a. 1) a shortcut was added to efficiently read from another proxy: a.lag(\freq. bin/unops work fully now again like any math op.put(0. earlier: input channels now wrap. so any number of channels can be set to any proxy. obj) or a[0] = obj prependargs were removed for now.play now does not create multiple synths if evaluated repeatedly (unless multi: true) lazy init works now. c]) added granular / xtexture functionality: gspawner / spawner (experimental. 782 .

12.4 Networking 783 .

clientID needs to be different with each participant! *for(homeServer. do(function) iterate over all addresses 784 . wrapAt(index) returns the nth web address. homeServer return the home server. homeAddr. The other servers are represented by their addresses (allAddr) in multiclient situation. addresses_(list of net addr) set the addresses the server is supposed to broadcast to. allAddr) like *new. starts from beginning. if index too large. name. name returns the name of the server. which is a server that is used for id allocation and all normal functions of a individual server model. options. but directly pass in an already existing server. The name is always the homeServer’s name extended by "broadcast" at(index) returns the nth web address. homeAddr.Where: Help→JITLib→Networking→BroadcastServer ID: 240 BroadcastServer dispatches osc messages to multiple servers superclass: Object (adaptor class) *new(name. clientID) create a new instance. options and clientID are used for the home server’s properties. This usually should include the home address.

0.homeServer.0. } ) // set them to different freqs.do { arg addr.rand2).sendMsg("/n_set". b. y]). a. } ) 785 . nil. 57201).addresses_( [x. "freq".sendMsg("/n_set". "freq".do { arg addr. one on each server b. y. 1980.sendMsg("/n_set".sendMsg("/s_new".makeWindow. 550).boot. a = BroadcastServer(\broad1. b.1". "freq".1". 57202).boot. "freq". addr. addr. nil. 1980.0. 1980). // set both their freq control a. 1980. ) a.Where: Help→JITLib→Networking→BroadcastServer // example ( x = NetAddr("127. 300). y]).0. 0).sendMsg("/n_set". x. y = NetAddr("127.addresses_( [x. from b ( b. 450 + 100. a. from a ( a. // create 2 synths. b = BroadcastServer(\broad2. // set only the home server’s synth control // set them to different freqs. 450 + 100. 1). "default".rand2).makeWindow. 1980.

0). "gate". 1980. // release all. from b 786 .sendMsg("/n_set".Where: Help→JITLib→Networking→BroadcastServer b. 0.

. args . which is hardcoded presently. netAddr) returns a new instance and stores it in a global dictionary the port is set to defaultPort. an sclang application can evaluate code on a remote sclang app.. it interprets the string 787 . Using SynthDef like global function definitions. localhost is used. if no address is passed in. Class Methods *new(name. ClientFunc.Where: Help→JITLib→Networking→Client ID: 241 Client represents a remote sclang application Client and LocalClient together represent a sender / reciever pair for sclang side osc messages.) evaluates a client function that is stored at that key password_ (symbol) set the password for interpreter access cmdName_ set the cmdName under which the client sends (default: ’/client’) this cmdName must be the same like the LocalClient reciever cmdName interpret(string) if the remote client has the same password. Instance Methods send(key.

If it is expected to listen to a specific remote client.Where: Help→JITLib→Networking→Client LocalClient superclass: Client represents a listener to a remote sclang application Note that passing a nil address to LocalClient will make it respond to any remote client and try to match any message that is sent from a client object. the address of that client should be used. Instance Methods start start listening to the world stop stop listening to the world remove remove from client list isListening returns whether it is listening to the world password_ (symbol) set the password for interpreter access from outside cmdName_ set the cmdName under which the client recieves (default: ’/client’) this cmdName must be the same like the Client sender cmdName allowInterpret open the interpreter to the world (potential hacking danger) disallow close the interpreter access 788 .

the key sent is a key of the ClientFunc that is evaluated. Note: for accessing a gui element or a document from an OSCResponder such as the one in LocalClient. NetAddr("127. ClientFunc(\yes. // this one sends the messages // eqivalent to the above defaults: a = LocalClient(\default.1". b = Client.Where: Help→JITLib→Networking→Client ClientFunc similar to SynthDef .0. nil). args. { defer({ . "rrere". { arg .0. 789 .postln }). // store some client functions to be accessible from outside (analogous to SynthDef) ClientFunc(\ok. args. args. 57120))... 39). // start the local client a. { arg .represents a client side stored function *new(name. "rrxxxre").send(\ok. args. // send messages b..start.. //addr is nil : listen to all b = Client(\default.new..send(\ok. }) }).. responder. // example // instantiate a remote-local pair (in this case both are local of course) a = LocalClient. // this one listens to any remote client and evaluates the functions.default.postln }). the other args are passed to the function: time. b... \ok2. func) global function that is accessed by LocalClient when a message is recieved. one has to defer the action: ClientFunc(\ok.

5.Where: Help→JITLib→Networking→Client b. { [1. because anyone can access the interpreter (also unix commands) if you do not set the password.postln "). "rrere".choose }). 400. 2. $n]. b. b.interpret(" SCWindow. b. d = Document("chat").fill(8. this is not possible. a. a. b. // open interpreter a.disallow //test: this should not interpret b. 39).postln").choose }).fill(8. // remote interpret b. opening remote interpreter access is risky.").send(\ok.choose }). e. 790 .send(\yes. // close interpret a.fill(80.interpret(" String. LFPulse.rand). 200)). 0.front.{ SinOsc. // remote GUI b. d. 10. $n].interpret(" String.play.bounds_(Rect(30.postln").new(\"aLl uR mAchIneZ are bEloNg to us!\"). //stop local responder writing a chat ( // hit tab for sending var n. 4.interpret(" Array. 3.stop. { [$u. b.ar(500.password = \xyz.background_(Color.send(\yes).allowInterpret. 6).0].kr(4)) }.password = \xyz. n = "John". { [$u.

{ e.default.string = ""}).sched(0.keyDownAction_({ arg doc. b = Client. string. char.tab) { string = n + ":" + e. // time is the original crime. { arg str.1.close.remove. otherwise sc crashes ) remove the tab. 791 . nil }) }). // sched.copy). e. 400.start.string ++ str ++ "\n" }. 50)).send(\chat. { a.string = d. 210. a = LocalClient.defer }).background_(Color.onClose_({ AppClock. if(char === Char.bounds_(Rect(30.rand).new. var string.currentLine. { d.1. } }). b. AppClock. e.Where: Help→JITLib→Networking→Client e = Document("chat-write"). ClientFunc(\chat.sched(0. d.

such as LazyEnvir and ProxySpace. Dispatchers like Public can be used for any EnvironmentRedirect. nil: listen to all. which is very flexible and leightweight but it also means that one has to be careful not to do harm to the other systems. Timing is still not yet synchronized.Where: Help→JITLib→Networking→Public ID: 242 Public dispatch system superclass: EnvirDispatch experimental. dispatchers with the same name send to and receive from each other (alternative: provide a sendToName) *startListen(addr) start to receive messages from the network addr: whom to listen to. (default) *stopListen stop listening instance methods: 792 . although it works pretty well for not too costly code. They cause a mirroring of parts of the environment to multiple locations. Code is only sent if it interprets without error on the sender side. This done bysending the code itself. see also: [public_proxy_space] class methods: *new(envir) create a new instance (with an EnvironmentRedirect) *all a dictionary of all available dispatchers.

If nil. the "worst" commands are rejected . object must be reproducible as a compileString!. send object to all. send to all. my own changes are passed into the action function (e. if \all. nickname) join a channel with a nickname leave leave the channel if public is set to false. logSelf_(bool) if logSelf is set to true.g. do not send. (closed functions.like unixCmd etc. patterns with no open functions) at(key) returns an object from the space at that key (see superclass).Where: Help→JITLib→Networking→Public addresses_(list) a list of addresses (NetAddr) to which to send to. This is only allowed if sendingKeys are set to \all channel_(name) set / get channel name nickname_(string) set / get nickname action_(func) action to be evaluated when receiving a message (optional) args: dispatch. if this key is sending. obj) put an object in the space (see superclass). even if they do not effect me (listeningKeys != \all). do not send. put(key. nickname. receivedString function 793 . join(channel. If nil. listeningKeys_(list) keys at which to receive (list of symbols). key. this list can contain also the sender’s address. sendingKeys_(list) keys from which to send (list of symbols). but does not get evaluated. public_(bool) basicSafety_(bool) if true (default). no broadcasting happens. send to all. if \all. which it then sends to. the log window) logAll_(bool) if logAll is true. I can see all messages that are coming in.

sendingKeys = \all. you need to use defer { } makeLogWindow create a log window. 794 . the spaces are enitirelly open.0. provide a unique nickname.sendingKeys = \all. // set their dispatch variables. e. // create 2 new instances (one "remote" one "local") e = Public.1".this can be done at any time laterto add new ones.new. d.new.addresses = addresses. e. d. d.0.new.g. // start an osc responder to dispatch the messages addresses = [NetAddr("127. Port must be 57120 (sc-lang) d = Public.Where: Help→JITLib→Networking→Public note: if you want to call the os from this action (e. for GUI). lurk / boss / merge change behaviour diametrically (just try it out) // example ( var addresses.join(\waitingroom. b.listeningKeys = \all. d.dispatch = d.dispatch = e. b = EnvironmentRedirect. // create two new environment redirect (works basically like an environment) a = EnvironmentRedirect. // set the addresses . Public. e. 57120)]. // if keys are set to \all. // join a channel.new.listeningKeys = \all. \ade). \eve). // this is loopback for now. e.addresses = addresses.join(\waitingroom. the envir is registered in the dispatch implicitly a.startListen.

795 .rand }. a.clear. a[\x] = "hi eve". b[\x] = { 1. a[\x]. // 5 is in b now as well.clear. b[\x].postcs. ) // using the environment a[\x] = 5. a[\x] = Array.rand(20.0. // more to come. b. b[\x].. 0.makeLogWindow. // see what is going on d.makeLogWindow. 10)..Where: Help→JITLib→Networking→Public ) ( e. b[\x] = "hi adam".

dispatch = e. see [Public] help for more about the configuration. e = Public(b). d = Public(a). Using a dispatch such as Public. a changes to a ProxySpace can be transmitted by code to a remote (or local) other ProxySpace and is compiled there as well. // example ( var addresses.addresses = addresses. b.addresses = addresses. d. This is very flexible and leightweight but it also means that one has to be careful not to do harm to other systems.0.dispatch = d.Where: Help→JITLib→Networking→Public_proxy_space ID: 243 public ProxySpace distributed system this is an example how to create a networked proxyspace. addresses = [NetAddr("127.startListen. b = ProxySpace(s). 57120)].0. Public. 796 . Code is only sent if it interprets without error on the sender side. a. e.1". Timing is still not yet synchronized. although it works pretty well for not too costly code. a = ProxySpace(s).

e.1 }.1 ! d.ar(rrand(300. 0.listeningKeys = \all. "a". d.ar(0.pop. d. d.join(\waitingroom.makeLogWindow. 797 . // same tone d.boot. // you can also enter the space: a.play. // be private b[\out] = { PinkNoise. ) // modify space s. // exit // now you can type into both of them.sendingKeys = \all. out. // example string EnvirDocument(a.public = false.free. \ade). ) ( d.makeLogWindow. 400)) ! b[\out] = { SinOsc. ". a. // two different tones 2) }.push. // set here 2 * 0. str).play.1 ! b[\out]. // play here a[\out] = { PinkNoise. just as in examples in ProxySpace.ar(0. "b".0. str = "\n out = { LFNoise2. // see what is going on e.help: ( var str.ar(300) ! 2 * 0.listeningKeys = \all. \eve).Where: Help→JITLib→Networking→Public_proxy_space e. EnvirDocument(b. 2) }. e.1) }.public = true.sendingKeys = \all. // boot server a[\out].ar(3000 + exprand(1. 2000). str). // play here too b[\out] = { SinOsc.join(\waitingroom.1 }.

Where: Help→JITLib→Networking→Public_proxy_space ) 798 .

superclass: ProxySpace distributed system *new(broadcastServer. the server should be a fresh. clock) return a new instance and make it the currentEnvironment broadcast return the broadcast server server return the home server makeSharedProxy(key. rate. firstAudioKey) create multiple SharedNodeProxies. unused BroadcastServer *push(broadcastServer. clock) return a new instance.Where: Help→JITLib→Networking→SharedProxySpace ID: 244 SharedProxySpace experimental. addSharedKeys(controlKeys. audioKeys. unused server. generate them automatically. this is a character (default: $s) of the first audio key in alphabet 799 . This should be done with a fresh. name. This should be done with a fresh. unused server controlKeys: names of the control rate proxies audioKeys: names of the audio rate proxies firstAudioKey: if the above are not given. using the letters a-z. numChannels) create a SharedNodeProxy with a group id that is derived from the key: only short strings work. name.

57201).0.play. 0. y. 0).ar) + Rand(0. 0. b. // play locally // play sine tone with freq dependant on ensemble. a.boot. 1).makeSharedProxy(\ensemble.0. b = BroadcastServer(\B2.Where: Help→JITLib→Networking→SharedProxySpace // examples: // prepare and boot two servers ( x = NetAddr("127.ar(440 + (300 * ensemble. nil. "Elizabeth"). // this has to be done with the fresh servers: p. x. r = SharedProxySpace. 800 .1) }.makeSharedProxy(\ensemble. b.0.1".push.1". a = BroadcastServer(\B1.makeWindow. y]). \audio. out.makeWindow.new(a. y]). 57202). ensemble = 1. "George"). r. but a little random. 10).0. // Elizabeth pushes her proxspace: p. y = NetAddr("127. \audio. currentEnvironment === p.allAddr_( [x. out = { SinOsc. // returns a shared node proxy. a. 1).new(b. ) ( p = SharedProxySpace. ) p.envir[\ensemble].boot. nil. 1). // tune up a bit.allAddr_( [x.

out. // Henry pushes his proxyspace r. 0. b.clear.stop. ensemble. out. // stop only locally // finish: r.push. out = { Ringz.5.ar(9. 801 .push.4.ar * 300 + 400.02].ar(0. 0. // Elizabeth p. 0. 0. freq = 300 * ensemble + 400.ar. 2.ar(Impulse.1 }.clear.2) }. ensemble = { SinOsc. ensemble = 0.quit.8). pi)) * 0. out. 10) }.ar( freq. 1.ar(0. // now both depend on the "same" bus.Where: Help→JITLib→Networking→SharedProxySpace ensemble = { Line.6) }. 0.ar( freq.push.quit. out = { SinOsc. // stop only locally // Henry r.stop.ar * [1. p. 0. // quit the servers a. SinOsc.play.

5 Nodeproxy 802 .12.

m. MouseX.rand(16. m = { SinOsc.kr(0. m = { Mix(SinOsc.rand. 300. 300.rand. 320).help. rrand(500. z.rand(16. 1000))). z = Bus. //using as a audio monitor 803 . a = BusPlug.rand. 0. //modulate channel offset z.control(s.free.setn(Array.play. rrand(500.put(16. m. 0. 19)). 0. 1000))).boot. rrand(500.rand.setn(Array. 300.rand(16. 0. 320).ar(a.1) }.put(16. 320). z. for most methods see NodeProxy.put(16. monitor returns the current monitor (see [Monitor] ) //using as a control bus listener s.play.1)) }.rand(16.for(z). 16).setn(Array. 300. z.ar(a. rrand(500. but it can be used as well for other things. z. 1000))). 1320).free. it is mainly a basic subclass of NodeProxy.setn(Array.Where: Help→JITLib→Nodeproxy→BusPlug ID: 245 BusPlug a listener on a bus superclass: AbstractFunction a superclass to node proxy that listens to a bus.kr(2.put(16. 1000))).kr(16).free.

//monitor whatever plays in p (the execution order does not matter) d. 0.ar(12. p. PinkNoise.2).1. x.1])) }.play. 0.play.stop.free. p.1])) }.Where: Help→JITLib→Nodeproxy→BusPlug p = BusPlug.index.audio(s. PinkNoise.ar([0.2) }.free.play(12). p. d = { Out.play.stop.play. 804 . //listen to that bus for a test: x = { InFeedback. //also p can play to another bus: p.play.ar(p.1. d = { Out. p.ar([0.ar(p.index.

s. . 1) * [1. doesn’t work right now.. 805 .0). multi: keep old links and add new one volume: volume at which to monitor fadeTime: fade in fade out time isPlaying returns true if the group is still playing stop(fadeTime) stops within the fadeTime vol_ set the volume out_ set the output index.default = s = Server. target. (same as . 2).ar(MouseX. toNumChannels. x. s.new. 3.add //example Server.play. volume. multi. { Out. playToBundle(bundle. SinOsc. 10000. 0.scope(16). toIndex. the bundle should support the message.play)) adds all playing osc messages to the bundle. 3]. fadeTime) plays from a bus index with a number of channels to another index with a number of channels.out = 0.ar(87. 1.play(87. x = Monitor.Where: Help→JITLib→Nodeproxy→Monitor ID: 246 Monitor link between busses superclass: Object play(fromIndex.stop(3. 0. x.. x.kr(40. within a target group. or a server.boot. fromNumChannels.2)) }. 2.internal.

play(89.play(87. mastervol. might change: // multichannel method // playN(outs.playN([0. 1.Where: Help→JITLib→Nodeproxy→Monitor x. 88 -> 1. 2]. // play: 87 -> 0. [87. 2.playN(vol:0. fadeTime:4). 1).1. multi:true). 0. 1. 3. 2].4.1].4. 88. x. 0. 1. 0.play(89.play(87. [0.4.2.stop. 0. now mixes down (wrapping) now distributes to 2 channels // multiple play x.3]. [0. // in < out : x. [0. multi:true). 0. 88. 1. 89]). [0. and 0.1]. 806 . x. x.0. // in > out : x. 1. // experimental. 88 -> [1. 1. 89]). 0. 2).play(88. [87. 0.3 x.stop. 0. 4]. ins. amps can be nested arrays x. [1. fadeTime. 2.1.3]. 0. multi:true).2. 3. 4]. 89 -> 4 x. 89 -> 4 // volumes 0. 0.playN([0. group) // outs. // play: 87 -> 0. 2. 0.1. amps. 0.

key) return an instance at that key for that server defaultServer_(a server) set the default server (default: Server. SinOsc. like Tdef and Pdef. { SinOsc. SinOsc. 635] * 3. Ndef(\sound).Where: Help→JITLib→Nodeproxy→Ndef ID: 247 Ndef node proxy definition superclass: NodeProxy reference to a proxy.max(0) * 0. it is interpreted as server -> key.max(0) * 0. obj) stores the object and returns the instance.boot. 0. if key is an association. Ndef(\sound. object) craete a new node proxy and store it in a global dictionary under key.ar([600. see also ProxySpace.fadeTime = 1.ar([600. *clear clear all proxies *at(server.ar([600. Ndef(\sound. if there is already an Ndef there. NodeProxy *new(key. forms an alternative to ProxySpace Ndef(key) returns the instance. 635]. { SinOsc. Ndef(\sound). Ndef(key. 635] * 2. { SinOsc.play.kr(2).max(0) * 0.2) }). replace its object with the new one.kr(2 * 3). SinOsc.2) }).kr(2 * 3). 0. The object can be any supported class.local.local) // examples s = Server. 807 . see NodeProxy help. Ndef(\sound. 0.2) }).

ar * 10. Ndef(\sound. a structure like the following works: Ndef(\sound. usually 64 samples. SinOsc. Ndef(\sound).max(0) * 0. 635].kr(300. 0. { LFNoise1.ar([600. Ndef(\lfo. Pbind(\dur.kr(3. this is due to the fact that there is a feedback delay (the server’s block size). Pfunc({ rrand(300. so that calculation can reiterate over its own outputs.max(0) * 0.map(\freq. Ndef(\sound).ar([600. 400.play.kr(2).2) }). { SinOsc. 700) })) ). { arg freq. Ndef(\sound). SinOsc.Where: Help→JITLib→Nodeproxy→Ndef Ndef(\sound.kr(2 * 3). 635] + freq. 400. 0. Ndef(\lfo)).2) }). 800) }).17. 800) }).clear. { LFNoise1. \freq. Ndef. //clear all recursion: Ndefs can be used recursively. Ndef(\lfo. LFNoise1. 808 .

0. key2.Where: Help→JITLib→Nodeproxy→NodeMap ID: 248 NodeMap object to store control values and bus mappings independant of of a specific node.. busNum=0. LFPulse.kr(rate. latency) apply a setting to a node by sending a bundle addToBundle(aBundle) add all my messages to the bundle s.. numChan. Out. busindex1. { arg freq=320. . valueArray1. { arg rate=2.2.. latency) apply a setting to a node by sending a bundle send(server... amp)).1). .ar(freq.kr(busNum. ( SynthDef("modsine".control(s. amp=0. value1. }). busindex1. 809 . . 0.) remove settings unmap(key1.1.) remove mappings setn(key1. Out.2)) }).) set bus mappings of a node unset(key1. 0..boot. ) //start nodes ( b = Bus. set(key1. key2.) map num busses mappings to node at(index) return setting at that key. SynthDef("lfo". 0. ..) set ranges of controls mapn(key1.. ..) set arguments of a node map(key1. nodeID. SinOsc.. x = Synth("modsine").send(s)..ar(0.send(s).. sendToNode(aTarget.

b. b. h.unmap(\amp).before(x. h.set(\freq. b. h. h. ) //apply the maps h. //the first time a new bundle is made k. ) //create some node maps ( h = NodeMap.index). h. k. [\busNum.sendToNode(x). 810 .Where: Help→JITLib→Nodeproxy→NodeMap y = Synth. k.free.sendToNode(x). k = NodeMap.new.map(\amp.new.free.free.set(\freq. //when a value was changed. a new bundle is made //free all x.sendToNode(x). 600). 400). y. 800).sendToNode(x).index]).set(\freq. //the second time the cache is used k. "lfo".sendToNode(x).

clear instance creation *new(server) *audio(server.free for free inner players and stop listen: p. all the examples below apply to ProxySpace accordingly: a = NodeProxy(s) is equivalent to a.stop... which in this case is something playing on a server that writes to a limited number of busses. is equivalent to a[3] = ... The rate and number of channels is determined either when the instance is created (. see also: [jitlib_efficiency] note that NodeProxy plays on a private bus.play and p.. a[3] = . (this can be for example a synth or an event stream).source = .. is equivalent to a = .end entirely removing all inner settings: p.. ProxySpace returns instances of NodeProxy..[the_lazy_proxy] These objects can be replaced. numChannels) *control(server. numChannels) 811 . if you want to hear the output. free only the inner players: p. a. mapped and patched and used for calculation. use p.control/.audio) or by lazy initialisation from the first source.Where: Help→JITLib→Nodeproxy→NodeProxy ID: 249 NodeProxy a reference on a server superclass: BusPlug Generally a proxy is a placeholder for something.

kr to mono. normally ar defaults to stereo. to stop the objects playing. release fadeTime: decay time for this action end(fadeTime) releases the synths and stops playback fadeTime: decay time for this action ar(numChannels) kr(numChannels) return a link to my output.Where: Help→JITLib→Nodeproxy→NodeProxy reading from the bus play(index. multi) play output on specified bus index (default: public busses) this works like a monitor. which is limited by [numChannels] causes an uninitialized proxy to create a matching bus. if multi is set to true it can create multiple monitors stop(fadeTime) stop to play out public channels (private channels keep playing as others might listen still) this stop the monitoring. defaultNumControl supported inputs NodeProxy Function SimpleNumber Bus SynthDef Symbol played by reading from interpreted as UGenFunc used to write to bus continously reads from that bus plays a synth from the def plays a synth from the def with this name 812 . this can be set in the classvars: defaultNumAudio. group. use free. numChannels.

this can be used to do filtering. an Instr. the nodeProxy will assume doneAction 2 and fade out]. all objects are freed anObject: can be a Function. anObject can be one of the supported inputs (see above) [only if the used synthdef (applies also to patterns) has the right number of channels and an out argument. index: where the object should be placed in the internal order. any valid UGen input 813 . extraArgs) set the source by index. release old one. add it to the present ones removeAt(index) remove the synth at index i and its player definition removeLast remove the last synth and its player definition put(index. anObject. if you supply a gate. channelOffset. mapped to this bus AbstractPlayer Instr converted to player and started Associations: (\filter -> func) filter previous input set controls (\set -> event pattern) setting the source: source_(anObject) play a new synth through me. if -1. extraArgs) play a new synth. no output assigned played like Task started in a separate bus.Where: Help→JITLib→Nodeproxy→NodeProxy Pattern Stream nil Pdef Task Tdef played as event pattern played as event stream removes all objects played like a stream played. add(anObject. channelOffset.

if present. list.... when the objects numChannels is smaller than the proxy extraArgs: extra arguments that can be sent with the object directly (not cached) put can be used as array indexing: a[0] = { SinOsc. are mapped (mapn) note that you should not map to more channels than the control has.3] = . setn. only the order of indices is relevant. unmap map(key(s).. proxy.) set ranges of controls run(flag) 814 . subsequent channels of the control.ar } one can put an object at any index.. or a[[0. . if the index equals an existing index...... setn(key. 4.] pause pause all objects and set proxy to paused resume if paused. . . .. . val. ) map the arguments in keys to the subsequent channels of a control proxy (keys can be a symbol or a number) if the proxy has multiple channels. start all objects group-like behaviour: set(key. the object at this index is replaced. using multiple index expands into multiple objects: a[0.) I behave like my nodeMap: see [NodeMap] set. channelOffset: using a multichannel setup it can be useful to set this..... 6]] = [ .Where: Help→JITLib→Nodeproxy→NodeProxy a pattern can be used if it returns an EventStream. unset.

dur) gate my bus to the level value for dur time // do not work properly yet ! lineAt(key. dur) set control value to the new value in dur time exponentially 815 .Where: Help→JITLib→Nodeproxy→NodeProxy pause/unpause all synths in the group extended group-like behaviour: xset(key. . numerical) for synthDef arg rate of nil removes setting bus-like behaviour: line(value.. value. value. dur) set my bus to the new value in dur time linearly xline(value.. dur) set my bus to the new value in dur time exponentially gate(value.) set the default rate (\tr.. use: lag(\key1. key2..) set with crossfade into new setting xmap(keys. nil..) set the lag values of these args (identical to setRates) to remove these settings. \ir. . . val. val. proxy) map with crossfade into new setting xsetn() untested lag(key.. rate1..) setRates(key. nil. . dur) set the control value to the new value in dur time linearly xlineAt(key..

freeLast) send all synths without releasing the old one. you can wake it up to force it playing.Where: Help→JITLib→Nodeproxy→NodeProxy gateAt(key. send(argList. value. normally this is not needed. index. stay at the new value sending synths to server (normally the source_() message does the sending already. if the control was not set before. freeLast: if to free the last synth at that index if index is nil. but it can be used for spawning) wakeUp until the proxy is not used by any output ( either . dur) gate my control to the level value for dur time.ar/.kr ) it is not running on the server. the argument list is applied to the synth only. the argument list is applied to all synths. freeLast) send a new synth without releasing the old one.play or . sends all sendAll(argList. freeLast: if to free present synths release and cleaning up: free(fadeTime) release all my running synths and the group fadeTime: decay time for this action release(fadeTime) release running synths fadeTime: decay time for this action 816 .

local.Where: Help→JITLib→Nodeproxy→NodeProxy clear(fadeTime) reset everything to nil. then clear.boot. neutralizes rate/numChannels if a fadeTime is given. s. headerFormat. first fade out. sampleFormat) record output to file (returns a [RecNodeProxy] that you can use for control) returns a [RecNodeProxy] *defaultNumAudio_(n) set the default channel number for audio busses *defaultNumControl_(n) set the default channel number for control busses _________________________________________________________ for more examples see [ProxySpace] // examples s = Server. setting properties: fadeTime_(time) set the attack/release time clock_(aClock) use a tempo clock for scheduling beat accurate misc: record(path. 817 .

// adding nodes a.audio(s. 400.source = { SinOsc.ar([350. 0.ar(a.3) * SinOsc. 104]. 0. 0.source = { SinOsc.ar([0. 0. 286] * 1.1) }.add({ SinOsc.6) + 200. 0. 0. 600]. // removes any object // feedback a.ar * 7000 * LFNoise1. Out. 818 . // exeeding channels wrap: a.2) }.source = { WhiteNoise. 2). 3).kr(3.source = \default.numChannels. // synthDef on server a. a. 600).1) }.2. a.play.1) }). 0. 0.source = { SinOsc.1) }.2) }.0.ar([390. 0. 0. a. a[1] = { LFPulse.2)) }). 0. 0.SinOsc. 0. { arg out=0.source = { SinOsc. a. 300] * 1.25.source = { SinOsc. 0. 0.ar * 6000 * MouseX.source = nil.6) + 200. a.fadeTime = 2.source = { SinOsc. a.kr(1.2) }. 0. // play to hardware output. 420.01]) }.ar(out.3].source = SynthDef("w".ar([390.ar([50. 0. 0. 2) + [100. a.01.kr(1.add({ BrownNoise.Where: Help→JITLib→Nodeproxy→NodeProxy using node proxy with ugen functions a = NodeProxy. 0.ar([Rand(430.source = 0. 286] * ExpRand(1. 351.ar( 700 * LFNoise1.ar([390.2. 0. 0.0.02]) }). 0.02.1) }.0.ar(500.3.ar(a.ar([0.2) }. // the proxy has two channels now: a. a. 0. // other inputs a. // fadeTime a. 0. 0. 286.kr(0. return a group with synths // setting the source a. 390]*1.3. // setting nodes at indices: a[0] = { SinOsc.postln.

rrand(1500.58. 0.kr(0.source = { arg f=400.fadeTime = 1.1). 0.05. c). // the objects are built again internally and sent to the server. // map multiple channels of one proxy to multiple controls of another // recently changed behaviour! 819 .1) }. 0.set(\f.kr(20 * [1.source = { Line. a.2] * 0.5.01.1. SinOsc. 40. // setting controls a.set(\f. in * MouseY. 0.source = { arg f=400. a[0] = { arg f=400. in * SinOsc.20] * 0.2]. a[8] = \filter -> { arg in.9. 1) * 4 + 360.1) }. 700) }. 0. a.ar(f * [1.set(\f.5).map(\f. f * 0.0.16] * 0.kr([10. a[4] = \filter -> { arg in.ar(f % MouseX. RLPF. a.ar(Pulse. a. 0. LFPar. a[2] = \filter -> { arg in. a. c. 0. 0. a.1. 1500. // mapping controls to other node proxies c = NodeProxy.source = { SinOsc.1000)) }. // filtering: the first argument is the previous bus content.set(\f.1. 0.0. 0.2) }.1. a[1] = { arg f. 300)). more args can be used as usual.ar(Rand(100. a[3] = { SinOsc.lag(\f.2) }. rrand(1500. a. rrand(900. 10) + SinOsc. 0.ar([1. f * 0. // control lags a. 0. c. a.5)).fadeTime = 2.control(s.kr(3. 700)). 0. c. a[3] = \filter -> { arg in.1) }. rrand(1500. a.2).ar(Pulse. 0.lag(\f.kr(300. in * MouseX. 0.25] * 840. 0. 1.58.2] * rrand(0.2). 1300) }.kr([10.1. 0.02] * 0. nil). 0.kr(0.ar(f * [1.max(0) }.ar(600.Where: Help→JITLib→Nodeproxy→NodeProxy a[2] = { LFPulse.xset(\f.source = { SinOsc. 700)). 0.5.ar(f * [1. a. 150. RHPF. in * SinOsc.2) }. 2).kr(1. 700)).02.05.1) }.3) * SinOsc.ar(ExpRand(1. 700)). 50.1) }. rrand(1500. 100) }.5.fadeTime = 0. // crossfaded setting a.

Formant. 0.gate(1000. 100. [\f]). 0. // linear interpolation to new map: a. LPF. n = a. f[1]) }. c. 0.source = { arg f=#[400.1). n.2. 400]. 1. 300. [100. [100.copy. a.source = { LFNoise0.unmap(\f).lineAt(\f. 2). a. c.source = 400. 700]. 0. c).3. // restore mapping experimental // sending envelopes (up to 8 levels) w = Env. 700].nodeMap. c.nodeMap. // changing nodeMaps a. 820 . 1.0]. 700]) }.ar(Pulse.source = { arg f=#[400. 1000). 600. 400].kr([2.copy. [300.ar(f[0] * [0. a. c.env(w). f[1] * 3) }. a.ar(Pulse. -4).0]. a.5.rand(2. 400].kr([2.0. 0. 1600. 0. 1).Where: Help→JITLib→Nodeproxy→NodeProxy a.ar(140.5.fadeTime = 1.001). n = a. 400).source = { SinOsc.4.3).1) }. [300. 0.set(\f.kr([Line. [100. n. 0.1). a.fadeTime = 5. LPF.ar(f.fadeToMap(n).new(Array.map(\f. // behave like a sc2 plug c. c).fadeToMap(n.1]. 700). 1]. 1700]) }. 0. 400.2).source = { arg f=#[400. c. 0.gate(1400. // multichannel proxy c is mapped to multichannel control of a a.map(\f. 30.kr(1. c. 10). c.2).3.Array.xlineAt(\f. 0.line(1000.set(\f.3).3. 0. 1700]) }.source = { SinOsc. a. [300. 700].gateAt(\f. c. f * 1.rand(3. 0. // direct access a.source = 400. c.2.

0.3).5.1). c. a.2). 5000.ar(Impulse.3).5.5. 5]/2.rand(8. 0.3).ar(Impulse.removeLast. 0. a. 0.end. 420) }. a[2] = { Ringz.play.ar(5.play.0).ar(Dust. 0.ar(Impulse.1). 0. a.env(w).01) }.put(1. // start the monitor a.1). // round to every 2.audio(s. // stop synthesis. 420) }. 1). c.ar(Impulse.free.put(1. // release the synths and stop the monitor c.05) }. 0.01) }. 3000. // stop the monitor a.play. 0.audio(s.2). 0. a. 1]. 821 .ar([1.kr(0.0 seconds a. a[1] = { Ringz.1)). 1000.stop.Array.ar(Impulse. 0.end.ar(Impulse. 0. a[3] = { Ringz.rand(7. 8000. a. 0. 0.new(Array. 0. 0.ar([3. 0. 0. 0. a. 0. 720) }.env(w).01) * LFPulse. { Ringz. then wake up proxies: a.source = { Ringz. a[0] = { Ringz.Where: Help→JITLib→Nodeproxy→NodeProxy c.ar(5.1]*15.3).ar([3. beat accurate playing a = NodeProxy.removeAt(2). 1000).put(0. a.ar([0.03. w = Env.permanent_(true). a.3.ar(Impulse. a. 0.clock = TempoClock(2. { Ringz. 0. 1). 400.01) }. { Ringz.3. 0. 5]*16.1). 0.ar(0.ar(5. 1).3. // free the control proxy c channel offset/object index a = NodeProxy.env(w). 1260) }.

source = b.audio(s.ar([2.asr(0. gate.2. \ffreq. var env.source = { b. Pan2. 300.store. gate=1. using patterns . amp=0. // filter the input of the pattern b. 300. // play b out through a: a.ar(out. add: }.Where: Help→JITLib→Nodeproxy→NodeProxy a. 0. 500. 8].fadeTime = 2. ffreq.ar(freq. ) a.5) }. amp. ) ( s.1. \who. Rand(-1. // monitor output // play the pattern silently in b b. // filter the input of the pattern 822 . a. out=0.kr(0. doneAction:2)). b = NodeProxy. // filter b with ring modulation: a. \freq.5).clear.event streams ( // must have ’out’ or ’i_out’ argument to work properly SynthDef("who". \legato. 330)) -0. ffreq=800.0.ar(SinOsc.fadeTime = 3. { arg freq.ar * SinOsc.02).0)) ) }).audio(s. 2). 0. 700.source = { a. Out. 1. env = Env.ar( Formant. a = NodeProxy. b.boot.2).source = Pbind(\instrument.kr(env.ar * LFCub. EnvGen.play.01.

0. Pseq([c. 1500) }.75. \legato. \who.2. \freq. 350. 620.kr(2. inf) ). b[4] = Pbind(\instrument. \freq.) // embedding in other patterns it will still return itself. c. \ffreq.2]. \legato.0. \who.05) }. 800]. inf). 0. Resonz.01). 1).1. 0.2.ar([0.Where: Help→JITLib→Nodeproxy→NodeProxy a. Pseq([720.1. b[3] = Pbind(\instrument. ) b[2] = Pbind(\instrument. \who. // map b to another proxy c = NodeProxy. 10). \ffreq. \freq.1. b.25] * 0. 400.fadeTime_(1).1]).source = { SinOsc. \freq. 0.inf). 700) }. 5500. Pseq([0. 0. \ffreq.5. \dur. 0. 0. \legato. 0. c. 10. Pseq([1. 0. \freq.1. 700) }.source = Pbind(\instrument.source = b. 0.inf). 823 . 0. 5000. 100. \who.kr(5. 0. \legato. 0. \who.01. ( b. c. \midinote.source = { MouseX. \amp. \dur. ffreq.1). Pseq([700. 300.source = { SinOsc. 400]. 200).1. 0. Pseq([600. 100.1. 0. // now one can simply embed a control node proxy into an event pattern. b[1] = { WhiteNoise.control(s. // use proxy in a pattern \dur. c.02).kr(SinOsc.source = Pbind( \instrument.2.kr(100. 1) }. \ffreq.ar([1. \amp. 0. 600]. 0. // (this works not for \degree. 0. \ffreq. b[4] = { arg ffreq=800. \legato. 400.4.1.c]. 300]. etc. Prand([500. 1300. c.inf). 0.inf).01]) }. inf). c.ar(WhiteNoise. 500.kr(0.source = { LFNoise1.

kr(1900.source = { a. a. }. 10) }.clear.ar * WhiteNoise. b. 1) }. 0.ar * WhiteNoise. // clear all. 10.map(\ffreq.1. free bus 824 . a. 50.removeLast.Where: Help→JITLib→Nodeproxy→NodeProxy b.ar(SinOsc.clear. c.kr(0.1.ar(0. 330))) c. b.source = { XLine. b.removeLast.ar(0. // map the control to the proxy b.clear. c).01.source = { b. 1) + (b.ar * SinOsc.

a[5] = \five.selectInPlace({ arg item.collectInPlace({ arg item. a[4] = \four. a[0] = \z. a. 700 + i }). a[0] = \z. do is faster. a. 825 .asString[0] === $f }). a.Where: Help→JITLib→Nodeproxy→Order ID: 250 Order an order of elements with an integer index superclass: SequenceableCollection keeps elements in an order. a[0] = \y. the following messages change the content of the collection without returning a new one. a[4] = \four. put and at are slower than IdentityDictionary/PriorityQueue. apart from this they work like collect/reject/select collectInPlace(func) selectInPlace(func) rejectInPlace(func) //example a = Order.new. inherits all methods from superclass. item. i.indices. a[5] = \five.

826 .indices.rejectInPlace({ arg item. a[9] = 100. a. item.isNumber.indices.Where: Help→JITLib→Nodeproxy→Order a.not }). a.

/* 827 . rates. if set to true (default: false) for inner workings see [jitlib_fading] // example a = ProxySynthDef("xtest". it wraps *sampleAccurate_ use OfsetOut.1 }). a.new todo: add variants. channelOffset=0. x. x = Synth("xtest"). func.ar(400) * 0. func.Where: Help→JITLib→Nodeproxy→ProxySynthDef ID: 251 ProxySynthDef superclass: SynthDef synth def that wraps ugen graph *new(name. makeFadeEnv if true it constructs a fader envelope and adds controls for gate and fadeTime channelOffset a constant offset that is added to the out number chanConstraint max numChannels for the synthdef.release. If ugenfunc returns a larger array. prependArgs: like in SynthDef. prependArgs. rates. makeFadeEnv. chanConstraint) name. { SinOsc.send(s).

it behaves according to the rate: audio rate signals are wrapped around a smaller channel size. control rate signals are not (the exceeding channels are left out) */ 828 .Where: Help→JITLib→Nodeproxy→ProxySynthDef if the resulting number of channels is larger than a given channelConstraint.

kr ) it is not running on the server.play or . 829 . numChannels) see superclass *newFrom(inproxy.ar/.Where: Help→JITLib→Nodeproxy→RecNodeProxy ID: 252 RecNodeProxy superclass: NodeProxy a node proxy that can record instance creation: *new(server) / *audio(server. numChannels) instantiate a new proxy that listens to the in proxy. access: open(path. sampleformat) open new file and initialize buffer on server record(paused) start the recording synth. you can wake it up to force it playing. headerformat. if paused is false start recording immediately default: true close stop recording. close file pause/unpause pause recording / unpause recording isRecording see if recording right now wakeUp until the proxy is not used by any output ( either .

1) }.510]. 100.play. 0.aif").stop.ar([LFNoise1. //monitor off a. a. a. 0. recording from some bus a = Bus.500].index.700].source = { SinOsc.open("xproxySpace.boot. 0. 300).stop.source = { SinOsc. a.source = { SinOsc.ar(a.audio(s. 0. Out. 0.ar([400.500].source = { InFeedback. 2). a.local.ar(0.ar(out.Where: Help→JITLib→Nodeproxy→RecNodeProxy ___________________________________________________ examples s = Server. a. { arg out.dup(2)) }).kr(80. { WhiteNoise. 0.audio(s.1) }.index]). s. SynthDef("test". n.close.source = { SinOsc. 2).ar([410. a. x = Synth("test".//monitor n. 0. a. n = RecNodeProxy.play.send(s).record(false).//turn off monitor 830 .1) }. 0.1) }. n.1) }. [\out.ar([400. 2) }. //stop recording and close file a. a = RecNodeProxy. 2). a.audio(s. //monitor.

open("recproxy514. b.ar(0. 100.unpause.01) }. instance creation from an existent node proxy b = NodeProxy.close. n.source = { SinOsc. //start recorder (paused) r.1) }. 0. r.aif").record.500]. r.1) }. //stop recording and close file r. n. //play something r = RecNodeProxy. 0. r. //listen to b b.record. 2). //stop listen to b instance creation from an existent node proxy II b = NodeProxy.audio(s.play. b. 0.ar([LFNoise1.ar([430.1) }.500]. 2). 500].1) }.close.open("noise.ar([400.aif").Where: Help→JITLib→Nodeproxy→RecNodeProxy n. 0. b. //open file r.source = { WhiteNoise.unpause.pause. 0. 831 .kr(80. 0.stop. //start recording b.source = { SinOsc. 300).source = { SinOsc.ar([410.510]. b.audio(s. r. 0. b.newFrom(b). 0.source = { SinOsc.pause. n.unpause.

sendMsg("/n_set". 0. a.unpause. //start recording r.audio(s.close.0. ) //stop recording and close file 832 . //stop listen recording from other sources s = Server. \out.sendMsg("/s_new". s.2. \gate.open("xproxySpace. \freq. ( Routine({ var id.play. a. a = RecNodeProxy.aiff"). s. }) }).local. //get the bus index. a. loop({ id = s. close file b.source = { SinOsc.stop. s. b = a. 800)). //end recording. 2).wait. 0.aif").0.2. //listen to b b. 0. id. 0). //play something r = b.500]. rrand(400.ar([400. a.play.record("recproxy101.unpause. id. "default".boot. //start recorder (paused) r. b.1) }. 0. //monitor.wait.index.play.record.Where: Help→JITLib→Nodeproxy→RecNodeProxy b.nextNodeID.

stop.close. 833 .Where: Help→JITLib→Nodeproxy→RecNodeProxy a. //monitor off a.

6 Patterns 834 .12.

0 beat duration source_(obj) set the source (a pattern). (default: 1. if none is given.) is equivalent) quant_(beats) set the quantization value. If a quantization is given. offset. the default is a Pbind with resting notes of 1. the pattern should be an event pattern (see Pdef) (*new is implemented for Pdef to avoid a dispatch) *default a default source..Where: Help→JITLib→Patterns→EventPatternProxy ID: 253 EventPatternProxy superclass: TaskProxy event stream reference keeps a reference to a stream that can be replaced while playing. schedule this change to the next beat (pattern_(.0) fadeTime_(beats) 835 . Multiple streams are thus handled without creating dependancies. outset] quant get the quantization value *defaultQuant_(beats) set the default quantization value for the class. related: [Pdef] *basicNew(source) create a new instance with a pattern (the source). can be an array [quant.

embedInStream(inval) just like any pattern. quant) starts the EventPatternProxy and creates a player. quant) quant can be an array of [quant.playOnce(clock. it is created and the pattern is rebuilt. val2. This is similar to NodeProxy-nodeMap. protoEvent. use . protoEvent. if you want to play multiple instances. .Where: Help→JITLib→Patterns→EventPatternProxy when the synthdefs that are used contain an \amp control. which updates its stream as soon as the pattern is changed. phase] stop stops the player player 836 . set(key.. a) using as stream reference asStream returns an instance of RefStream. key2. val. If there is none. the pattern is rebuilt.) set arguments in the default event. When set for the first time.. the patterns are replaced by crossfading the previous with the new over this time (in beats) envir_(event) provide a default event for the Pdef. embeds itself in stream b) using as EventStreamPlayer play(clock. It is used to filter the incoming stream before it is passed to the source pattern.

m. m = {EventPatternProxy. 0. u=1.basicNew} ! 4.25. doneAction:2). u = SinOsc. 0. 2]. sustain).perc(0. 3])).Where: Help→JITLib→Patterns→EventPatternProxy the current player (if the Pdef is simply used in other streams this is nil) pause / resume / reset / mute / unmute perform player method isPlaying returns true if Pdef is running. \dur.do { var d. c]. it will schedule a stream for playing as soon as a new one is assigned to it. if a Pdef is playing and its stream ends. amp * env). 7. ) s.source = Pbind(\instrument. 8.ar(d * 300. x = Pseq([a.2) * d.ar(u + 1 * freq. 1). var env.store. m. Pseq(#[0. freq.125. \dur. \Pdefhelp.25. Pan2.1. \legato.ar(out.play. 1) }. 8])).play.ar(SinOsc. Out. inf). 4. amp=1. \Pdefhelp. pan)). Pseq(#[7. 0. 16. b. \degree. u. \dur.kr(Env. \dur. Pseq(#[0.source = Pbind(\instrument. c. #a. \Pdefhelp. rrand(0. \degree. 5.source = Pbind(\instrument. 1. }). pan.03. \Pdefhelp. env = EnvGen.boot. 0. b. 837 . \degree. 1. 0.01.source = Pbind(\instrument.1. 5. 2)).1). \degree. c. a. d = exprand(0. 1. { arg out. b. a) embedding EventPatternProxy in streams: ( SynthDef("Pdefhelp". sustain=1.

Pseq([0. 2. \degree. inf). Pseq(#[0. 3. Pshuf(#[0. Pseq(#[7. 0. \Pdefhelp. 0. 0. \Pdefhelp. 1)).source = Pbind(\instrument. // infinite loops are scheduled (to ths clock’s next beat by default) and released: a. \degree. 3]. 4.source = Pbind(\instrument. 1)).source = Pbind(\instrument. \dur. 5. 1. inf)). a. Pseq(#[0. Pstutter(8. \degree. 0. inf)). 0. 0. \dur. \degree. 3] + 1. ) a. \dur.125. // EventPatternProxy can be used in multiple patterns ( x = Ppar([ Pbindf(Pn(a. 5] . 0. \Pdefhelp. 0. Pseq(#[4. Pseq([0.stop. 5. m. 3.inf)) ). 4. \Pdefhelp.1.source = Pbind(\instrument. 2]*3)).25. Pseq(#[0. Pbindf(Pn(a. 838 . a. \gtranspose. \gtranspose. Pseq(#[0. \degree. a. \degree.stop. \degree. 5.source = Pbind(\instrument. 4. \dur. 0. \dur.inf)). a. 0. 4. 2. 1)). \Pdefhelp.Where: Help→JITLib→Patterns→EventPatternProxy c.125.1. \dur. \Pdefhelp. inf).25. \dur. \Pdefhelp.2. 0.753. a. inf)).6 ). 4]. 1) ) ]).source = Pbind(\instrument. 2]. Pseq(#[0. 2]. inf). inf)).2)]. 5. 1. 5. 2].1. 2]. 3] . 3]. 0. Prand([6. \dur. Pstutter(8. \dur.source = Pbind(\instrument. \Pdefhelp. 3. \Pdefhelp. Pbindf(Pn(a. Pseq(#[0. 4.753.source = Pbind(\instrument. a. Pseq(#[0. \dur. 8b].2. \degree. 4. \degree. \degree.source = Pbind(\instrument. 0. 1. 3. x. 4. inf)).play. 3.

1. b) playing EventPatternProxy ( // load a synthdef s. A silent resting pattern is used. dur). amp=0. ) #x. y. var env. 0.25.source = Pbind(\dur.set(\detune. \gpdef).ar(freq. \degree. 4. 4. \instrument.perc(0. x. // set environment a.05. a.1. Out. \degree. Pseq([3. \instrument. inf). SynthDef("gpdef". 5b.source = Pbind(\dur. // assign various patterns to it: x. x. \instrument. env = EnvGen. \gpdef). 6]. Pseq([3. \degree. \degree. \gpdef).01.1.source = Pbind(\dur. Pseq([3. inf). \gpdef)). 5b]-2. 2.25. 6]-1. \instrument. inf). Pseq(#[0.kr(Env. \gpdef). 5]. 0. \degree.source = Pbind(\dur. 3. inf). 0.25. -50). \Pdefhelp.boot.play. 0. dur=0.ar(out. 4. y = {EventPatternProxy. 2b. env)) }). Pseq([3. SinOsc. 0.basicNew} ! 2.Where: Help→JITLib→Patterns→EventPatternProxy a. 6]+1. 0). 1b. 0. // play them. doneAction:2) * amp.source = Pbind(\instrument. \instrument. y.set(\detune.source = Pbind(\dur. 4. inf)). 4.25. freq=440.stop. x. 4b. 839 .store. x. 0. 5b.25. \dur. y. 5b. { arg out=0.play.

y. 0. 5. 4. \instrument. 5. 6]-2). Pseq([3. \gpdef). \gpdef ) ). ( x.35.4]. [7. 3]-3). // drop in ending patterns x. 5b. \degree.125.source = Pbind(\dur. \instrument. 4. inf).stop. 10].25. \degree. x. \instrument.fadeTime = nil. 0.rand. Prand([8. 0. 4]-3).source = Pbind(\dur. 4. 2. 0. x.source = Pbind( \dur.source = Pbind( \dur.0. \instrument. \degree. \gpdef). \degree. 4. \gpdef). 9.1). 2. \degree. 5. // tempo change TempoClock. 5. 10]. \instrument.tempo = 1. [7.25. 6]-2). 4. \degree. 1 / 6. \instrument. \instrument. Pseq([3.play. 0. 5.3. y. Pseq([3. [7. 0.source = Pbind(\dur.default. \gpdef).Where: Help→JITLib→Patterns→EventPatternProxy // using fadeTime: y. 6]+4.1) .25. Pseq([3. 0. 840 . Pseq([3. 6]. inf). 3. inf). x. [7. ) ( x.4]. \degree. x.125. \instrument.fadeTime = 8. \degree. \gpdef).25. Pseq([3. 9.source = Pbind(\dur. Pshuf([3. 5b. 3. Pseq([3.source = Pbind(\dur.5.25. \gpdef). 6]+1. Pseq([3. 6]+1.source = Pbind(\dur. 0. inf). inf). y. Prand([8.source = Pbind(\dur. 6]-2.4]. 4. \gpdef). \instrument. x. \gpdef) ). \degree. ) x.4].

tempo = 1.Where: Help→JITLib→Patterns→EventPatternProxy TempoClock.stop.0. y.default. x. 841 .stop.

if none is given. schedule this change to the next beat quant_ set the quantization value quant get the quantization value *defaultQuant_ set the default quantization value for the class.Where: Help→JITLib→Patterns→PatternProxy ID: 254 PatternProxy superclass: Pattern stream reference keeps a reference to a stream that can be replaced while playing.0 in order to make it safe for durations) source_(obj) set the source. If a quantization is given. the default is 1. see: EventPatternProxy instead of a pattern. Multiple streams are thus handled without creating dependancies. (default: nil) condition_(func) provide a condition under which the pattern is switched when a new one is inserted. the stream value and a count is passed into the function 842 .0 (it is not 0. *default a default source. creating a routine. a function can be passed in. related: [Pdefn] *basicNew(source) create a new instance with a pattern (the source). the pattern should be a value pattern (see Pdefn) (*new is implemented for Pdefn to avoid a dispatch) for event pattern proxy.

embeds itself in stream PatternProxy implements some methods for the benefits of its subclasses Pdefn/Pdef/Tdef which are not useful for PatternProxy. 843 .) set arguments in the environment. 77].stop. 0. val2.postln. val.Where: Help→JITLib→Patterns→PatternProxy the methods count_(n) simply counts up to n and switches the pattern then reset switch the pattern immediately. This allows to create streams that idle on until a new pattern is inserted. replacing nil with a default value (1).asStream.. envir_(event) provide a default environment for the proxy.1). When set for the first time.basicNew(Pseq([1. the routine pattern is rebuilt. x = Pseq([0. set(key. endless returns a Proutine that plays the proxy endlessly. 66.play. (stuck conditions can be subverted by this) embedInStream(inval) just like any pattern.3. . t = Task({ loop({ x. 66. 2. EventStreamProxy and TaskProxy. a. it is created and the pattern is rebuilt.. 0. inf).source = Pseq([55. If there is none.source = Pseq([55. // example a = PatternProxy.inf). If given. key2. a. 3]. a]. t. it is used as an environment for the routine function.inf)).next. 77].wait }) }).

quant = 4. 3.03. Pan2. u.store.do { var d. pan)).boot. 5. x. 1). amp * env). x).inf).2) * d.1. env = EnvGen.ar(d * 300. 2. [1s.ar(out.ar(SinOsc.inf). \dur. x.inf). like Pdefn can be accessed in multiple streams ( SynthDef("Pdefhelp". sustain=1. var env. x. 7.inf).kr(Env.Where: Help→JITLib→Patterns→PatternProxy // PatternProxy.source = Pn(Pshuf([0. Ppar([ Pbind(\degree. Pset(\instrument. u = SinOsc. 3. x. // if quant is set. the update is done at the next beat or whatever is specified: x.source = Prand([0. 1. sustain). 4]]. 1/3) ]) ).source = Pseq([0. Out.play. rrand(0. ) ( x = PatternProxy.2). 2].1. 3. { arg out. doneAction:2).01. 6]. 1. d = exprand(0. pan. s.ar(u + 1 * freq. 1) }. freq. Pbind(\degree.basicNew. 0. }).quant = nil. \Pdefhelp. amp=1.perc(0. x. ) x. // reactivate immediacy ( 844 . 8).source = Pn(Pseries(0. u=1.

3. 845 .choose. 11].yield.yield. 3.choose.choose.source = Prout { loop { 4. #[6.do { | j| } } }) ) (i % j).Where: Help→JITLib→Patterns→PatternProxy x.do { | i| #[2. #[5.yield }. 4]. 4]. 0.

*new(key) acess the pattern at that key (if none is there.Where: Help→JITLib→Patterns→Pbindef ID: 255 Pbindef incremental event pattern reference definition superclass: Pdef keeps a reference to a Pbind in which single keys can be replaced. a default pattern is created) see Pdef // example: ( SynthDef(#5f5f5f"Pdefhelp". freq. If there is already a Pbindef there. It plays on when the old stream ended and a new stream is set and schedules the changes to the beat. the difference to Pdef is that it allows to incrementally change the the elementary patterns (patternpairs) of a Pbind .also of an already existing Pbind in a Pdef. { arg out. . just like in PbindProxy. replace its pattern with the new one.. paramKey1. pattern1. or add a new one (the whole pattern is replaced). sustain=1.. 846 . amp=1. u=1. *new(key. if there is already a Pdef there. pan. set the parameters only. var env. ) store the pattern in the global dictionary of Pdef under key.

#007200\degree. 5. 5. 3. 5. \Pdefhelp. sustain). #007200\degree. Pbindef(#007200\a. // does not resume now Pbindef(#007200\a).ar(u + 1 * freq. }). #007200\degree.1.1. 1b]. Pbindef(#007200\a. 4.ar(d * 300. doneAction:2). Out. Pbindef(#007200\a. 2. 5. 4.01. #007200Pbindef(\a. Pbindef(#007200\a. rrand(0. Pdef(#007200\a)]).do { var d. 6]. // play single instance Pseq([Pbindef(#007200\a). u = SinOsc. 3. 0. \instrument. 1). Pseq([0.kr(Env. Pdef(#007200\x). 3. ) s.0. 2. 4. inf)). 0. #007200\dur.1). 2. u. 1)). Pseq([1. 0. 2.02). Pseq([1. Pseq([1. Pbindef(#007200\a. #007200\mtranspose. 5. #007200\degree. 2]. Pseq([1.quant = 0. // an already existing Pdef can be incrementally changed #007200Pdef(\x. 5b. #007200\degree. 0. #007200\legato. Pbind(\instrument. 6]. 5.3)).ar(SinOsc. 6]. nil). 4. 6]. 1b. amp * env). 0.0. 3. 0. 3. 6]. 1) }.2) * d.play. Pbindef(#007200\a. 3. \Pdefhelp). 5. \dur.01. #007200\dur. // apart from this Pbindef behaves like Pdef: Pbindef(#007200\a). Pseq([1b. Pbindef(#007200\a.ar(out. 4. 3). inf)).playOnce. #007200\mtranspose.1). 5.stop. #007200\degree.play. Pbindef(#007200\a. #007200\degree.store. Prand([1. 2.perc(0. #007200\dur. 1. inf). Pbindef(#007200\a). 6. 3). 847 . 1)). 1)). Pbindef(#007200\a.play.2].Where: Help→JITLib→Patterns→Pbindef env = EnvGen. Pan2. 2. // same here (Pdef(\a) is the same pattern as Pbindef)) Pbindef(#007200\a) === Pdef(#007200\a) // identical. 0. 3. -3). 2. d = exprand(0.4.boot. 2. pan)). 0. // remove key Pbindef(#007200\a. Pseq([1.

rand). 848 . 3. 7. inf). #007200\degree. 2). 7. 4]. #007200Pbindef(\x.Where: Help→JITLib→Patterns→Pbindef Pbindef(#007200\x. Pbindef(#007200\x. #007200\degree. -0.2. Pn(Pseries(0.02. \stretch. 7. 10))). Pseq([0. #007200\dur.

at(#007200\freq). x. at(key) return a pattern at that key. so different elementary patterns can be quantized differently. pattern2.. ) create a new instance of PbindProxy with the given patternpairs source returns the wrapper for the Pbind set(key1. quant_(val) set the quant of all elementary patterns quant 849 . this can be used to set quant value individually. ) set the given patternpairs. pattern1. It plays on when the old stream ended and a new stream is set and schedules the changes to the beat.. pattern1. . key2.. . related [Pbindef][Pdef] *new(key1..Where: Help→JITLib→Patterns→PbindProxy ID: 256 PbindProxy superclass: Pattern incremental event pattern reference keeps a reference to a Pbind in which single keys can be replaced. key2. pattern2.quant = 2.

pan. Pseq([1. inf)). 0.set(#007200\degree.play.1. Pseq([1. pan)).02).play. 1) }. x.ar(d * 300. Pseq([1b. Prand([1. freq. inf)). ) s. u=1.1).play. x. 0. 5. x. u. 5.set(\instrument. 2. x.ar(SinOsc. #007200\mtranspose. 5. \Pdefhelp). 5. 3). 5. 3. 5b.boot. 1. 6. 1b. Pseq([0.set(#007200\legato. x. x. { arg out. var env. inf). 2]. d = exprand(0.set(#007200\degree. amp=1. x. Pan2. x. #007200x. x. 0. -3). // embed in other patterns: ( 850 . 4. sustain=1. sustain). 0. amp * env).ar(out.1. #007200\dur. #007200\dur. 3. 6]. 1)). x = PbindProxy.ar(u + 1 * freq.set( #007200\degree. Out. }).kr(Env.new.perc(0.set(#007200\degree. doneAction:2).set(#007200\degree. 2.0.01. Pseq([1.1). 0.4. 4.do { var d. u = SinOsc. // remove key x. 1). env = EnvGen.store. nil). x. 6]. 0. x. 3). 2. 3. 4. 3. 1b]. 3.Where: Help→JITLib→Patterns→PbindProxy return the quant value of the source pattern // example: ( SynthDef(#5f5f5f"Pdefhelp".2].set(#007200\mtranspose.2) * d. rrand(0. 2.play.03.set(#007200\dur. 2. 0. 2. 5. 6].

#007200\dur. 2. Pseq([1b. Ppar([ x. #007200Pbindf(x.4). 1b. 0]. 3. 5. 5.play. inf)). 4) ]). 3. 0.set(#007200\degree. 4. ) x. 1b. 0.set(#007200\degree. 851 . 0. \ctranspose.Where: Help→JITLib→Patterns→PbindProxy x. 5. inf). 2]. 6. Pseq([1b.

just like its superclass. Changes in this global library have effect immediately. For value patterns (numerical. *new(key. if none is given. It plays on when the old stream ended and a new stream is set and schedules the changes to the beat. applying the arguments from the inevent. if the pattern is a function. Pdef creates a PlazyEnvir internally that dynamically creates the pattern returned from the function. or if quant/offset values are given.Where: Help→JITLib→Patterns→Pdef ID: 257 Pdef stream reference definition superclass: EventPatternProxy keeps a reference to a stream that can be replaced while playing. It can be used to store event Patterns globally. Pdef(key. like Tdef and Ndef. pat) stores the pattern and returns the instance. non event patterns) [Pdefn] is used. It is very similar to [EventPatternProxy]. due to their incopatibility with Pfindur. note that exchanging the source of a Pdef while playing does not work with Pmono and Pfx yet. replace its pattern with the new one. if there is already a Pdef there.0 beat duration 852 . *new(key) acess the pattern at that key (if none is there. pattern) store the pattern in a global dictionary under key. a default pattern is created) *default a default source. at the next time step. but handles the storing of global instances: Pdef(key) returns the instance. the default is a Pbind with resting notes of 1.

If there is none.0) can be an array [quant. the pattern is rebuilt. *all_(envir) set the global environment quant_(beats) set the quantisation time for beat accurate scheduling. . can be an array [quant. offset. offset. This is similar to NodeProxy-nodeMap. (stuck conditions can be subverted by this) fadeTime_(beats) when the synthdefs that are used contain an \amp control. the patterns are replaced by crossfading the previous with the new over this time (in beats) envir_(event) provide a default event for the Pdef. it is created and the pattern is rebuilt.Where: Help→JITLib→Patterns→Pdef *removeAll remove all streams *all environment (IdentityDictionary) that stores all Pdefs. outset] condition_(func) provide a condition under which the pattern is switched when a new one is inserted. When set for the first time. 853 . key2. val2. set(key.. the stream value and a count is passed into the function (see example) the methods count_(n) simply counts up to n and switches the pattern then reset switch the pattern immediately..) set arguments in the default event. val. It is used to filter the incoming stream before it is passed to the source pattern. outset] *defaultQuant_(beats) set the default quantisation for new instances (default: 1.

a) using it as stream reference embedInStream(inval) just like any pattern.) map Pdefn to the keys in the event. protoEvent. pdefKey.) is equivalent) endless returns a Proutine that plays the proxy endlessly. This allows to create streams that idle on until a new pattern is inserted. embeds itself in stream b) using it as EventStreamPlayer play(clock. pdefKey . phase] stop stops the player player the current player (if the Pdef is simply used in other streams this is nil) pause / resume / reset / mute / unmute 854 .. key.Where: Help→JITLib→Patterns→Pdef map(key. use .. pattern) (pattern_(. quant) starts the Pdef and creates a player. replacing nil with a default value (silent event). source_ set the pattern (internally done by *new(key. if you want to play multiple instances. quant) quant can be an array of [quant.playOnce(clock. protoEvent..

\dur. env = EnvGen. 8. 0.2) * d. d = exprand(0. ) s. Pdef(\metronom.1. 1. sustain).01. 0. Pseq(#[0.ar(SinOsc. Pdef(\c)].play. Pseq(#[0. 3]))).ar(out. { arg out. Pbind(\instrument. 5. amp * env). 2]. 1. 1). inf). u=1. freq. pan)). 0. u = SinOsc. 2))). }). 0. 7.do { var d. \degree. \Pdefhelp. \Pdefhelp. 3. \legato. 1. u.ar(d * 300.store. \dur. \Pdefhelp.Where: Help→JITLib→Patterns→Pdef perform player method isPlaying returns true if Pdef is running. \degree. doneAction:2).25. 16.1. x = Pseq([Pdef(\a). Pdef(\b). sustain=1.play. Pbind(\instrument. if a Pdef is playing and its stream ends. Pdef(\b. rrand(0.125. 4.perc(0.1)). amp=1. Pan2. \dur. Pdef(\a. Pdef(\c. it will schedule a stream for playing as soon as a new one is assigned to it. 855 .03. for another use of Pdef see also [recursive_phrasing] a) embedding Pdef into a stream: ( SynthDef("Pdefhelp".ar(u + 1 * freq. 1) }. Pbind(\instrument.kr(Env. \dur. Pbind(\instrument.boot. pan. 0. Out. Pseq(#[7. \degree. var env. \degree. \Pdefhelp.25. 8]))).

4. Pbind(\instrument.stop. inf))). 4.2. // infinite loops are scheduled (to ths clock’s next beat by default) and released: Pdef(\a. 4. \dur. 2]. 0. Pdef(\a. \Pdefhelp.753. Pdef(\a. Pseq(#[0. 3. Pbindf(Pn(Pdef(\a). inf))). \dur. 0. // Pdef can be used in multiple patterns: ( x = Ppar([ Pbindf(Pn(Pdef(\a).6 ). 4. inf))). Pbind(\instrument. Pdef(\a. 4]. Pbind(\instrument. Pdef(\a. Pbindf(Pn(Pdef(\a). \degree. 2]. \dur. 3] . 2]. \Pdefhelp.2. Pseq(#[0. \degree. 4.25. \Pdefhelp. 4]. Pbind(\instrument. Pstutter(8. 0. \degree. 3]. 856 .125. Pbind(\instrument. 3.4. Pbind(\instrument.1. \degree. \degree.inf)) ). Pbind(\instrument. inf))). \Pdefhelp. Pdef(\a. Pbind(\instrument. \degree.125. \degree. 1. 0. ) Pdef(\a. 0. 0. \degree. inf). Pseq([0. \Pdefhelp. 2]*3))). x. Pseq(#[7. Pdef(\metronom). 0. inf). \Pdefhelp. Pseq(#[0.1. 0. 2. inf). 0. 1. 1. \dur. \Pdefhelp. \degree. 0. 3. 3]. 1))). 1. 5. 5] . \dur. 5. Pseq(#[0. Pseq([0. inf))). 0. \Pdefhelp. 3. Pshuf(#[0. \gtranspose. 3. 2. \degree. Pbind(\instrument. Pseq(#[0. \dur. 8b]. 3] + 1. Pstutter(8. Pseq(#[0. \dur. \dur. Pdef(\a. \Pdefhelp. inf))). 5.2)].play. 1))). \Pdefhelp.inf)).25. \dur.stop. \degree. Prand([6. \dur. Pdef(\a. Pseq(#[4. 2]. 1))). Pbind(\instrument. 1) ) ]). 0. 5. Pseq([0. \dur.753. Pseq(#[0. 4. 4. \gtranspose. 5.Where: Help→JITLib→Patterns→Pdef Pdef(\c. 0.

stop. \degree. inf))). 8b]. Pbind(\instrument.1. the above changes are crossfaded Pdef(\a).2. \Pdefhelp.fadeTime = 2. // set environment Pdef(\a).2)]. 1.ar(freq.play. dur). 2. 4. Prand([6. SynthDef("gpdef". 0. Pseq(#[0.play. b) playing Pdef ( // load a synthdef s.05. { arg out=0. // . 4b. -50). doneAction:2) * amp. // play a second one (automatically instantiated) // assign various patterns to it: 857 . freq=440.ar(out. Pdef(\y). amp=0. // creates a Pdef with a default pattern.boot. var env.. env = EnvGen.perc(0. Pseq([0. 0. Pdef(\a.Where: Help→JITLib→Patterns→Pdef Pdef(\a.. dur=0. Pbind(\instrument. ) Pdef(\x). \Pdefhelp. Pdef(\a). x. // play it. 1b. inf))).set(\detune. \degree. 0.1.set(\detune. SinOsc. 5]. // using a fade time. 3. env)) }).01. \dur. Out. 0). A silent resting pattern is used. 4. Pdef(\x). 2b. \dur.store.kr(Env.

5. 0.1) . Pseq([3. 4.tempo = 1.125. 4. 6]-1. \instrument. 0.4]. inf). \gpdef)). \degree. 5b. Pseq([3. 5b. 6]. Pbind(\dur. Pdef(\y. Pbind(\dur. \gpdef)). 0. Pdef(\x. Pseq([3.25. ) ( Pdef(\x. Pseq([3. 4.25. inf). 4. 6]-2. Pbind(\dur. 4. Pseq([3. Pbind( \dur. \degree. Pbind( \dur. \instrument. Pdef(\x).4]. Prand([8. \gpdef) ). 9. Pdef(\y. \gpdef ) ). Pdef(\y. // drop in ending patterns Pdef(\x. Pbind(\dur. Prand([8. 0. Pbind(\dur. [7. Pseq([3. 10]. \degree. \gpdef)). 0. ( Pdef(\x. \degree. 0. 5b. Pseq([3. Pseq([3. Pdef(\y. 6]+1. 5. [7.125. 4. \degree. \gpdef)). 6]+4. Pdef(\x. 6]+1. \degree. 4. \instrument. \gpdef)). 6]. 3. 5b.25.25. \instrument. Pbind(\dur. \instrument. 2. \gpdef)).stop. Pbind(\dur. 5b]-2. inf). \instrument. 0. Pbind(\dur.play.25. 2. Pseq([3.default. \degree. Pdef(\y. 4. \gpdef)). 0. 5b. inf). 6]-2). 858 . // using fadeTime: Pdef(\y). 6]+1. inf). ) Pdef(\x).1). 3.25. \degree. 1 / 6. \gpdef)). inf). \instrument. 0. \instrument. 0.Where: Help→JITLib→Patterns→Pdef Pdef(\x. \gpdef)). 0.25.3. Pbind(\dur.25. 4. Pbind(\dur. \degree. \degree.5.0.fadeTime = 8. 9. Pdef(\x. \instrument. inf). inf). Pseq([3. \degree. 4]-3). Pseq([3. 10].rand.25. inf). 5. \instrument. // tempo change TempoClock. \gpdef)). \instrument. \instrument.

Pseq([3. but the following would crash. \gpdef)). outset When quantizing to a larger number of beats.25. [7. Providing an outset quant value is a way to make the change so that it appears as if it had been done at the previous grid point already.play. TempoClock. \degree. Pshuf([3. Providing a number larger than zero. 5. Pbind(\dur.4]. Pdef(\x)]. Pseq([Pbind(\instrument. \gpdef)]. \instrument. inf)). a structure like the following works: Pdef(\x. Pseq([Pdef(\y). inf)). 3]-3). the next possible quant point is used as outset.35. because . Pdef(\x).default. Pdef(\x. Pbind(\instrument.clear. the changes become very slow if one has to wait for the next beat.4]. 5.0. 4. recursion: Pdefs can be used recursively under the condition that the stream call structure allows it. 0. Pbind(\dur. 0. \instrument. The stream is fast forwarded to the current position relative to the quant grid. For example. \gpdef). if quant is 32. [7. Pdef(\x).clear. and one has just missed the first beat when changing the pattern. // clear all. 859 .tempo = 1.embedInStream is called recursively with no limit: // Pdef(\y.Where: Help→JITLib→Patterns→Pdef Pdef(\x. \degree. Pdef(\y). \gpdef)). 6]-2).

4. // offset by 1/6 beat relative to y Pdef(\x. Pbind(\degree. inf))). 5. Pdef(\x. inf))). 0. 0.3)). Pseq((0. Pbind(\degree. 2. Pdef(\y). Pseq((0.. outset] // examples ( Pdef(\x).. 0.quant_([8. \dur. 2. 0. Pseq((0. Pseq((0.7)-2.play. inf))). \dur.25. 3.quant_([8. inf).5)). Pseq([ 1. The new pattern is inserted at the next beat (outset=1). 1]). Pdef(\x. Pbind(\degree. 1]). inf). Pseq((0. 4b ]. inf). Pseq([ 1.5.7). 3. Pbind(\degree. the stream is fast forwarded to the time it would be at now if you had done so. 1. \legato. Using an outset of 1. 0.play. \legato. Pbind(\degree. Pseq([ 3. 0. quant can be: [quant. 2.Where: Help→JITLib→Patterns→Pdef one has to wait for 32 beats until the change happens. 0. Pdef(\y. note this fast forwarding might create a cpu peak if the pattern is very complex/fast or quant is very long. offset. Pseq([ 0.quant_([8. 2.7)+2. 0. Pdef(\y. inf). 4 ]. 0. inf). 0. Pdef(\y).scramble-2. 4 ]. 1)). Pdef(\x. Pdef(\x. 7. Pseq((0. \dur. Pbind(\degree. 7.. Pbind(\degree. 860 . Pbind(\degree.1)). Pbind(\degree. 4. Pbind(\degree. \legato. \legato. 1. 2.7)..3)). 1]). 1/3. 0.25. 3. ) Pdef(\x. Pdef(\x).7)+2. inf). \dur. // offset by half a beat Pdef(\x). 4 ]. it is assumed that you had already changed the pattern at the first beat. \dur.scramble-4.. 0. Pdef(\x. 6.7). Pdef(\y. so it simply has to be taken into account.1)).. This is hard to avoid. inf). 1)). 0.

play(quant:quant).trace(\degree)). \dur. Pbind(\degree..trace(\degree)).7).trace(\degree)). Value and a count index are passed to the function. Pbind(\degree. The condition is always valid for the next pattern inserted.7). Pdef(\x). 1. Pseq((0.quant = 8. Pdef(\x). Pdef(\x. Pdef(\x. no offset. Routine { loop { 8. inf)). Pseq((0. Pseq((0. there 861 . Pdef(\x). 6].7)+2. Pdef(\x.7). Pseq((0. inf)).wait } } }. \dur.fadeTime = nil.7). inf) + [0.5)). inf)). the instance variable condition can be set to a function that returns a boolean.. Pbind(\degree.play(quant:quant). 1].play.7)..7).postln. the reset message can be used. For stuck conditions. 0. Pbind(\degree. Pdef(\x). insert quant to 1 beat Pdef(\x). Pbind(\degree. Pseq((0.trace(\degree)). Pdef(\x.. update condition In order to be able to switch to a new pattern under a certain condition. ) Pdef(\x. Pseq((0. Pdef(\x).Where: Help→JITLib→Patterns→Pdef // some testing ( varquant = #[8. 0. inf)).. 3]). // quantise to 8 beats.. 0.quant_(quant). Pdef(\x.quant = 1. inf) + [0. Pseq((0.do { | i| ("uhr:"+i). inf) + [0. Pbind(\degree.reverse.trace(\degree)). Pbind(\degree. Pbind(\degree. Pseq((0.7). 6]..fadeTime = 8.. inf)). As counting up (such as "every nth event. a swap can happen") is a common task.trace(\degree)). Pdef(\x.5).

quant = 0.7) + 5. inf).Where: Help→JITLib→Patterns→Pdef is a method for this.3)). 0. 862 .rand.postln Pdef(\x. \dur. \dur. Pbind(\degree.. Pseq((0. // we don’t want quant here. \dur..rand. so decisions can be made dependent on the event’s fields reset // reset to change immediately: Pdef(\x).reset. 0. // the above is equvalent to: Pdef(\x. Pseq((0.3)). called count(n). 0.postln % 6 == 0 }).count(8).3)). Pbind(\degree.condition_({ | val.condition_({ | val. // the value that is sent in is the event. i| i.5). Pdef(\x). Pdef(\x). Pbind(\degree. Pseq((0..7) + 5. Pdef(\x. i| == 0 }). (i % 8). inf).play. inf).

Tdef and Ndef.0 (it is not 0. (see example below). *new(key) acess the pattern at that key (if none is there.Where: Help→JITLib→Patterns→Pdefn ID: 258 Pdefn value-stream reference definition superclass: PatternProxy access and assignment are done by *new keeps a reference to a task that can be replaced while playing. instead of a pattern. a default pattern is created) *default a default source.0 in order to make it safe for durations) *removeAll remove all patterns *all dict that stores all Pdefn *all_(envir) set the global environment 863 . if none is given. the pattern can be anything that embeds in a stream. it is very similar to [PatternProxy] it can be used to store value patterns globally (for event patterns. Pdefn(key) returns the instance. Pdefn(key. a function can be passed in. creating a routine. pattern) store the pattern in a global dictionary under key. pat) defines the pattern and returns the instance. the default is 1. like Pdef. see Pdef). *new(key.

reset switch the pattern immediately. it is created and the pattern is rebuilt. the change is scheduled to the beat (pattern_(.Where: Help→JITLib→Patterns→Pdefn quant_(beats) set the quantisation time for beat accurate scheduling can be a pair [quant. embeds itself in stream. offset] *defaultQuant_(beats) set the default quantisation for new instances (default: nil) can be a pair [quant. pdefKey. if quant is not nil. key2. When set for the first time.. it is used as an environment for the routine function.. val2. the patterns can be accessed via the currentEnvironment endless returns a Proutine that plays the proxy endlessly. the stream value and a count is passed into the function (see example) the methods count_(n) simply counts up to n and switches the pattern then source_ set the pattern (internally done by *new(key. key.. . offset] condition_(func) provide a condition under which the pattern is switched when a new one is inserted. map(key. (stuck conditions can be subverted by this) envir_(event) provide a default environment for the proxy.. pattern).) set arguments in the environment. set(key. pdefKey . val.) map one Pdefn to the other. the routine pattern is rebuilt. replacing nil with a default 864 .. If given. If there is none.) is equivalent) embedInStream(inval) just like any stream.

Pdefn in expressions Pdefn(\c. inf) 3. Pdefn(\a.value. so that it is a good time value default. 100).postln }.value. This allows to create streams that idle on until a new pattern is inserted. // (re)define Pdefn(\c) 8. Prand([1. Pseq([1.Pdefn(\a)). 4. 2.do { t. Pdefn(\c.value. // (re)define Pdefn(\a) Embedding Pdefn in other patterns 865 . Pdefn(\a. Pdefn(\b. inf)). Pdefn is similar to [Pdef] and [Tdef] . // default value for a Pdefn is 1. 3]. t = Pdefn(\c). Pdefn(\a) + Pdefn(\b)). // create a stream from Pdefn(\c) t. see the other helpfiles for comparison. inf)).value. // (re)define Pdefn(\b) as Pseq([1. // (re)define Pdefn(\a) as 100 t. Pdefn(\a) * Pdefn(\b) . 2]. 2.postln }. 3].Where: Help→JITLib→Patterns→Pdefn value (1).do { t.asStream.

1). 0. 3. d = exprand(0. \dur.inf)). 66. Out. env = EnvGen.wait }) }).1)). 866 . Pdefn(\deg). Pseq([55. 0. Ppar([ Pbind(\degree. inf).ar(d * 300. 1. Pseq([0. t = Task({ loop({ x. 77]. x = Pseq([0. u = SinOsc. // Pdefn can be accessed in multiple streams ( SynthDef("Pdefhelp".Where: Help→JITLib→Patterns→Pdefn Pdefn(\x. 5. Pbind(\degree. ) Pdefn(\deg.ar(out. pan. Pset(\instrument.play.play.perc(0. Pan2. sustain=1. amp=1. var env. amp * env). Pseq([1.ar(SinOsc. }).1. freq. ) ( Pdefn(\deg. sustain).inf)). [1s. 3]. 77]. Pseq([55.stop.inf)).store. pan)). Pdefn(\x. 0. 1) }.inf)). Pdefn(\x)].next. 2].postln.3. s. { arg out. Pdefn(\x.03. rrand(0. 3.01.ar(u + 1 * freq. u=1. Prand([0.asStream. doneAction:2). 66.boot. Pdefn(\deg)).2) * d. \Pdefhelp. 4]]. 2.1. u.do { var d. 1/3) ]) ). t.kr(Env.

Pseries(0.Where: Help→JITLib→Patterns→Pdefn Pdefn(\deg. { loop { 5. 6]. #[5. ( Pdefn(\deg. 3. 1. -1.do { | j| } } }) ) (i % j).postln.quant = 4. 2. // activate immediately again ( Pdefn(\deg. 7. inf) }). 3.choose.choose. 7.inf)).2). 1.choose. ) Timing: when does the definition change? // if quant is set. Plazy { var pat. Pseries(11. 12].choose. 4]. 11)].yield. Pdefn(\deg). pat = [Pshuf([0.do { | i| #[1. #[14.quant = nil.2). Pn(pat. 6].yield }. 4]. Pn(Pshuf([0. Pn(Pseries(0. 8). 0. 11). the update is done at the next beat or whatever is specified: Pdefn(\deg). Pdefn(\deg. 2. 3. the instance 867 . 3.yield. update condition In order to be able to switch to a new pattern under a certain condition.inf)).

As counting up (such as "every nth event. reset // reset to change immediately: Pdefn(\x). the reset message can be used. The condition is always valid for the next pattern inserted.8). Pseq((0.choose) } }). z = Pbind(\degree. Functions as arguments to Pdefn: (experimental.choose) } }).5). inf)).. 3.count(9). 0.reset. \dur.postln % 9 == 0 }).1. bound to change!) Pdefn(\deg. Value and a count index are passed to the function.condition_({ | val.rand. Pseq((0.01) + [2. For stuck conditions. there is a method for this. 3.round(0. Pseq((0. { loop { yield(0. Proutine { loop { yield(0..Where: Help→JITLib→Patterns→Pdefn variable condition can be set to a function that returns a boolean. a swap can happen") is a common task. 9]. inf)).play. // this is not exactly true. 9].25).condition_({ | val. Pdefn(\x).postln % 6 == 0 }). Pdefn(\x.rand. // equivalent to: Pdefn(\deg. see below. i. called count(n).1.round(0. inf)). i| i.. // the above is equvalent to: Pdefn(\x.8).. i| Pdefn(\x.01) + [2. 868 .

t. \b. Pseq([1. { | e| //(e.b) + 0.a + e. 1. Pdefn(\z).envir d Pdefn(\z).nextN(3). { | e| loop { yield((e. inf)).round(0.set(\a. // [1] t = Pdefn(\z).rand.a + e. 3].01)) } }) ).b) + 0.rand. ( Pdefn(\z.next. 2.01) 1 Pseq([1.set(\a. Pseq([1. e.round(0.Where: Help→JITLib→Patterns→Pdefn The (inner) environment when passing a function to // set() creates a local environment that overrides the outer currentEnvironment Pdefn(\z). t.1.1.asStream.set(\a. t. ( Pdefn(\z. e = Pdefn(\z). 1)). 3]. 1) }) ). 869 . 3). 2. Pdefn(\z.nextN(3).b]. 5). 2.

b = 10. // Pdefn default value (1) is used Pdefn(\other. inf)). t. Prand([200. \other).nextN(3).map(\a. 300. t. 870 . // if you want to keep using the currentEnvironment at the same time. // assign a pattern to \other t. // assign the currentEnvironment to the envir’s parent (or proto) field // (this shouldn’t be a proxy space of course. a = 9.nextN(3).parent = currentEnvironment.envir. // post the envir // using the "map" message one can map one Pdefn to the other: Pdefn(\z). 400].nextN(3).Where: Help→JITLib→Patterns→Pdefn Pdefn(\z).) Pdefn(\z).envir.

play. x. 7. 4. Pseq([0. 4) ). keyPattern.Where: Help→JITLib→Patterns→Pdict ID: 259 Pdict pattern that embeds patterns from a dictionary superclass: Penvir *new(dict. \b. Prand([\a. 5. 8])). 2])). \c]) ]. 0. ) 871 .read. \degree. \degree. Pseq([ \a. 2]. Pseq([7. ( e = ( a: b: c: ).06. 3. 8. 2)) x = Pdict(e. Pbind(\dur. 1. 0. \degree. default) // example SynthDescLib. Pbind(\dur.1. 0. repeats. Pseq([0. Pbind(\dur.3.

a = Pseq([1. 12. 2. 6.do({ b.5.do({ b.postln }).connected = false. decicion.do({ b. 3].Where: Help→JITLib→Patterns→StreamClutch ID: 260 StreamClutch superclass: Stream buffers a streamed value StreamClutch. 2. 3].new(pattern. 872 . b = StreamClutch(a. //statistical clutch a = Pseq([1.next.next.next.coin }). { 0. inf). b = StreamClutch(a).postln }). //sound example: ( var clutch. 6. connected) pattern a pattern or stream to be buffered connected if true it wil call the next stream value for each time next is called if false it returns the last value //example: SynthDescLib. b. inf).postln }).read. pat.

inf). 0. decicion. b. 450]. pat = Pbind(\freq.play.asEventStreamPlayer. \dur. [300. 873 . b.10). inf). ) // independant stepping ( var clutch.asEventStreamPlayer. 450].Where: Help→JITLib→Patterns→StreamClutch decicion = Pseq([Pn(true. 0. 10)].asStream.step. ) b.3). pat. decicion). clutch = StreamClutch(pat. 400. Prand([true. Pseq([200.connected = false. [300. 302].3). false]. \dur. inf). b = StreamClutch(pat). Pseq([200. pat = Pbind(\freq. 302]. clutch.play. 400.

0 beat wait time source_(obj) set the source. (default: 1. schedule this change to the next beat the object is a routine function. which is evaluated in a protected way. if none is given. so that failure will notify the proxy that it has stopped. offset] quant get the quantization value *defaultQuant_(beats) set the default quantization value for the class. related: [Tdef] *basicNew(source) create a new instance with a function (the source). the default is a loop that does nothing with a 1. If a quantization is given. (*new is implemented for Tdef to avoid a dispatch) *default a default source.0) 874 . The object can also be a pattern of time values.Where: Help→JITLib→Patterns→TaskProxy ID: 261 TaskProxy event stream reference superclass: PatternProxy Keeps a reference to a task (time pattern) that can be replaced while playing. quant_(beats) set the quantization value. can be a pair [quant. the source should be a routine function (see Tdef) or a pattern of time values. It plays on when the old stream ended and a new stream is set and schedules the changes to the beat.

) set arguments in the environment. a) using it as stream reference source_ set the routine function / pattern (internally done by *new(key. val. offset] condition_(func) provide a condition under which the pattern is switched when a new one is inserted. obj) embedInStream(inval) just like any stream. If there is none. embeds itself in stream b) using it as EventStreamPlayer 875 . the methods count_(n) simply counts up to n and switches the pattern then reset switch the pattern immediately. When set for the first time. (stuck conditions can be subverted by this) envir_(event) provide a default environment for the proxy. replacing nil with a default value (1 s. wait time). This allows to create streams that idle on until a new pattern is inserted. val2. it is created and the routine pattern is rebuilt. the stream value and a count is passed into the function. endless returns a Proutine that plays the proxy endlessly. key2. If given. set(key.. . the routine pattern is rebuilt. it is used as an environment for the routine function..Where: Help→JITLib→Patterns→TaskProxy can be a pair [quant.

x.source = { loop { "---------////----------------------". x = TaskProxy. x. 0. } }.postln.default.scramble.wait. } }. 876 . if a TaskProxy is playing and its stream ends.Where: Help→JITLib→Patterns→TaskProxy play(clock.tempo = 2. x.seconds. if you want to play multiple instances. phase] stop stops the player player the current player (if the TaskProxy is simply used in other streams this is nil) pause / resume / reset / mute / unmute perform player method isPlaying returns true if TaskProxy is running.playOnce(clock. 1.source = { loop { "ggggggggggggggggg9999ggg999ggg999gg". 1.postln. quant) quant can be an array of [quant. x.basicNew. x.source = { loop { thisThread. a) using it as a task player // create an empty Tdef and play it. } }. TempoClock. protoEvent.source = { loop { thisThread.wait. use .25.postln.01.play. quant) starts the TaskProxy and creates a player. } }. 0. protoEvent.wait.scramble.wait.postln.seconds.5. it will schedule a stream for playing as soon as a new one is assigned to it.

x.05.source = { var x.kr(Env.01. x. } } ) ( x. } }. doneAction:2). Out. x.Where: Help→JITLib→Patterns→TaskProxy x. dur.store. -1. 877 .stop. 0.scramble.1. SinOsc.play. 0. 0. var env.ar(out. \freq.stop.tempo = 1.play. ) x.0. env = EnvGen. SynthDef("pdef_grainlet". { arg out=0. x. 640)).sendMsg("/s_new". // sound example ( // load a synthdef s.wait.postln }.postln }.3).ar(freq.boot.source = { "one more". rrand(600.0. freq=440.postln.perc(0. ( x.source = { loop { "some more".wait. env)) }).source = { "the end". x. TempoClock. "pdef_grainlet".25. 0.default.source = { loop { s. dur=0.

rand. "pdef_grainlet".choose.do { arg item.rand.wait. 0.0. 10 + 30.rand) }. ) // play ending stream once ( x.125.next).loop.0.basicNew { loop { s. loop { s. loop { s. } } ) 878 . x = Plazy { Pseries(1300 + 300.asStream.asStream.wait.sendMsg("/s_new".05].rand. } } ) ( x.loop.wait. 0. -1. dt. dt = [0. 100). 0.asStream.rand. s. "pdef_grainlet".next). -1. \freq. \freq.0.sendMsg("/s_new".wait.0. 20.0.sendMsg("/s_new".sendMsg("/s_new". 1. "pdef_grainlet".05. x = Plazy { Pseries(300 + 300.0.1. 10 + 30. } }. dt. y. 1500). x.0. -1.source = { var x.0. } } ) // metronome ( y = TaskProxy. \freq. \freq.source = { var x. 110 + 130.05.play. -1. x. 16) }.Where: Help→JITLib→Patterns→TaskProxy x = Pseries(300. item). x. 0. "pdef_grainlet".

postln }. "two"..postln. a.. y. 0.source = { "one". [\freq.source = { var z. and so on ."..5.". 1. }. r = Task { "counting.embedInStream. // change the def r. 1..embedInStream.wait. "done. 2. 1. c.wait.embedInStream.basicNew. z = Synth(\default. // play a stream c. x.wait. r.release }. z. c.5. // of course TaskProxies can be used in other Tdefs: ( b = TaskProxy.basicNew } ! 2. ) r..Where: Help→JITLib→Patterns→TaskProxy .postln.play. b. 300]).play. 1.".source = { var z.wait. a.release }. b) embedding TaskProxy into other Tasks / Routines ( #a..postln..stop.source = { "counting.postln..reset.wait. z. z = Synth(\default). c = { TaskProxy. a. 2.stop.wait. 879 .wait.

) b.1. 0. // if one wants to branch off a stream in a separate thread.wait.1. a.play.embedInStream. c.asStream. ) 880 . }.wait.play.asStream.postln. ( Routine{ c. asStream is used.Where: Help→JITLib→Patterns→TaskProxy c. "done.play. }.play.playOnce.". 0.asStream.

Tdef(key.0 beat wait time *removeAll remove all tasks *all dict that stores all Tdefs *all_(envir) set the global environment 881 . It plays on when the old stream ended and a new stream is set and schedules the changes to the beat. if none is given. pat) defines the pattern and returns the instance. *new(key) acess the task at that key (if none is there. if there is already a Tdef there. like Pdef and Ndef. obj) store the task in a global dictionary under key. it is very similar to [TaskProxy] *new(key. Tdef(key) returns the instance. replace its task with the new one. obj is a function or a pattern of time values. the default is a loop that does nothing with a 1.Where: Help→JITLib→Patterns→Tdef ID: 262 Tdef task reference definition superclass: TaskProxy keeps a reference to a task (time pattern) that can be replaced while playing. a default task is created) *default a default source.

see example for usage. This allows to create streams that idle on until a new pattern is inserted. key2. quant] condition_(func) provide a condition under which the pattern is switched when a new one is inserted. set(key.) set arguments in the environment. it is created and the routine pattern is rebuilt. When set for the first time. the routine pattern is rebuilt. a) using it as stream reference embedInStream(inval) just like any stream. replacing nil with a default value (1 s.Where: Help→JITLib→Patterns→Tdef quant_(beats) set the quantisation time for beat accurate scheduling can be a pair [offset. embeds itself in stream.. If there is none. quant] *defaultQuant_(beats) set the default quantisation for new instances (default: 1. val2.0) can be a pair [offset. the methods count_(n) simply counts up to n and switches the pattern then reset switch the pattern immediately.. (stuck conditions can be subverted by this) envir_(event) provide a default environment for the proxy. endless returns a Proutine that plays the proxy endlessly. If given. val. . 882 . it is used as an environment for the routine function. the stream value and a count is passed into the function. wait time).

Tdef(\x.scramble.play. a) using Tdef as a task player Tdef(\x). it will schedule a task for playing as soon as a new function is assigned to it. quant) quant can be an array of [quant. // create an empty Tdef and play it.playOnce(clock.postln.wait. }) }). doReset.seconds. { loop({ thisThread. 1. 0. if a Tdef is playing and its stream ends. quant) starts the Pdef and creates a player.seconds.wait. use . 1. Tdef(\x. }) }). phase] stop stops the task player the current task (if the Tdef is simply used in other streams this is nil) pause / resume / reset / mute / unmute perform player method isPlaying returns true if Tdef is running. }) }). 883 .5.wait. { loop({ thisThread. }) }).scramble. Tdef(\x. doReset.postln.postln.wait.Where: Help→JITLib→Patterns→Tdef b) using it as Task play(clock.25. 0. { loop({ "ggggggggggggggggg9999ggg999ggg999gg".postln. Tdef(\x. { loop({ "---------////----------------------".01. if you want to play multiple instances.

1.01.05. 0.perc(0. freq=440. // sound example ( // load a synthdef s. { loop({ "some more".ar(freq. env)) }). 640)).tempo = 1.postln.Where: Help→JITLib→Patterns→Tdef TempoClock. Tdef(\x).clear. ( Tdef(\x. var env.wait.25. Tdef(\x. Tdef(\x). Tdef(\x.postln }). }) }) ) ( 884 .0.store.stop. -1. dur.scramble.sendMsg("/s_new".3).play. Tdef(\x). { loop({ s.play. Out.ar(out. env = EnvGen. dur=0. Tdef(\x.default. { "one more".boot. 0. "pdef_grainlet".tempo = 2.0. doneAction:2).default.kr(Env. }) }). SinOsc. ) Tdef(\x). { "the end". SynthDef("pdef_grainlet". \freq. 0.postln }). 0. TempoClock. { arg out=0. rrand(600.wait.

-1. // play ending stream once ( Tdef(\x. x = Plazy({ Pseries(1300 + 300.rand.0.rand. 20. 100). }) }). 10 + 30... \freq.rand. 110 + 130. }) }) ) .choose.asStream.05]. dt. 16) }). x = Plazy({ Pseries(300 + 300. item). }) }) ) ( Tdef(\x.stop.sendMsg("/s_new"..0. "pdef_grainlet". 0.0. }) }) ) // metronome Tdef(\y.sendMsg("/s_new".wait.0.. loop({ s.play. x.do({ arg item. loop({ s.asStream.sendMsg("/s_new".wait.0.wait. { var x. 1500). 0. \freq.125.sendMsg("/s_new". "pdef_grainlet". -1. x. 0.Where: Help→JITLib→Patterns→Tdef Tdef(\x. -1. "pdef_grainlet".rand) }). -1.wait.1. 885 . { var x. 10 + 30. x = Pseries(300. \freq.next).loop.rand. dt.asStream.05. dt = [0. 1.05.next). s. 0.loop. Tdef(\x).0. { var x. { loop({ s. and so on . \freq.0.0. "pdef_grainlet". x.

wait.. 886 .".removeAll. z. { var z. Tdef(\c). Tdef(\c.wait.embedInStream. r = Task({ "counting.asStream.". r.play. 0.release }). // play a stream Tdef(\c. // of course Tdefs can be used in other Tdefs: ( Tdef(\b.wait.5.play.play.reset. { "counting. // change the def r. "two".5. z = Synth(\default.postln.postln }). { var z.. ) Tdef(\b). Tdef(\c). "done..wait. b) embedding Tdef into other Tasks / Routines ( Tdef(\a. }). 1. 1.wait.release }).wait. z = Synth(\default). 2. { "one".embedInStream. ) r.wait. }). 1.embedInStream.".postln.postln.postln. Tdef(\a). "done.. z. 2.". 1. 300]). [\freq.Where: Help→JITLib→Patterns→Tdef Tdef.postln. Tdef(\a).embedInStream.

5. asStream is used. dur=0.05.play. 0. ) Tdef as a time pattern Instead of using a Pdefn for time values.1.perc(0.kr(Env. 1.asStream. SynthDef("pdef_grainlet". ( // load a synthdef s.play. 0.boot. freq=440. When changing its source.3).store. dur. }). Tdef(\c). SinOsc.ar(freq. 0. ) Tdef(\z. 887 .play. Out. 0. inf)).ar(out. Tdef(\a). { arg out=0. // also the method playOnce can be used ( Routine({ Tdef(\c). Pseq([1. 0. it keeps the stream of values synchronized to its clock. it can be useful to use a Tdef.wait. var env.asStream. env)) }). 0.Where: Help→JITLib→Patterns→Tdef // if one wants to branch off a stream in a separate thread. 1.wait.play. doneAction:2).5].asStream. env = EnvGen.01.1.

Pseq([1. 1.5]. 1]. 1. Pfunc { TempoClock.default. 0. 0. 2. Pbind( \dur. 3. 1. inf). 0]. inf)). 0. \note. 0. \note. inf)). Pseq([1.5]. 888 . 4.5.elapsedBeats. // reference beat \sustain. Ppar([ Pbind( \dur. 1. \pdef_grainlet. // but might be in different order ( // to avoid this. inf)). // exchange time pattern Tdef(\z.Where: Help→JITLib→Patterns→Tdef ( Pset(\instrument. \x. 0. Pseq([1.23.play(quant:1). 8 ) ]) ). ) Tdef(\z. Tdef(\z.postln } // posts the onset times ). // pattern stays in sync. 1. 1.1. Tdef(\z).5. 0. Prand([1. set the quant to a appropriate value.

7 Tutorials 889 .12.

b1. // push it to current // this synthdef can be changed on the fly. // create a new environment d. as well as with the synth def above s1 = Synth. 4000).ar(40). but works differently.. // add a bus: b1 = Bus. [\freq.1) ) }). Ringz.send(s). // [1] // now you can play around with these lines. s1. 890 .ar(Dust. // using a simple environment. 0. \x. ) use expression [1] for replacing a given synth // send a first synth: s1 = Synth(\x). but the synth will // not change from this. see [jitlib_basic_concepts_01] and d = (). freq.set(350). { | freq=440| Out.replace( s1. this looks just like ProxySpace. 3000]).set(\freq.Where: Help→JITLib→Tutorials→Basic_live_coding_techniques ID: 263 // basic live coding techniques ("object style") // without the use of JITLib // more to come.control(s).push.ar(0. ( SynthDef(\x. [jitlib_basic_concepts_02] // for the difference.

Where: Help→JITLib→Tutorials→Basic_live_coding_techniques s1. d. // finish: b1. s3 = { Out. 1)) }.index.free. 900.xline(800.clear.kr( b1.set(100). d. 891 . // add some mouse control on the fly s3. MouseX.free.kr(300.pop. b1. // remove it again. 5).map(\freq. b1). // set the bus to different values: b1.

kr(2) + 400 }. z = z * SinOsc.20) }.2]) }.kr. many objects understand . ctl2[1] = { LFNoise2.wrap2( ctl2) * pat = Pbind(\freq.20) * LFNoise0. freq[0] = { freq[5] = ctl1.1) }. ctl1.ar( freq.kr([20. 20).storeOn. which a way to post their string that is needed to reproduce them by compilation. sometimes one wants to store a certain configuration of a proxy space. z = 9. ctl1 / ( ctl2 + ctl1).do { | i| z }. 4.kr([20. 0.2.20) }. // an example how ProxySpace can document its current state: p = ProxySpace.kr([20. 0.set(\freq.push(s). ctl2[0] = { LFNoise2.20].0. Pfunc({ 1.rand })). out. 760.20]. \ffreq.asCompileString.kr(2) + ctl2. ) 892 .20].sqrt. i+[0. which can be done if all functions used are closed functions.Where: Help→JITLib→Tutorials→Jitlib_ascompilestring ID: 264 { 10 + 6 * harry }. out = { SinOsc. ( ctl1 = { var z = 1.kr(i.

// document all dependants of 893 . // document everything // document all dependants of out ctl1 p.document([\ctl1]). p. // the document message creates a new document which it posts the code into p.asCompileString.Where: Help→JITLib→Tutorials→Jitlib_ascompilestring p.document([\out]).document.

// returns a function 894 . // you can start to calcuate with y.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_01 ID: 265 some placeholders in supercollider 1 this helpfile explains some basic concepts of interactive programming with supercollider and proxy space. even if its value is not yet given: z = y + 10. even if only one ugen is created eventually. see also: [OutputProxy] [Function] [Ref] using a Ref as a proxy: // reference example // create a new Ref object y = ‘(nil). previous: [JITLib] next: [jitlib_basic_concepts_02] a) What is a proxy? A proxy is a place holder that is often used to operate on something that does not yet exist. For example. Any object can have proxy behaviour (it may delegate function calls to different objects for example) but specially functions and references can be used as operands while they keep their referential quality. an OutputProxy is used to represent multiple outputs of a ugen.

// this fails. // access the enironment: x = 9.value // the same without a reference does not work: y = nil. // now 9 is stored there is nothing stored: nil x + 100. // set y + x. // calculate with it currentEnvironment. // the value is stored in the environment y + x. // cause an error: y y is nil. y = -90. // this works.value = 34.postln. // this fails. // empty y first z = y + 10. using a Function as a proxy: 895 . // also an array does not provide this referentiality: y = [nil]. z.postln. // store something x. // the function z can be evaluated now. // an environment without sufficient defaults has the same problem: currentEnvironment.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_01 // now the source can be set: y. // array with nil as element z = y + 10. // anEnvironment x.

896 . see also client side proxies like [Tdef][Pdefn][Pdef] b) NodeProxy For interactive programming it can be useful to be able to use something before it is there . Some preparations have to be done usually . // boot the server s. Audio output on the server has mainly two properties . for example if one wants to do maths with running processes on the server. // two proxies on a server. z.value.2. // empty y first z = { y } + 10. number of channels is 2 // use them in calculation z. instead it creates a new function. 2). z.boot. z = NodeProxy. which // does not fail when evaluating it after y is set to 34. y = NodeProxy.sin * 0.audio(s.a calculation rate (audio or control) and a certain number of channels.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_01 // a function can serve the same purpose y = nil. In other situations this sort of preparation is not enough. // this does not fail.play. which cannot be changed while it is in use. y = 34. 2).it makes evaluation order more flexible and allows to postpone decisions to a later moment. a reference has to be created.audio(s.like above. These are the main static properties of a node proxy. calculation rate is audio rate.source = y.

301].source = { Saw.push(s.source = 0. // move out of the proxyspace. So the above reads like this: p = ProxySpace.0. 301].ar([300. // the source can be of various type. y.clear.2. z.source. free their bus number y. In order to provide a simple way of creating node proxies.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_01 // set its source now. p. // post the source y. 4*pi) }.play.pop. // store proxy space in p so it can be accessed easily. z = y. y = { Saw. z. one of them would be a number: y.sin * 0. // clear the space (all proxies) p. 4*pi) }.clear. further readings: [NodeProxy] [ProxySpace] [Ndef] 897 .boot).clear. a proxy space can be used.ar([300. // end them.

Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_01 next: [jitlib_basic_concepts_02] 898 .

// set b + a. // this works. // calculate with it currentEnvironment.basic concepts 2 external structure of the node proxy. // now 9 is stored there is nothing stored: nil a + 100. b = -90. // access the environment: a = 9. previous: [jitlib_basic_concepts_01] next: [jitlib_basic_concepts_03] a) b) c) d) e) f) normal environment lookup proxyspace as an environment using the proxyspace to change processes on the fly when are the node proxies initialized? moving out of the proxy space using ProxySpace together with other Environments a) normal environment lookup currentEnvironment.postln.. // cause an error: y y is nil. you haven’t left it from last helppage.postln. referencing in proxyspace and environments. // the value is stored in the environment b + a.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_02 ID: 266 proxy space . // store something a. 899 . // anEnvironment (if not.) a.

if "know" is true.new(s).postln. so i becomes the current environment. x. a proxy space this environment represents processes that play audio on a server. currentEnvironment. x.a + x. p = ProxySpace. // this is identical. x + // accessing creates a NodeProxy (uninitialized) automatically. // create a new environment. currentEnvironment === p.b.know = true. // but a placeholder (proxy) instead p. because the lookup does not return nil.push. x. further readings: [Environment] b) proxyspace as an environment one can replace the current environment with a special type of environment.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_02 // note that you can always access environments (or ProxySpaces) from outside as well: x = currentEnvironment. // now there is two placeholders in the environment. p. 900 . x[\a] + x[\b] // equivalent to b + a // or.postln. // this works immediately. // push it. y. store it in variable p for now.

[1450. now it is initialized to . 950]. 1234]. // as soon as a sound function (or any compatible input) is assigned to a proxy // this sound plays on its own private bus (so it is not audible yet. [850.ar([5.play.2) } ) // the proxy has been initialized by its first assignment. // it plays at audio rate (because we have assigned an audio rate ugen function) // and it has two channels (because the function has stereo output) x. // what bus index is it? this posts the index to the postwindow // before it was .ir(nil). 0.ar(4) * 20.boot. // the signal onto a public bus. // now listen to it.) ( x = { RLPF. 7]) * 5. 0.bus // what bus is it? x.2) 901 . a monitor is created (see [Monitor]) that plays This is independent of the proxy itself.index.ar(Impulse.ar(2) x. // for further info see: [jitlib_basic_concepts_03] (part c) // the sound function can be changed at any time: ( x = { RLPF.ar(Impulse.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_02 c) using the proxyspace to change processes on the fly // boot the server s.

7]) * 5. ({ exprand(200.5)) * 0.2) } // same pulse ratio (5/8).ar * 8.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_02 } ) // You can tune a sound function to your liking very easily // by replacing it with little (or big) variations: // filter freqs higher: x = { RLPF. [1800. 0) }.ar(Impulse. // different filter freqs every time: x = { Ringz. 4000) } ! 2). // it has two channels. just as the x. // but it can be used in any other proxy: ( x = { RLPF. // note that y is not audible directly. } ) [1450.ar(20). you can create little // textures by hand: x.5. 8] * 3.ar([5.ar(Impulse.2) * 5. 2000].. 8] * rrand(0.ar(Impulse. 2000]. 0. y.ar([5.5.2) } // different filter: x = { Ringz. 1.05) } // here is another proxy: y = { Pan2. different pulse tempo: x = { RLPF.ar( y. but it plays on another (private) bus. [1800.ar([5.ar(Impulse. 0. [1800.2).ar(Dust. 0. 1234]. the result changes dynamically: 902 .fadeTime = 3. 0. 0.bus. 2000].05) } // and if you set the proxy’s fadeTime.2) // when the proxy changes.ar([5. 8] * 3.

1]) }. 18.ar(MouseX. 18. nil can be used: y = nil.bus.postln. z2 = { LFNoise0. 2. 1)) * [1. 1)]) }. as far as it is possible. 0. further readings: [proxyspace_examples] [Bus] [AbstractFunction] [UGens] d) when are the node proxies initialized? bus initialization of a node proxy happens as soon as it is used for the first time. // a four channel control rate proxy z2.play. // y is playing on another bus.kr(0.ar(MouseX. 4]) }. // stop listening.kr([1.stop. 903 . y = { PinkNoise.ar([MouseX. 3. MouseY. 1] }.2) * [1. y directly: // to remove an input. y = { Impulse.stop. // than // we can also listen to y.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_02 y = { Impulse. 18. later inputs are adjusted to this bus.kr(2. x x.kr(2. y. the proxies run in the background.bus. 1). // stop listening y.bus.kr(2. x.

play(0. u = { PinkNoise. numChannels are extended by wrapping). z34.numChannels.postln.ar(3) // the first access allocates the bus // a 3 channel audio proxy z34. // use only one u.ar. A typical problem is demonstrated here: u.2) }. // play 2 channels: the 1 channel is expanded into 2. Thus it can be useful to explicitly initialize proxies that use variable type inputs: b. c. // here it is explicitly given.clear.clear. p. play defaults to 2 channels.bus. This initialisation happens whenever the proxy is first used. // initialize 2 audio channels (default).postln. Later. // here it is explicitly given only to make it more clear. // initialize 1 audio channel u.ar(0.postln. // a constant value causes a single channel control rate proxy.2) }. the proxy can be accessed with other rate/numChannels combinations as needed (rates are converted.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_02 z100 = 0. 2). z34. only one channel is used: u = { PinkNoise.ar(0.play(0.5. // 2 channels u.numChannels.bus. so to expand the channels u.postln.kr(8).clear. // numChannels of . // these initializations can be removed by using clear: z34. Note that this might cause ambiguous initialisation in which case the proxy should be always initialized first. // if the proxy is not inititialized.play defaults to the proxy’s numChannels. // explicit initialisation // post the whole proxy space 904 .bus. 2). if evaluated the other way round. // 1 channel u. 0 is the output bus number. z100.

Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_02 e) moving out of the proxy space: // play the audio: x. p === currentEnvironment. p. // the old values are still here.pop.5) }. use end: p. currentEnvironment.clear.ar(0.postln.clear. // note that if you use this kind of accessing scheme. // remove the content.postln. currentEnvironment. // clear all in the normal environment: currentEnvironment. This is a common mistake when using normal environments. so the garbage collector can release their memory.end(2) // 2 seconds fade out. // to end all processes in p. // restore original environment: p.postln. // to remove all bus objects and free them from the bus allocato. use clear: p. // p is the proxy space: p. 905 .play.clear. the objects are not garbage collected // until the keys are set to nil. x = { PinkNoise. // this is not the case anymore. a + b.

// you can also access the proxy space indirectly: p[\x]. d = (). you can use a normal environment indirectly: d[\buffer1] = Buffer.envir.postln. 1024). p. // to test this.postln.alloc(s.push. previous: [jitlib_basic_concepts_01] next: [jitlib_basic_concepts_03] 906 .Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_02 f) using ProxySpace together with other Environments using proxy space as an access scheme for node proxies can get in the way of the normal use of environments as pseudo variables. Here is some ways to cope with this. when the proxyspace is pushed. }.play.envir[\x]. // for more than one access to the environment.envir: p.use { buffer1.postln. 0. check for currentEnvironment here // and in the envir document. when you want to know if a certain proxy exists already. // this can be useful for lookup. // or: p.ar(450. // without creating new proxies. you can restrict the // scope of proxyspace to one document (note: this is mac-only currently) EnvirDocument(p. "proxyspace"). 0. use use // to access the inner environment of proxy space directly. use . zz = 81. p[\x] = { SinOsc. d. // direct access would create that proxy.1) }. which would not make sense in that case. // if you want to keep using the current environment as usual.

kr(0. 907 .boot). we will add it later.ar. pause/resume. y.kr(LFNoise1. previous: [jitlib_basic_concepts_02] next: [jitlib_basic_concepts_04] // make new space p = ProxySpace. The index can be any positive integer. z = ( y * pi).push(s. // explicitly initialize proxies a) NodeProxy slots: One node proxy can hold several objects in an execution order.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_03 ID: 267 proxyspace . in which the source objects are stored (see [Order]). // y is still unused. which is on the server.basic concepts 3 internal structure of the node proxy. node order and the parameter context a) slots b) fadeTime b) play/stop.1 * { LFSaw. which is a client side parameter context. As the group can contain an order of synths. // the initial slot (0) is used when assigning directly. send/release.1 ! 3). there is a client side representation. clear c) the parameter context A NodeProxy has two internal contexts in which the objects are inserted: The group.play. z. and the nodeMap.max(0.sin * 0.sum * -18).2) }.

301].1 }.ar(440) * 0.sum.postcs // the function that was put in.ar(exprand(300. z. LFTri.1 }.ar(Saw. { SinOsc. 401.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_03 // other slot numbers are accessed by positive integers: y[1] = { Saw.4) }.ar(870) * 0. 0. y.. { SinOsc. // in case of an audio rate proxy the fade is pseudo-gaussian // in case of a control rate proxy it is linear. // to remove one of them..kr({exprand(1. 600).3].08 }. 0. 2 and 3 (subsequent) z[1. 401.play.3].ar(770) * 0.4) }. 3)} ! 3).ar([300.3). y[0] = { Saw. nil is used: y[0] = nil. // what is to be found at index 1? y[1] // a playing interface y[1]. multiple assignment // the function is assigned to th slots from 1 to 4 z[1.95) }.end. 908 . // if no slot is given. z. // the function is assigned to the slots 1.4] = { SinOsc. all other slots are emptied z = { OnePole.ar([400.source. 0.ar([400.end. // this returns objects in the slots. 0.04 }]. b) fade time: // setting the fadeTime will allow cross fades.] = [ {SinOsc.max(0)) * 0. 0. y.source.

fadeTime = 0.0.3])) * 0.monitor. 909 .ar(ExpRand(300. Saw. // monitor the proxy z.3])) * 0.stop. z = { max(SinOsc. Only if it is not playing (e.ar([304. // is the monitor playing? You can pass a vol argument to play to adjust the monitor volume without affecting the proxy internal bus volume. Saw.1 }. play starts monitoring. if the proxy group is playing (this can be tested with .ar(ExpRand(3.isPlaying).isPlaying. but only in private z. Stop never affects the internal state of the proxy. play/stop this pair of messages is related to the monitoring function of the proxy. z = { max(SinOsc. 304. // the fadeTime can be set effectively at any time z.g because one has freed the group by cmd-period) it starts the synths/objects in the proxy. stop ends the monitoring.fadeTime = 5.ar(ExpRand(3.ar([300. 304.isPlaying.3])) * 0.play.3])) * 0.1 }. Saw. z.ar([304. z = { max(SinOsc. note that the fadeTime is also used for the operations xset and xmap.1 }. // is the group playing? yes. // note that now the proxy is still playing. // 5 seconds z = { max(SinOsc. 600)).ar([304. Here is what they do. 160)).ar([304. play will not affect the proxie’s internal behaviour in any way.(see below) c) play/stop. 301]). 304.2. 160)). stop etc. no. z. Saw. 304.1 }. send/free. pause/resume there are a couple of messages a NodeProxy understands that are related to play.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_03 z. // first hit cmd-period.

3). // send another synth. as the group was still playing. 960) ! 2) * 0. free is used: z. // monitor. the current fadeTime is used for fade in z. if the synth frees itself (doneAction 2) spawn can be used. if the group wasn’t playing. // this does also not affect the monitoring. in order to free the synths and the group. 910 . this does _not_ start the proxy.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_03 z. z = { SinOsc. z. // monitor. this starts also the synth.release. the current fadeTime is used for fade out z.vol = 0. end is used.stop.ar(ExpRand(200.play. // first hit cmd-period. It does not affect the monitoring (see above). this starts the proxy.release. z.free.ar(ExpRand(20. use rebuild. stop playback.play. z.send. // end in 3 sec in order to rebuild the synthdef on the server.play(vol:0. z. send / release this pair of messages controls the synths within the proxy.1 }.end(3). release the old z. // monitor. z. release releases the synth.play. in order to free the synths and the group together. as the group was not playing. send starts a new synth. // while playing you can set the volume also: z. // send a new synth. send by default releases the last synth.8. z. // release the synth.send. 660) ! 2) * Saw.

rebuild. 660)} ! // which is paused.ar({exprand(30. 9))) z. // you can add a new function. pause / resume when paused. // pause the synth.400) + ({exprand(1.3)} ! * LFCub.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_03 this can make sense when the synthdef has a statistic architecture (but of course this is far less efficient than send) ( z = { sum( SinOsc. z.end.1 }. a node proxy still stays active. // resume playing. but every synth that is started is paused until the proxy is resumed again.play. z = { SinOsc. z.max(0) rrand(1.0.pause. z.kr({exprand(1.resume. 8. // send just creates a new synth z. which do not happen when pauseing control rate proxies.ar(Rand(300. 9)) rrand(1. z. 1. 900)} ! * LFSaw.0)} ! * 0. ) rrand(1. 911 .play.rebuild. z. Note that pause/resume causes clicks with audio rate proxies.ar({ExpRand(300. 2) * 0. 9)). // rebuild the synthdef z.1 ) }.send.

z. 440).set(\freq. SinOsc.isNeutral. 1. this context is kept and applied to every new synth: y = { arg freq=500. y = { arg freq=500. the group.clear. Formant.1 }.1 }. // no bus z.play. 70) * 0. y.ar(freq * [1. z. So clearing has to be done with regard to this.ar(50. // unlike in synths.bus. freq * [1. the monitor and releases the bus number.1]) * 0. 1. // not initialized. note that when other processes use the nodeproxy these are not notified.1]. d) The parameter context what happens to function arguments? y. now the argument ’freq’ is a control in the synth (just like in SynthDef) which you can change by the ’set’ message. 912 .Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_03 clear clear removes all synths.

freq * [1.set(\freq. 440). Formant.ar(freq + 3) * 0. // also here the context is kept: y = { arg freq=500. y = { arg freq=#[440.xmap(\freq.1 }.05 }.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_03 xset is a variant of set.ar(freq * [1. 300). SinOsc.ar(freq) * SinOsc.map(\freq.kr(Rand(1. 800. xmap is a variant of map. y. 1).xset(\freq. 800.1]) * LFPulse.ar(4.fadeTime = 3. 800. c).kr(300. 600). a control can be mapped to any control proxy : c = { MouseX. 550]. 1. to crossfade the change using the current fadeTime: y. 70) * 0.mapn(\freq. 1) }.1].xset(\freq. a multichannel control can be mapped to a multichannel proxy using mapn: c2 = { [MouseX. // the same context is applied to all slots: y[2] = { arg freq=500. 3)) * 0. y.1 }.kr(300. to crossfade the change using the current fadeTime: y. to remove a setting or a mapping. MouseY. use unmap / unset. y. c2).unmap. 1)] }. c). SinOsc. y.kr(300. 913 . y. the parameter context also can keep bus mappings. 1. y.

// apart from the parameters explicitly set. see [NodeMap] p. previous: [jitlib_basic_concepts_02] next: [jitlib_basic_concepts_04] 914 . in 8 secs.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_03 the parameter context can be examined: y.nodeMap. // it contains the bus index and the fadeTime // for more information.clear(8). // clear the whole proxy space.

y.ar(1).05) }.default. 0. y. the clock is responsible for the timing of insertion of new functions.clock = TempoClock.ar(Impulse. the assignment operation = ). y = { Ringz. previous: [jitlib_basic_concepts_03] next: [JITLib] a) clock b) quant and offset c) client and server tempo d) sample accurate output a) clock generally.clock = TempoClock. are normally done whenever the put method is called (or. per default at the next beat of the clock.ar(1).push(s. p = ProxySpace. in ProxySpace. // these two synths are started at the time when they are inserted: x = { Ringz.boot). x.default. // now they are in sync 915 .Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_04 ID: 268 Timing in NodeProxy 4 Changes that happen to NodeProxy. 400.play. 600. 0.ar(Impulse. // adding a common clock: x. Sometimes it is desirable to time these changes relative to a clock. usually a tempo clock. most importantly setting its source.play.05) }. every node proxy can have its own time base.

600.ar(Impulse. 0.clock = TempoClock. 400 ! z = { Ringz. exprand(300. [500.ar(1).ar(1). put. which can be either a number or an array of the form [quant.8) }. 800.05) }. y = { Ringz. 600. b) quant and offset In order to be able to control the offset/quant point of insertion. the ’quant’ instance variable can be used.05) }. just like in pattern. 400.0 y = { Ringz. sequence of events: When inserting a new function into the proxy.ar(1).3. removeAt. z = { Ringz. rebuild (and the rebuild operations lag. 3400 ! z.ar(1). exprand(300. quant of 1.ar(Impulse.ar(Impulse.ar(2).08) }. // offset of 0. quant and offset scheduling is used for the following operations: play. 0. 514].ar(Impulse. // for simplicity. Then the proxy waits for the next beat to start the synth. setNodeMap.default. bus_) 916 . z = { Ringz. 0.ar(Impulse. wakeUp.ar(Impulse.quant = [1.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_04 x = { Ringz. y = { Ringz.play. the synthdef is built. 0. y. When using node proxies with patterns. sent to the server who sends back a message when it has completed.05) }.3]. offset]. the patterns are played using the clock as a scheduler.8) }. setRates.ar(Impulse. 2).05) }. 2).ar(1). 0.ar(1). 0. z.play(quant). one can provide a clock for a whole proxy space: p. 0.end. 0.

// pattern uses tempoclock p. x.tempo = 2. \freq.2. the ProxySynthDef class variable sampleAccurate can be set to true: // example ProxySynthDef. NodeProxy uses a normal Out UGen for writing to its bus.0).clock.clock. // impulse uses tempo x = Pbind(\instrument. which creates an instance of TempoBusClock together with a node proxy ( tempo) which it keeps in sync. \default. 917 . 0.05) }. 400].kr). Pseq([300. // create a new tempoclock with 2 beats/sec y.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_04 c) connecting client and server tempo a ProxySpace has the method makeTempoClock. // set the quant back to 1 and the offset to 0 y = { Ringz. y. 600. If sample accurate playback is needed (OffsetOut). // set the tempo to 1 p. // set the tempo to 2. inf)). d) sample accurate output for efficiency.ar(Impulse.ar( tempo.play.makeTempoClock(2.0.sampleAccurate = false.free.quant = 1.tempo = 1. p.free.2 x.

03. p.perc(0.Where: Help→JITLib→Tutorials→Jitlib_basic_concepts_04 // the grain frees itself x = { SinOsc.stop.001.play.do { arg i. (0. r.spawn. } }.rebuild.005). previous: [jitlib_basic_concepts_03] 918 . x.wait.wait. // steady tone. x.ar(800) * EnvGen.clear. 0. ( r = Routine{ loop { 200.sampleAccurate = true.4). // remove all.ar(Env. 0. // jittery tone. 1. because sample accurate. }. ) ProxySynthDef. doneAction:2) }.

some very little. a = SynthDef(\name..source = . some more... a. ProxySpace. This is also important if you want to automate certain processes . a.push.rebuild // this rebuild is also used when setting one of the following properties: server. A) rebuild and send: manual rate the following code requires a rebuild and send of a SynthDef and is thus most cpuexpensive. it is shown here more in detail.hand-use) for automatisation it is better to build a synthdef and assign it a = { someUGenFunction }.. To prepare such an object for playing.put(0. C) a = NodeProxy. are equivalent in cpu load. a. { someUGenFunction }). different objects require different preparation..add(.. As working with the placholders does not show directly which actions take hardly any calculations and which are expensive.Where: Help→JITLib→Tutorials→Jitlib_efficiency ID: 269 Efficient coding with NodeProxy NodeProxy (and. // the same applies to rebuilding the graphs: a. setRates B) starting synths and tasks 919 . others are much more efficient (B.) is equivalent to a = . though fine for slower use (esp.. placeholders for all kinds of sound producing objects that are able to write to a specific bus on the server. bus...some things in this library are not meant to be used in certain ways (A) and better solutions should be used instead then.. args).) a[0] = . a = Patch(instrname. a[0] = . in disguise ProxySpace) represent "pronouns"....audio.

400. a. it is better to use // the above or a lag in the synth.lineAt(key).. \dt. a = Routine({ loop({ s..) a.sendMsg("/s_new". .. so if automated.set(\freq..) a. which is load mainly on the server and depends on the characteristics of the synthdef: a = \synthDefName. // if you use the same key with a different value. the mapping bundle of the proxy is cached // for the following the bundle is recalculated if a new key is assigned.. a. a.line.map(\freq. lfo). a.unmap(\freq).) // directly sends a message.unset(\freq).)..) a.fadeTime = 2.refresh.fadeToMap(a map) // synthdefs for these things are on the server already. \freq. a. name.xlineAt(key) C) sending messages to running synths: for these the least calculation has to be done a.2).env. a. the bundle is modified a. // the synthdef is already on the server a = Pbind(\instrument.. a.)}) }). a.. name.nodeMap_(a map) a.send(. 920 . // if running the bundle will be recalculated a..xline // some more calculations have to be made on client side.xmap(. a. 0. a.. a. // waking up a stopped proxy does not require a resend these resend the synth with new properies a.sendAll(. ..xset(.gate.Where: Help→JITLib→Tutorials→Jitlib_efficiency the following code sends commands to the server to start synths.wakeUp..

ar(740. 0. 0.15). it is about as efficient as (B) .local. 500).play.read( s3).push(s.set(\freq.gateAt(key) // for avoiding bundle recalculation you can directly talk to the group. s1 = { Blip. //now you can also crossfade audio efficiently: 921 . //resetting the source stops reading mix = \default.1)) }.boot). 0.Where: Help→JITLib→Tutorials→Jitlib_efficiency a.5) }.ar(Rand(32.first example (setting a defname) it works only for 1 or 2 channels right now. ( s = Server. s2 = { SinOsc. 100. mix.ar(1).2.1) }. mix.1) }.ar( mix.group. mix. switching audio control rate sources can be easily and efficiently switched using map or xmap. out = { Pan2. s3 = { Pulse. // this setting will not be kept when you exchange the synth a. 0. p = ProxySpace.ar(140. ) out.kr(-1. 0. MouseX. here is an example of how already running audio rate inputs can be switched.read( s1).read( s2).

600. s3: s3) ).2) }.3). s3].read( s2). 2) }. mix.2.2. }). 0.ar( freq. s1 = { Blip. mix. you can add the inputs to the mix nodeMap parents: mix. // to avoid this. loop({ dt = rrand(0.2) }.read([ s1.choose).fadeTime = 1.parents. 0.2.kr(200.ar(60.fadeTime = dt. 0.stop.kr.1) }. 0. 0. 0.ar( freq. 0.kr * 0. mix. // note that when restarting out. s2 = { SinOsc.Where: Help→JITLib→Tutorials→Jitlib_efficiency mix.3. dt.nodeMap.5. 922 .1) }. 0.01. s2: s2. t.putAll( (s1: s1.ar(105. t.read( s3). the inputs have to be woken up. 0. 0. s3 = { Pulse.1) }. 0. s3 = { Pulse.wait. }).1) }.read( s1). // automation: ( t = Task({ var dt.ar( freq.kr * 0. mix. ) s2. freq = { MouseX. s2 = { SinOsc.play(SystemClock). 10. 100. // change the sources meanwhile: s1 = { Blip. mix.ar(350.

s3].task = Routine({ loop({ mix. [0.01.Where: Help→JITLib→Tutorials→Jitlib_efficiency // also the task can be added to the proxy: ( mix. mix. s2.1).fadeTime = rrand(0.read([ s1. }). 0.4]. ) 923 .choose).2.wait.choose. }). 0.

boot). 1. \freq. 1980. out. SinOsc. // note that you can use this functionality also when using ProxySynthDef directly: d = ProxySynthDef("test".Where: Help→JITLib→Tutorials→Jitlib_fading ID: 270 Fade envelope generation and crossfading NodeProxy (ProxySynthDef) looks for inner envelopes in your definition function to find out whether a fade envelope is needed or not. In case there is no other inner possibility of freeing the synth. if one wants to use a self releasing synth or a different out ugen: e) own responsibility: if the function creates a ugengraph that can be freed by trigger or other things.send(s).play. s. so in most cases. 340).. just these two points ar important.push(s. 1.ar(freq) }). either a) a fade envelope is created (audio / control rate output) b) the synth is freed directly with no fading (scalar output or doneAction 1) c) if you provide a gate arg and a doneAction 2 to your ugenGraph function. 924 . { arg freq=440. "test". p = ProxySpace. f) own out channel with ’out’ arg: the control ugen with the name ’out’ is set to the output channel number of the proxy. this is supposed to be a fade envelope for the synth d) if a synthdef name is used.sendMsg("/s_new". there is not much to worry about. it waits for this action instead of the node proxy freeing the synth. case c) is supposed ..

s.ar([1.0. // for a scalar output also no fade env is created. ) b) automatic free instead of crossfade // inner envelope that cannot free the synth.sendMsg("/n_set". SinOsc. t_trig) * PinkNoise.1]) }. ) out. ) ( kout = { PinkNoise. 240).0.ar(Rand(440.1]*400) }. the synth is freed when a new // function is assigned.set(\t_trig.kr(Env.ar([1. \gate. 1). ) c) custom fade envelope // when a gate arg is provided. 1980.sendMsg("/n_set".ar(0.1]*0.group.1) }. a) automatic fade envelope generation // no inner envelope and audio / control rate output ( out = { PinkNoise. 1980. t_trig) * SinOsc. ( out = { arg t_trig. this envelope 925 . \freq. ) out.ar([1.1]*0.group. but the synth is freed (without fading) ( out = { Out. 1).asr. 1980. s. and the env can free the synth.Where: Help→JITLib→Tutorials→Jitlib_fading s. EnvGen. 4). EnvGen. 0).asr.550).set(\t_trig. ( out = { arg t_trig.sendMsg("/n_set". \fadeTime.kr(Env.kr([1.2)) }.1) }.

Out.550)) }. Formant. an out input and can free itself. // with no further significance ( 926 . ) // you can also provide a fadeTime arg. { arg gate=1. 200. Formant. out. ) d) SynthDef name assignment // if a symbol is used as input.40).1]*Rand(440.asr. 10) * EnvGen. the defname of a def on the server is supposed // to represent a SynthDef that has a gate. out. gate. fadeTime=1. ( out = \default. 10.kr(Env. out. 0. as a symbol carries no channel information! (in all other cases the number of channels is wrapped or expanded to fit the proxy) // if the synthdef has a fixed duration envelope. ) // this is the minimal requirement arguments for such a use (similar to Pbind) ( SynthDef("test".asr(fadeTime. gate.kr(Env.Where: Help→JITLib→Tutorials→Jitlib_fading // is supposed to be the fade envelope for the synth: ( no extra fade env is created. Out. ) out = \test.ar(out.ar([1. 600.1. whic is set by the proxy: ( SynthDef("test".ar(Rand(20.send(s).ar(out. doneAction:2) * 0. doneAction:2) ) }). { arg gate=1. doneAction:2)) }). out = { arg gate=1.kr(Env.fadeTime).ar(300. note that the number of channels is your own responsibility when using symbols. EnvGen. gate.fadeTime = 3.asr.2) * EnvGen. there is a FAILURE /n_set Node not found message.send(s).2 * SinOsc.

set(\t_trig.set(\t_trig.6) * EnvGen. doneAction:2) ) }).group. { arg gate=1.Where: Help→JITLib→Tutorials→Jitlib_fading SynthDef("test".asr. gate. ( out = { arg t_trig. PinkNoise.1]) }. 0. ) out.kr(Env.ar([1.group. doneAction:2) * PinkNoise. ) out = \test.ar(Rand(20. //end it out. EnvGen. f) own output responsibility // the arg name ’out’ can be used to output through the right channel. // of course with this one can get problems due to a wrong number of channels 927 .40). e) own free responsibility //inner envelope that can free the synth. //end it again // if there is a ugen that can free the synth.perc.ar(out.send.set(\t_trig.1]*0.3). FreeSelf. //start a new synth out. }. 600. 1).kr(Env.group. no extra fade env is created either. 1). ) out.kr(t_trig). // but it supposes the synth frees itself. 1). no extra fade env is created: ( out = { arg t_trig. out. so if a new function is assigned it does // not get freed. t_trig. 10. Formant.send(s).ar([1. Out.

ar(out.1)) } ) //this plays out into another adjacent bus: ( out = { arg out.0.ar([10.0. 10].0. //left speaker ( out = { arg out. Impulse.0.1)) } ) //both speakers ( out = { arg out. OffsetOut. 10]. OffsetOut.0.Where: Help→JITLib→Tutorials→Jitlib_fading // or deliberate hacks. this is a possible source of confusion.0. 10.ar([10. Impulse. OffsetOut.1)) } ) 928 .ar(10. Impulse.ar(out.ar(out.

a server window can be created: s. clientID). NetAddr(hostname. I’ll try to add solutions here. This can be done by: in OS X: SystemPreferences>Date&amp. 1) using ProxySpace with more than one client. a network name port the port on which the server is listening. default is 57110 clientID for each client (each sc-lang) a different integer number has to be given see [Server] b) from each client. port). if you cannot sync the time. Time automatically" to true. // this will initialize the tree and start notification // if needed. or if you have a name resolution. a) boot the (remote) server and create a local model (you cannot directly boot a remote server instance) s = Server("serverName". you can set the server latency to nil. before you start: remember to synchronize your system clocks. The clientID argument can be left out then. initialize the default node and set notify to true: s.makeWindow. only step (a) and step (d) are relevant.Time: set"Set Date &amp. with separate bus spaces Note: if only one client is using a remote server. serverName can be any name hostname is an ip address.Where: Help→JITLib→Tutorials→Jitlib_networking ID: 271 networked programming please note any problems.boot. This will break the pattern’s functionality though. in linux: set the ntp clock a local time server is better than the apple time server. 929 .

s. n = n. with a partly shared bus space step a. shared1. so the easiest is to increase the numberOfParticipants by one.asInteger * s. 2) using ProxySpace with more than one client. increase the number of busses in the server options before booting: (s.ar(2). just take care that the shared busses are taking number space already. skip (d) c) before allocating a number of busses for each client.clientID.alloc(n). // or other names. 930 .) ( var numberOfParticipants. s.floor.alloc(n). n = n.numAudioBusChannels / numberOfParticipants.audioBusAllocator. then do (c) like in (1).asInteger * s. n. create shared busses: p = ProxySpace.Where: Help→JITLib→Tutorials→Jitlib_networking c) preallocate a range of busses in each client.controlBusAllocator. b like in (1).clientID.push(s). so no overrun happens. numberOfParticipants = 4.options. shared2.numAudioBusChannels = 1024.floor.numControlBusChannels / numberOfParticipants. n = s. n = s.kr(1).options. sharedkr. ) d) now create a ProxySpace from the server: p = ProxySpace.push(s).options. If there is conflicts.ar(2).

Where: Help→JITLib→Tutorials→Jitlib_networking 3) writing a chat see example in[Client] see also [Public] 931 .

out = { Pan2.ar(Dust.set(\rate.8.Where: Help→JITLib→Tutorials→Proxyspace_examples ID: 272 proxy space examples preparation of the environment ( s = Server.kr * [0. 932 .2) }. the crossfade envelope is created internally.2). 1.ar(40+[0. 0.local.ar(Saw. Pan2. 0. out.ar([443. 0. out = { SinOsc.ar(2000.1) * Pulse. ) playing and monitoring // play some output to the hardware busses.kr * [1.ar( lfo.1.kr(rate)) }.play.0. this could be any audio rate key. referencing between proxies lfo = { LFNoise2. 600-Rand(0.5) }. setting the node controls out = { arg rate=2. 0.ar( lfo.2) }.125]. out = { SinOsc.boot.2) }. 1).push(s).ar(PinkNoise.2].ar(PinkNoise. 30). out = { SinOsc.ar(0.ar( lfo.ar(0. LFClipNoise.0. 0.0. Pan2. s.kr(30.15) }.ar(60*[1. 0. 300. 0. 500) }.1) + SinOsc.set(\rate.kr(rate)) }. out = { arg rate=2. 0. out. 0. 2). [1200. p = ProxySpace.2]. out = { Resonz. 408]*0. 0. LFClipNoise.1].200)]. LFClipNoise. 0.kr. out = { SinOsc.ar([400.1.1).1). 0. out.kr(2)) }. 1600]. // replacing the node.

kr(0. 300) }. 0. lfo = ( lfo3 / 50). 1) }. lfo2 = { SinOsc.2].5. 4*pi). 100) lfo = lfo2. 80. 600. }.ar(2). 0. }.99) }.4) }.abs. 0.Where: Help→JITLib→Tutorials→Proxyspace_examples lfo = { LFNoise1.stop. math // unary operators lfo2 = { SinOsc. 0.5.kr(0. waking up a network of proxies // hit cmd-.kr(0. 0.1 * lfo3 = { Mix( lfo2. 100) // binary operators lfo3 = { LFTri. // free all node proxies out. currentEnvironment. 0. lfo = lfo = lfo2 + lfo3. 330]. 0.kr(30. lfo3.2]) }. lfo3. out. to stop all nodes feeding back (one buffer size delay) out = { SinOsc.ar(2) * 0. // there is no immediacy: out = { Impulse.sin * 200 + 500 * { LFTri. 600.ar(1 ! hear the buffer size cycle 2) + ( out. 200. out = { SinOsc.free. 1.reverse * LFNoise2. // supercollider ’differential equations’ 933 .ar( lfo.1) lfo = 410.kr( lfo.kr * [1. 1.0015. }.play.kr(1. 40) + SinOsc.1. // start again out. // free the playback synth.kr(0.kr * 0. 0.5.3.ar([220.kr * [1. 500) }.kr / 90. 0.

z = Slope. zz.kr(2)) }. 0. 0.ar(Dust. 1)) * 0.01. 0. LFNoise0. Array.410).ar(Pan2.1) }.ar(array + freqOffest.names(\array). 2000)). SinOsc.ar(ctl + freqOffest. 553.ar( out.ar(z). 0. 580 ].1 + Decay2.ar(600).kr(Array. 400.ar(Mix(SinOsc.ar(Slope. array = #[ 997.kr(1000. 506. 777. // a simpler short form for this is: ( out = { arg freqOffest=0.Where: Help→JITLib→Tutorials→Proxyspace_examples out = { SinOsc. var ctl. 0.ar(600.setn(\array. ( out = { var z.ar(Mix(SinOsc.1) }.kr(-1.ar( out. 0.ar(Rand(300. ctl = Control. MouseX. out.rand(8.ar(zz * 410) * 0.ar) * MouseX.1)).map(\freqOffest. 18000.05).set(\freqOffest. 400.200)). rrand(300. out. ) mixing out1 = { SinOsc.1 / 8)). 934 .kr(2)) }. 891.ar(100. 1000)). Pan2. 0.ar). } ) multiple control ( out = { arg freqOffest. Pan2. 0. ) out. 0. 0.1 + SinOsc.exprand(8. 731. z) * SinOsc. LFNoise0. zz = Slope. lfo). 925.1 / 8)).

0.ar(600. 0. 0.1) }. and frees its bus for more on the proxy slots see: [jitlib_basic_concepts_03 ] 935 . // this neutralizes the proxy. 0.free.1) }. 0. 0.1) }.ar(400. // removing: out. out2.Where: Help→JITLib→Tutorials→Proxyspace_examples out2 = { SinOsc. 0. out = out = out1 + out1.free.2.add({ SinOsc. 0.removeLast. // or with direct access: out[1] = { SinOsc.send. out. 0. out. // this sends at index 1 only out. // cleaning up.clear. 0. restoring / erasing out. // this frees the group.1) }). 0.1) }. out3 = { SinOsc. // another way is: out = { SinOsc.add({ SinOsc. 0.ar(400 * 1. 1).1) }).ar(500. 0.2.send(nil.removeAt(0). out. // resends all synths out. 0.ar(400.ar(500. out.ar(500 * 1.send.1) }. out = out2 + out1 + out3. freeing the bus: out. out[2] = { SinOsc. not the play synth x out.

[key. 400) }. p.1) }. proxy.play .isPlaying]. lfo is kept. // the rate is guessed as far as possible. proxy.postln }.reduce.kr or . // lfo = { LFNoise2. 0.ar also a name that is not yet used. as its parents. out. // because they might be used again at any time. // to remove everything else: p.clean.play. // all monitoring proxies (in this case out) are kept. // this shows how to free unused proxies.kr * 2.ar( freq. // after out is stopped. 220) } 936 . p. equivalent: p. out) are kept.keysValuesDo { arg key. [key. // empty space.kr(115. out2.stop.Where: Help→JITLib→Tutorials→Proxyspace_examples garbage collecting // often there are proxies playing that are not used anymore . 0. p. it is removed. 0.postln }.postln. execution order // you can .this is good. // all monitoring proxies (in this case p.kr(3. 160. 0.clean. 0. sin( lfo.kr / 10)) }.reduce(to: [ out]). out = { Pan2. such as out1. 70. // play some key (audio rate is assumed) // the rate is determined from the first access: // like this lfo becomes control rate myOut = { SinOsc. p. freq = 900. proxy. proxy. too: out. freq = { SinOsc.ar(SinOsc. // stop monitor p. on this topic see also: [the_lazy_proxy] myOut. p.isPlaying].2).play.kr.keysValuesDo { arg key.ar( lfo.postln.postln.

ar(Rand(800.1) }.1.1].1.1]. \ffreq). 0.ar(115.1.play. 0. 0. out. out = { SinOsc.ar( otherFreq.set(\ffreq.fadeTime = 0.1].0)*[1.01.clear.play. // remove the setting out. out.stop.1) }.set(\ffreq.Where: Help→JITLib→Tutorials→Proxyspace_examples myOut = { SinOsc.1.rand2). 0. 0. 300. 0.2) }. 30+20. out = { arg freq=500. \freq.rand2.1) }.set(\freq.1]. currentEnvironment. out = { SinOsc. 0. SinOsc.1) }. 400+100. // release the synths and the group with a given fadeTime without changing proxy time out.unset(\freq.clear) setting the xfade time out. 220) }.free(3). out. pi). (same: p. 0. out. 0.1].rand2).ar(freq*[1. out. 500 + 200.ar(ffreq. 400+100.1. ffreq=120. 0.0)*[1. 70. out.ar(Rand(800.rand2). out = { SinOsc. // argument settings and mappings are applied to every new function 937 . 300.set(\freq.rand2). 0. 30+10. 0. 300. 300.ar * 2. // clear every proxy in this environment and remove them.fadeTime = 4. // stop monitor setting and mapping arguments out.1) }.ar(Rand(800. 0.ar(Rand(800. otherFreq = { SinOsc. out = { SinOsc. out.0)*[1.0)*[1. SinOsc.

\tr).2) }. out.3. 0. 100.1) }. pi). 200) }.4. out = { arg freq=300. out. 0. 30. Pulse. 0.kr(3. dt=1. a nodeproxy control this rate is used for each function passed into the proxy.fadeTime = 2. out.ar(ffreq. 30.1.xset(\freq.ar(7000*[1. 1).set(\trig.3. so the node proxy does not store the new value out. 0. ffreq=20. 800.scramble. 0.kr(0. // argument rates: just like a synthdef has input ’rates’ (like \ir or \tr).xmap(\ffreq. 0. \dt. BPF. \dt. // can be given a rate. lfo). 0. lfo3). 0. 80.1. 9000). 0.kr(trig. // equivalent to out.Where: Help→JITLib→Tutorials→Proxyspace_examples out = { arg freq=100. \dt. 0. SinOsc. 0.2).ar(LFSaw. SinOsc.2])) } out. 200) + FSinOsc. out = { arg freq=300.ar(freq*[1.group. 938 . 0. 0. out. inf) / 3. out. 10) }. 0.1].setRates(\trig. 2).set(\trig.1.ar(ffreq)*ffreq. ffreq=20. 100) }.ar(SinOsc.group.13. 500].kr(0. rrand(400.ar(ffreq. // lagging controls: out. 0. dt) * Mix(SinOsc.kr(0. out.1]+ SinOsc. 0.xset(\freq. ffreq=20. 1).map(\ffreq. // mapping to other proxies lfo = { SinOsc.kr(10. SinOsc.lag(\xfreq. Decay2. lfo2). // crossfaded setting and mapping: out. 700)).1). out = { arg freq=300. 1). lfo2 = { LFClipNoise. out. 0.setRates(\xfreq.2. freq. 400. 0.set(\trig. SinOsc. 0.3. ffreq=20. freq). 1. out.01.ar(freq. 100) }. 600]. // set the group.3.31).2) }.1). lfo).ar(freq*[1. 0.xmap(\ffreq. // trigger inputs out = { arg trig. 0. lfo = { FSinOsc. pi).1.1) }. lfo3 = StreamKrDur(Pseq([Prand([530. 700. fadeTime is used lfo = { FSinOsc.xmap(\ffreq.group.1.1].ar(ffreq*[1.

\xfreq. xfreq=700.lag(\xfreq.set(\trig.set(\trig. 1. 0.9000)). 1. just as it does in SynthDef _____________________________________________________________ other possible inputs using a synthdef as input // for a more systematic overview see: [jitlib_fading] // you have the responsibility for the right number of channels and output rate // you have to supply an ’out’ argument so it can be mapped to the right channel. \dt.1. \xfreq. rrand(2000.set(\trig. dt) * Mix(SinOsc.01).set(\trig. \xfreq. out. \dt.9000)). 0. // note that the same works with the i_ and the t_ arguments. 0. out. rrand(2000. 0.2. rrand(2000.setRates(\trig. rrand(2000. 0.group. \dt. 939 .Where: Help→JITLib→Tutorials→Proxyspace_examples ( out = { arg trig.1. 0. 0. 0. \xfreq.group. 1.set(\trig.5.9000)).group.ar(xfreq*[1.2])) }.group.group.1. 0. 1. out. out. \dt. rrand(2000.1. \xfreq.9000)). Decay2. dt=1.group. 0.set(\trig. rrand(2000.play.1. 1. \dt. 1.1.9000)).kr(trig. // changing the lag. \dt.3. out. out.9000)). // removing the trig rate: out. ) out.01. nil). \xfreq. the synth is reconstructed with the new lag: out.

0. 800).03).1). Out. 0. 500]. 0.ar(Dust.asr. 0. // if the synth def is in the synthdesc lib (. // if you supply an envelope that frees itself. Rand(f0. 0. 800).1.2) * EnvGen. 0. evaluate this several times SinOsc. out = SynthDef("w".0. ( out = SynthDef("w". 600). gate=1.kr(Env. 800)]. Out.store) its gate is detected.ar(out.send(s). { arg out. // using this method. ) out = \staub.01. ( SynthDef("staub".1].ar(out.kr(Env. 0.2)) }). { arg out=0.ar(out. no bundle is sent to free it ( out = SynthDef("w". { arg out=0. 600]. doneAction:2) ) }). Rand(1. { arg out. 3) * 3000*[1. Ringz. it can be assigned by name. f0=430. as the def is on the server already. 0. SinOsc. 0. ) 940 . ) // once the SynthDef is sent.2)) }). 0. Out.ar(15).ar(out. 800)]+lfo.ar(out.perc(0.ar([Rand(f0. Out. a gate argument should be // provided that releases the synth.Where: Help→JITLib→Tutorials→Proxyspace_examples out = SynthDef("w". gate. 600).SinOsc. doneAction:2)) }). { arg out=0.ar([Rand(430. Out.2) * EnvGen. lfo. // if you supply a gate it fades in and out. (doneAction:2) // this is very efficient.asr(1. gate. gate=1.ar([Rand(430.001) * EnvGen.kr(Env. Rand(430.SinOsc. doneAction:2) ) }).ar([Rand(430.

Where: Help→JITLib→Tutorials→Proxyspace_examples out. 0. Out. Rand(-1. out. env = Env. 1000*[1.store. out=0. 1. ffreq=800. EnvGen. out = nil.0.ar( Formant.0.5).1.wait.ar(WhiteNoise. out = 0.1].0)) ) }). 0. doneAction:2)). the synth is // freed and not released. // removes object and stops it. amp. ( SynthDef("staub".store.asr(0. detune=0.rand]).kr(env. 5000]).ar(0. ffreq. freq=440.play. 30. // store the synth def so it is added to the SynthDescLib ) out = \staub. { arg out.spawn([\f0. Pan2.do { out.01). out = \staub. ) out. using patterns // example ( SynthDef("who". // now out plays continuous stream of zero.spawn. 0.spawn([\f0.ar(out. Out.ar(freq + detune.01. { arg amp=0. // the proxy can determine whether to release or to free the synth.ar(out. // so if there is no ’gate’ arg provided and the def has a desc. Ringz. 5000 + 1000. var env. } } // when the synth description in the SynthDescLib is found for the symbol. // watching the synth count shows that the old synth is freed.001)) }). 941 . fork { 5.1. gate=1. gate.

inf). 400.pi). 300. 1) }. 0.default. ( out = Pbind( \instrument. \who. \who. 100. 800.125]*0.1. 15500. 942 . 1500) }. \legato. 0. 0. // use it in a pattern \dur.kr(100. 700)] } // btw: setting the clock will cause the pattern to sync: p. \ffreq. lfo = { MouseX. 700) }.2. 10. lfoStereo. SinOsc. 10).kr(SinOsc.75.. etc.inf). 400.kr(2. Pseq([ lfo. // embed a control node proxy into an event pattern: // this does not work for indirect assignment as \degree. lfo = { LFNoise1. 0. // 2 channel control rate proxy out = Pbind(\instrument. // multichannel expansion of the events: multichannel control rate proxies cause lfoStereo = { LFNoise1. \ffreq. 1].2. Rand(0. 10). 1). \detune. \who. these can be done in the SynthDef.kr(100. Pseq([500. 1500. 0. // so this functionality is still standard // works only with control rate proxies. inf) ). lfo. 0. 1500) }.kr(0. \freq. 500.02).kr(SinOsc.02). \legato. \ffreq.5. [600.02). 1300.4. ) // note that when you use a proxy within a non-event pattern it gets embedded as an object. 700) }. 0.kr([1. \who. 100.kr(0. 400. \freq.Where: Help→JITLib→Tutorials→Proxyspace_examples out = Pbind(\instrument. \legato. 601]. 0. 380. lfo. 10. lfo = { SinOsc. 550]. 0. 1300. lfoStereo = { [MouseX. 5500. out = Pbind(\instrument. \freq. \freq.kr(5. \legato. 0. \midinote. // because there is calculations in the event! if needed.clock = TempoClock. Pseq([1. 300]. lfo = { SinOsc. 0.

// store an instrument ( Instr(\test. \dur. doneAction: }. 100. inf).ar(freq. 2. ffreq. 3000] + 170.ar(SinOsc.0. 300.3) * EnvGen.tempo = 1.1]*0. rrand(5000. 390.fadeTime = 3.02) } ).0).125 * [1. [1.0 // patterns also crossfade. 300]. 2/3]. 100.ar(Dust.clock. Pan2. ) out = Patch([\test]. pan) 943 . 200. ( out = Pbind( \instrument. 8000)]). 0. { arg dens=520.kr(env. lfo. 510. \ffreq. 300. \legato. 2. Pshuf([ lfo.Where: Help→JITLib→Tutorials→Proxyspace_examples p. [10. p. 0.5pi. ( out = InstrSpawner({ arg freq=1900. 0.0. ) using instruments and players // note that you’ll get late messages (which don’t cause problems) // pause and resume do not work yet. 550]. 2). Ringz.1).clock.tempo = 2. 3.[ Prand([1500. 800.1. 0.env. \freq.rand2.choose ).0. Pshuf([500. 380. \who. inf).ar(dens.inf) * rrand(1. 700.pan. ffreq=7000. if an \amp arg is defined in the synthdef: // (evaluate a couple of times) out. 0.

ar(pmf. freq=800.set(\dens. Out.inf) ].001. 0. // out.Where: Help→JITLib→Tutorials→Proxyspace_examples Env.0.1).ar(u. pi). pmf=1. 500).kr(Env.1]. env = EnvGen.9. 0. u.perc(0.clear.xset(\dens.0.4).unmap(\ffreq). // allow sound object assignment without immediate sending // putting an synthdef into the node proxy without playing it right away // the synthdef has an envelope that frees by itself. pan)) }) ).ar(freq * Rand(0. // does not work (yet). 120).01). ( out = SynthDef("a".play.new({ 944 . { arg out=0.awake = false. // envelope u = SinOsc. _____________________________________________________________ client side routines spawning out.ar(out.04. pan. // create a task to repeatedly send grains ( t = Task. SinOsc. // out. // out.0. 1030).002. var env.set(\ffreq. out. // out. env). Prand([-1.perc(0.doneAction:2). 0.125) ) out. 1. Pan2.

[1. var env.3).stop.start.choose.perc(0. -1.wait.choose. out.start. // set some argument out. freq=800.map(\freq. 0. // change the definition while going along ( out = SynthDef("a".5.set(\freq.spawn([\pmf.9. 600. 700) }.25].1) * 3000 }). \pan. 0.1. 1]. like "t"). // note: if you want to avoid using interpreter variables (single letter. 0. }) }). 0.kr(Env.kr(0. 945 . lfo. t. out. lfo = { SinOsc. 0. 1. 300].0.kr(Dust.kr(0. 0.01. lfo).1.stop.Where: Help→JITLib→Tutorials→Proxyspace_examples loop({ // starts a synth with the current synthdef at index 0 out.ar(freq * Rand([0. 0. { arg out. out.choose]). [0. ) t.kr(1). 0. Pulse. t.set(\freq. lfo = 300.clear.01.awake = true. 600).help) // you can use Tdef for this. (see Tdef.1.doneAction:2).ar(out. 20. 3000.add({ Trig. lfo = { SinOsc.1. env) ) }). env = EnvGen. [0. 4000) }. ) t.1). 300). Out.9]. // don’t forget this // free all synths in this current ProxySpace currentEnvironment.

2. [0.kr(Env.2 ). pan) * env) }). 5. 946 .01. MouseX. ) t. // different filters.fadeTime = 1.1. 0. 1)) }. 0.play. -1].choose.wait.choose * 0. 1).1) }. ) // a target for the grains someInput.2). pan.003.0.2.ar.ar( someInput.001. MouseX.kr(0.ar(2). // initialize to 2 channels audio ( t = Task({ loop({ s.Where: Help→JITLib→Tutorials→Proxyspace_examples granular synthesis: efficient code see also [jitlib_efficiency] out. 0. out = { BPF.index. out = someInput.doneAction:2). [1.ar(FSinOsc.perc(0. }) }).0. out. \i_out.ar( someInput. 0.ar(Rand(1000. Out. { arg i_out = 0.10000)). var env. 1.kr(100. env = EnvGen.play.ar(i_out. ( SynthDef("grain".ar(2) > 0).-1. out = { CombL. 0."grain". 18000. // returns the bus index of the proxy \pan.02]. Pan2. someInput.send(s).0. 0.sendMsg("/s_new".ar * (LFNoise0.

ar. 0.kr(3.ar. q = ProxySpace(s).ar(0.5) }. 1000.use({ out = { Resonz. 1000.stop. 2000) }.clear. t.ar( someInput. 1040).stop. // quit server: s.05) }.pop. // create two proxyspaces without a running server ( p = ProxySpace(s).Where: Help→JITLib→Tutorials→Proxyspace_examples out = { RLPF. 947 . // restore original environment _____________________________________________________________ using multiple proxyspaces note that this can be done while the server is not running: with p.kr(1.ar( in. in = { WhiteNoise. 0. currentEnvironment.kr. freq = { LFNoise2.01) }. ProxySpace.quit. p.play the environment can be played back. }).wakeUp or p. freq. LFNoise1. //_________ out.

kr. 400.5) }). 0.ar * 450. // adding a synth at index 1 // equivalent to q.use({ in = { Dust. 0.kr(1.1) }.aiff").ar(20. 0. 0. { Impulse. out = { Resonz.Where: Help→JITLib→Tutorials→Proxyspace_examples q.use({ freq = }) ) 100 + p[\freq] / 2.005) }.ar(2.play. 2000) }.boot.ar(7.at(\in).play(\out). // out is the default output external access q[\in][1] = { Impulse. server // play the proxy at \out p. connecting two spaces (must be on one server) ( q.put(1.5) }. 0. freq = { LFNoise2. }). "proxySpace. // start recording 948 . q. ) // wait for the booted s.ar( in.record(\out. freq. recording output (see also: [RecNodeProxy]) r = p. 0.

unpause.Where: Help→JITLib→Tutorials→Proxyspace_examples r.kr(\freq) + LFNoise1. p. freq = 1000.kr(1.close. freq = 400.pop. // stop recording r. p.01) }. q.pause.clear.clear.ar(0. 200. in = { WhiteNoise. freq = 700. // pause recording r. 300) % 400 }. // restore environment // make y the currentEnvironment q.push. push/pop // make x the currentEnvironment p. 949 .pop. // feedback freq = 400. // restore environment q.push. freq = { p.

Where: Help→JITLib→Tutorials→Proxyspace_examples ______________________________________________________________ some more topics nodeproxy with numbers as input: p = ProxySpace. out.boot). a[2] = 20. out = { SinOsc.fill(proxy. // these add up: a[0] = 440.kr(30.push(s.kr(out. a. // now there is a crossfade.1) }. { the number })) * EnvGate.kr(5. a[1] = { SinOsc. 2).play. 0. { arg out. 950 .numChannels.ar( a. 145) }. // internally a numerical input is approximately replaced by: // (pseudocode) SynthDef("name".kr * Rand(1.new(fadeTime:fadeTime) ) }).fadeTime = 2. a[1] = 220. 0. a[0] = 300. Out. 0. fadeTime. 0.kr(Array. Control. a = 900. a[2] = { SinOsc. 20) }.

Where: Help→JITLib→Tutorials→Proxyspace_examples 951 .

ar(freq). if present. doneAction:2) ) } ). sustain=0.5.boot. such as a cloud of short grains. SynthDef("noiseGrain". ( s. Furthermore. 952 . Its function is evaluated in the context of the outer environment (see [PlazyEnvir] ) which should return a pattern or a stream.sine(sustain. window = Env. freq=800. var window. Out. when the event type \phrase is passed in. so that structures like a cloud of clouds can be constructed.ar(window. this scheme can be applied recursively. the event looks for a pattern in Pdef. { arg out = 0.all if it can find a definition .if it finds one it plays this pattern in the context of the outer pattern’s event.store. pan ) * EnvGen.001.ar(out. If there is no definition to be found there. pan = 0.ar( SinOsc. Pan2.Where: Help→JITLib→Tutorials→Recursive_phrasing ID: 273 Recursive phrases and granular composite sounds Pdef can be used as a global storage for event patterns. it uses a SynthDef with this name. When passing a function to Pdef it creates a PlazyEnvir internally. SynthDef("pgrain". amp=0. Here a way is provided by which these definitions can be used as an instrument that consists of several events (a phrase). amp).

sustain=0.ar( Ringz.value. freq=800. amp). 2. 5 ) }). Pdef(\sweep3.ar(out. 953 . amp=0. { arg freq=440. Pseq((1. n=8. { arg sustain=1.perc(0.3. Pdef(\sweep2. Pan2. sustain. sustain. 1.5. freq=440.. Pbind( \instrument. 2 ) }). 0.value / n. n=8. has to be evaluated * ratio + 1 * freq. \freq.Where: Help→JITLib→Tutorials→Recursive_phrasing { arg out = 0.1.scramble) * ratio + 1 * freq. \dur. has to be evaluated \freq. Pseq((1.002. Pdef(\sweep. \pgrain. \recursionLevel.store. window = Env. freq.001. ) }) * freq. \phrase. \dur..3) \dur. pan = 0.ar(PinkNoise. \instrument. sustain. pan ) * EnvGen. ratio=0.n). \freq.1).ar(0.n)) ) }). Out. \sweep. freq=440.6).8. doneAction:2) ) } ).1. \legato. Pbind( \instrument.value / n.ar(window.3.value // freq is a function. \n. \noiseGrain. Pbind( \type. { arg sustain=1. 1. var window.value. ratio=0. // sustain is also a function. Pfunc({ rrand(0.

\sweep3. 15.Where: Help→JITLib→Tutorials→Recursive_phrasing // the pattern that is found in Pdef. inf) * 0. [0. Pseq([1. // phrase event from global library \instrument. -0. inf).4.1]. \ratio. Pseq([1.02]]. \default.1]. 0.1. inf).03. 10]. \pgrain.5]. \sweep2. [0. 0. 15]]. 0. Prand([ 0.play ) // various instruments and synthdefs can be used on the same level ( Pbind( \type.1. \pgrain].inf) + Pseq([0. 15. \degree.3.inf) ). Pseq([0. 0. 3]. Pseq([0. 0.all (or your own defined library) is truncated in time // using the sustain provided by the outer pattern.inf) ). \legato. ( Pbind( \type.5. [0. inf). \dur. 0.1. 3. [0. \phrase. 5]. -0. inf). [0. \sweep.play. \phrase. \ratio. inf) ). 1. 4. \n.1. inf). 0.4].play ) // multichannel expansion is propagated into the subpatterns ( Pbind( \type. 2]. 0.1. Pseq([\sweep.7.1] ]. ) 954 . 6. inf). \sustain. 0. 0. 6.5. \n. Pseq(#[0. 3]. Prand([0. \degree. 0. 6. \sweep. 0. 3]. \degree.2. \n. Pseq([4. Pseq([0. inf) + Prand([0. \instrument. \phrase. 25. // phrase event from global library \instrument.

3. 1. 3. 0. 2. // just like with non recursive phrasing. Pfunc(#{ 1.play ) //////// recursion examples ////////// // the given pattern can be recursively applied to itself // resulting in selfsimilar sound structures. // play without changing player state (see [Pdef.Where: Help→JITLib→Tutorials→Recursive_phrasing // of course also a patten can be used directly in a Pdef ( Pdef(\sweep. 1. 5]) * 0. 4. 1. \instrument.inf).play. \pan. 3]. Pseq([0. \sweep. new values override old values. 2). \dur. \phrase.05. like lindenmeyer systems (see also Prewrite) // special care is taken so that no infinite loops can happen. Prand([0. 1b].5. \legato. 955 . Pbind( \instrument. Pdef(\sweep).help) Pn(Pdef(\sweep).5. 1b. 4. emebdded in stream (see Pdef. \noiseGrain].fork. inf). Pseq([\pgrain.help]) // play within a pattern ( Pbind( \type. // any values that are not provided within the pattern definition // are passed in from the outer event. Pseq([1.0.rand2 }) ).inf) ) ) ) // play directly. 2. \degree.

\sweep. \phrase. 0.3].. // now dur is dependant on outer dur.inf). 956 . { arg dur=1. ) // recursion over one level ( Pbind( \type.3. n=4.value / n.8. dur.value ) }). Pseq((0. \pgrain. Prand([1. freq=440. \legato.5). 0 ).play. with legato > 1. \dur. \degree. Pbind( \instrument. ratio=0. Pseq((1. \phrase. ) // no recursion. \sweep..Where: Help→JITLib→Tutorials→Recursive_phrasing ( Pdef(\sweep.play. 2. \instrument. \phrase. ) // no recursion ( Pbind( \type.n)) * ratio + 1 * freq. \instrument. \instrument. not on sustain \freq. \sweep. \degree.0 and varying notes // note how subpatterns are truncated to note length // provided by outer pattern (in this case determined by legato) ( Pbind( \type. inf) ).2.

legato is recursively applied \legato.Where: Help→JITLib→Tutorials→Recursive_phrasing \degree. \recursionLevel..play ) // to block this recursion.play ) // recursion over one level: ( Pbind( \type. n=4. Pseq([0. \pgrain. \degree. 1 ). var legato. \legato. 10]. \phrase. freq = freq.5. ratio=0. assign legato explicitly: ( Pdef(\sweep. \instrument.n) * ratio + 1 * freq) ) }).inf). \degree. Pseq((0..2. inf). 1 ). freq=440. // because freq is calculated internally and overrides degree on the second level ( Pbind( \type. legato. Pseq((1. \sweep.value. 1 957 . \phrase. legato = freq % 200 / 200 * 3 + 0. or modify it. { arg dur=1. Pbind( \instrument. \recursionLevel. \freq. \dur. \instrument. 0. \sweep. \recursionLevel. 2. dur.10). 1. 1. 4. ) // recursion over one level: degree is assigned to each phrase.value / n.5.

2. 3]. -5. \phrase. \phrase.Where: Help→JITLib→Tutorials→Recursive_phrasing ). 3 ). 2].play ) // "zoom" in TempoClock.default. Pseq([1. TempoClock. \n. // recursion over variable levels ( Pbind( \type.0. \sweep. \recursionLevel. \instrument. \degree.default. \instrument. -5. \instrument. inf).2.tempo = 0.play ) // recursion over two levels ( Pbind( \type. \n. \recursionLevel. Prand([0. 2 ). \sweep. \degree. 7.play ) // recursion over three levels with variable number of grains ( Pbind( \type. 3].inf). \sweep. Prand([2. \recursionLevel.tempo = 1. \degree. 1.inf) 958 . 0. \phrase.

0. { arg sustain=1.value) ) }). sustain. 1. \scale. 5.value ) }). ratio=1. Pseq([1. Pseq([-5. Pseq((1. inf).value / n. ratio=1.n)) * ratio + 1 + degree. 2].play ) // replace the frequency based pattern with a degree based pattern ( Pdef(\sweep. \phrase. degree=0. Prand([2. degree=0.. \pgrain.play ) // pass in a synthDef from the outside ( Pdef(\sweep.. { arg sustain=1. n=8. 4. n=8. Pseq((1. 2. \legato.inf) ). ) // drunken master ( Pbind( \type. 10]. \degree. 0. sustain. -2]. \dur. inf). \sweep. 959 .4. 2]. inf). 8]. \degree. Pbind( \instrument.Where: Help→JITLib→Tutorials→Recursive_phrasing ).n) * ratio + 1 + degree.5. 7. #[0. \n. 3. \instrument. Pbind( \dur. \recursionLevel. Prand([0.value / n. \degree.

inf) ). \degree.exprand(0.use { sustain = { 2. \pgrain.0. 3. \recursionLevel. \synthDef. e. -2]. 8].. 1]. Prand([2. \sweep. degree=0. \phrase. 4. 1]. \instrument. \recursionLevel. sustain.play ) 960 .value ) }).05) } }. Pdef(\sweep. inf). 0. \n. 4. 8]. \n. Prand([2. Prand([\pgrain. 3. // replace by some other event \instrument. ) ( Pbind( \type. Pseq((1. \phrase. { arg sustain=1. n=8. inf).value / n.inf). inf).default. -2]. e. Pseq([-5. Pbind( \parent. \dur.inf) ). \sweep. \instrument. ratio=1. Pseq([-5. Prand([0. \noiseGrain]. \degree. 0.n)) * ratio + 1 + degree. inf).play ) // use a different parent event in the inner pattern ( e = Event.Where: Help→JITLib→Tutorials→Recursive_phrasing ) ( Pbind( \type. \default. Prand([0. \degree.

Pbind( \instrument. \degree.play ) use a function to insulate from embedInStream // recursion inside the pattern definition ( Pdef(\sweep2. ) ( Pbind( \type. \sweep.value).value) ) }). n=2. 8. degree=0. ratio=1. n = n. degree=0. \recursionLevel. \dur.inf) ). 5 ] * ratio + 1 + degree. 32]. inf) }. \phrase.. \pgrain. 2 ) }).value. \n. \dur. Pseq([-5. 2. ) 961 . \sweep. \instrument. ratio=1. \phrase. Pbind( \type. sustain. Pseq([ 1. Pseq((1. 0.Where: Help→JITLib→Tutorials→Recursive_phrasing // pass in a pattern from outside ( Pdef(\sweep.value / n. \instrument. sustain. 1].value / n.5). \recursionLevel. -2]. // \degree. 3. 16. inf). { arg sustain=1. { arg sustain=1.scramble * ratio + 1 + degree. \degree. Prand([0. { Pshuf([2. 4. n=8. 4. 3.

play ) // change pattern definition while playing: ( Pdef(\sweep.play ) // instruments do not crossfade while they play (to make phrasing more efficient). 7) ) ) ) // koch "snowflake" ( 962 . inf) ). \sweep2.01. 2b. 2 ). \instrument. \legato. ( Pbind( \type. exprand(0. Pseq([-5.01. 0. \dur. 3. \phrase. 0. Pbind( \instrument. Pseq([0. \n.0). \dur. rrand(5. 4]. 3.Where: Help→JITLib→Tutorials→Recursive_phrasing ( Pbind( \type. 2. rrand(0. \degree. 3. -2]. \phrase. \instrument. 2. \n.1). inf). \sweep. \degree. \octave. \legato. \pgrain.

freq=440. \instrument.play ) ( Pdef(\koch. \dur. \phrase. \legato. 2. 9.1 ).2. \pgrain. Pbind( \dur. 1]) ) }).value / 3.play ) ( Pbind( \type. 2. { arg dur=1. ) 963 .value / 3. \phrase. \legato. freq. dur. \koch. \koch. \recursionLevel. Pbind( \dur. { arg dur=1. degree + Pseq([0. \synthDef. \synthDef. \dur. degree=0.1 ). ) ( Pbind( \type. 9. \freq.Where: Help→JITLib→Tutorials→Recursive_phrasing Pdef(\koch.value * Pseq([1. 1. 1. \instrument. \pgrain. \degree. dur. 0]) ) }). \recursionLevel. 4. 1.

ar(from.linen(0.01. sustain / n ) }) ) 964 . bufnum. { arg sustain=1. n). from=0.0. to. env = EnvGen. Out.wav"). sustain) * BufFrames. 1. Pseries(from.0. 1.Where: Help→JITLib→Tutorials→Recursive_phrasing // soundfile example ( SynthDef(\play_from_to. \from. to=1. step. { arg out.ar(1.0. n=3.01).sendMsg("/b_allocRead".ar(out. n) + step. sustain=1. to=1.0.0.value. sustain. Line. Pbind( \instrument. // this plays it straight ( Pdef(\poch. \play_from_to. step.kr(bufnum) ) * env ) }).0. doneAction:2). sustain = sustain.store. bufnum. from=0. \legato. \dur. BufRd. ) s. var step. step = (to . \to. Pseries(from. var env.0.ar(Env. 170.from) / n. "sounds/a11wlk01. 0.

0.value. \recursionLevel. [\from. Prand([-1. f. \play_from_to. \phrase.series(n. 170 ). 1. \bufnum. inf). from. \poch. 1. 0. step = (to .play ) // now turn round the middle part ( Pdef(\poch. \dur. 1]. \poch. \legato. { arg sustain=1. step]. to=1. \dur. \recursionLevel.0.0. step) +. \from. \to. f = Array. \phrase. t.0. f[i] = f[i]. 965 . Prand([0. inf). from=0.0. sustain = sustain.from) / n.t [0. i = n div: 2. \to. 3.Where: Help→JITLib→Tutorials→Recursive_phrasing ( Pbind( \type. 3. 3. \to].0. Pseq(f). n=3. sustain / n ) }) ) // varying recursion ( Pbind( \type. 3]. var step.reverse. Pbind( \instrument. 1. \from. i. \instrument. \instrument. 2. \dur.

\amp.play ) 966 . Prand([1. 170.Where: Help→JITLib→Tutorials→Recursive_phrasing \n. 2. 0. \bufnum. 3]. inf).2 ).

the default value is used: test. only for its parents. //note that no other proxy should be reading from x when this is done: //for simplicity nodeproxy currently does not care for its children.clear.kr(7) }.isNeutral.kr(1.ar.Where: Help→JITLib→Tutorials→The_lazy_proxy ID: 274 the lazy proxy NodeProxy (and BusPlug) uses a lazy evaluation scheme to derive its appropriate rate and numChannels from the first meaningful input that is assigned to it. //2 krtest. the proxy is neutral: p = ProxySpace. as soon as the first time the source is set.0. //1 the default can be set in the class NodeProxy: 967 . So as long as the source is not set. //the first arg to kr / ar is the default number of channels if no number of channels is passed in. // or in another way: x. it derives its bus arguments from that input x = { Array.kr * b.push. 100) }) }. { SinOsc. for a quick initialisation. x.kr. see [NodeProxy] and [ProxySpace] helpfiles for basic info.defineBus(\control.kr(5) the properties are also set when some other proxy reads from it: x = { LFPulse. also defineBus can be used: x. clear is used: x. 5). 0.rand.fill(14. // x is now 14 channels control rate in order to reset these properties.

f.clear.clear.clear. f. e. 3).defineBus(\audio. f. e. test3. NodeProxy.map(\zzz.defineBus(\audio. f.defineBus(\audio. the rate is converted and the channels are expanded in the ususal multichannel expansion pattern: f. u. // if the number of channels passed in is less.ar(2).clear. control rate is assumed: u.defineBus(\audio).squared + r. f. x. 5).clear. x = e. when unary or binary operations are performed.kr(2).kr. x = e + f.clear. 1). //3 krtest3. 8). x = e + f. x. x. // 13 also if a proxy is used as a map source. the highest rate / numChannels is used to initialize all uninitialized proxies: x.defaultNumControl = 13. if a rate1 proxy is used as rate2 input.defineBus(\control).Where: Help→JITLib→Tutorials→The_lazy_proxy NodeProxy.ar.defaultNumAudio = 3. 968 .defineBus(\control. u).clear. e. x. e. it only uses the first n channels f.

boot).ar(3.1.0)).Where: Help→JITLib→Tutorials→The_lazy_proxy f. src = { SinOsc.push(s. //the wrapping offset is moved accordingly 969 . 5))) }. MouseX.kr(0. 500. 0.ar(Array. 400.ar(Array. 2. 500.play.kr(0. 5)) }. out = { Mix( src. SinOsc.ar(2).1) }. an offset can be passed in as second argument to ar/kr //modulate offset: p = ProxySpace. out.0). out = { src.exprand(5.ar(1. MouseX.rand(5.

12.8 Ugens 970 .

0. offset.5]. 900)) }). In this way it is similar to the In ugen.kr(0. Channel.1). offset. 80).kr(0. For a channel mixer see NumChannels *ar(array. a = Array. }. 1. 20). 1. if wrap is set to true (default) the index wraps across the input array. numChannels. 2. 1800) * [1. 2). a = Array. 2].kr(0. 20).ar(Rand(500. ) ( { var a.fill(8.1) }). Rand(300. numChannels. SinOsc.Where: Help→JITLib→Ugens→Channel ID: 275 Channel output a fixed number of channels of a larger input array that can be moved across. { SinOsc. 2). Channel does not multi channel expand. MouseX. }. 20). }. 0. a = Array.1.1) }).fill(8. wrap) ( { var a.ar(Rand(500. MouseX. 8) * [1. 0.fill(8.play. MouseX.5].play.play. { SinOsc. Channel. { SinOsc. 971 . 1800) * [1. 0. false).ar(a. 0. otherwise it clips.ar(a.ar(Channel. wrap) *kr(array.kr(a.kr(Rand(0. Rand(0. ) // without wrapping ( { var a. 0. 0.

Where: Help→JITLib→Ugens→Channel ) // when the offset is fixed. 5.5] * LFNoise1. ) Note: put is all the input ugens are continously running.ar(a.do({ b = b * Channel. ) ( { var a. 2).01)) }).kr(0.play.ar(Rand(300.ar(a. a. 2) }).play.1 }. 1800) * [1.1 }. Channel returns a fixed array accordingly.kr(0. b * 0. cpu-expensive.01)) }). b. 1. 8.5] * LFNoise1. b. 3. m = MouseX. { SinOsc.rand. 5. This may not be the most efficient way if each in- 972 . 1. so this makes sense only in certain cases. m.fill(8.ar(a. // (similar to Select ugen) ( { var a.do({ b = b * Channel. 2) }). b = Channel.ar(a. b = Channel. 2).fill(8. b * 0. // the othe ugens keep playing. a = Array.ar(Rand(300. 8.kr(0. a = Array.size). 3.rand + m. 1800) * [1. { SinOsc.

array. This may not be the most efficient way if each input is cpu-expensive. Pulse.ar ]. when using fixed values the normalizeSum method can be used to normalize the values TWChoose is a composite of TWindex and Select *ar(trig. [0.ar. TWChoose. 1)).kr(1. which means an extra calculation overhead. 0. 1000.99.05].Where: Help→JITLib→Ugens→TWChoose ID: 276 TWChoose The output is selected randomly on recieving a trigger from an array of inputs.normalizeSum) * 0.ar(Dust.05.ar(MouseX. If normalize is set to 1 the weights are continuously normalized. a = [ SinOsc. a.2 }.ar. 973 . 0. Saw.weights.array. ) Note: all the ugens are continously running.weights. the weights of this choice are determined from the weights array.normalize) ( { var a.normalize) *kr(trig.play.

13 Language 974 .

c=3 # a. // afterwards a=1. 3. 6]. <variable> = <expression> examples: # a. 2. 3. // afterwards a=1. 2. 3. The form of a multiple assignment is: # <list of variables> = <expression> – or – # <list of variables> . c = a + b. 975 . 5. Multiple Assignment A multiple assignment statement assigns the elements of a Collection which is the result of an expression on the right hand side. 3.. 3.. 2. // ILLEGAL.. to a list of variables on the left hand side.. 6]. b. There must be at least one variable name before the ellipsis. c = [3. b=2. 2. 4.. 5. A single assignment is in the form: <variable> = <an expression> examples: x = [1. 6]. 4. b=2. a = [1. 5. b . 4]. then the entire remainder of the collection is assigned to that variable.Where: Help→Language→Assignment ID: 277 Assignment Statements Single Assignment A single assignment assigns the value of an expression on the right hand side to a variable on the left hand side. A multiple assignment statement is preceeded by the symbol #. just use: a = [1. 4. 5. 6]. 6] # . 5. c = [1. 4.rotate(1).. If the last variable on the left is preceeded by three dots. 2. 4. c = [1.

13] = 1.9... // a series to the end of the array 976 .10.200).10.10. // a series by any step size a = (0.200).10] = 1...] = 1.. Your right hand side expression can return any object that responds to these messages.Where: Help→Language→Assignment Multiple assignment is implemented using the ’at’ method and the ’copyToEnd’ method.] = 1. a = (0. Instance Variable Assignment The basic syntax for setting the value of an instance variable is to use the variable’s setter method which is the name of the variable with an underscore appended..10.200). a[5. point... The two syntaxes are equivalent. // set point’s x coordinate to 5 An alternative syntax is to use instance variable assignment.200). This type of assignment is translated to the first form by the compiler. point.. // from n to the end of the array a = (0. // series stepping by 1 a = (0.x_(5).10.. a[. a[12. a[7. a[1.5] = 1.200). // from zero to n a = (0.x = 5. Series Assignment to an ArrayedCollection or List There is a special syntax for doing assignments to a range of values in an ArrayedCollection or List.3.

Where: Help→Language→Assignment 977 .

A getter message is a message with the same name as the variable which returns the value of that variable when sent to the receiver. Class names are the only global values in the SC language. d has both a getter and setter. The name of a class must begin with a capital letter. Nil. >c. A getter message for an instance variable is created by typing a less than sign < before the variable name. True. A setter message is created by typing a greater than > sign before the variable name. Instance variables declaration lists occur after the open curly bracket of the class definition and are preceeded by the reserved word var. Instance variables may only be directly accessed and changed from within the class’ own methods. Infinitum. Classes whose instances consist of an atomic value are Integer. named and indexed. Float. c has only a setter. Some classes’ instances have no instance variables at all but instead have an atomic value. Instance Variables The data of an object is contained in its instance variables. <>d. Each object contains a separate copy of its instance variables. Instance variables are of two kinds. var a. Symbol. 978 . the value of a class name identifier is the object representing that class. Instance variables which are not explicitly initialized will be set to nil. False. Since classes are themselves objects. A setter message is a message with the name of the variable with an underscore appended which sets the value of the instance variable to the value of the argument to the message.Where: Help→Language→Classes ID: 278 Classes All objects in SuperCollider are members of a class that describes the objects’ data and interface. Instance variables may be exposed to clients by adding getter and setter messages to the class. Getter and setter methods may be defined in the declaration of the instance variable. Color. Char. <b. b has a getter but not a setter. If both occur then they must occur in the order <>. a has no getter or setter. Instance variables names in the list may be initialized to a default literal value by using an equals sign.

p. When an object is sent a message the method whose name matches the message selector in the receiver’s class is executed. Method definitions follow the class variable and instance variable declarations in the class.y = 7. } p = Point. .x_(5)...Where: Help→Language→Classes Point{ // x and y are instance variables which have both getter and setter methods // and default to zero. p.new. The message selector must be an identifier or a binary operator. Class variables may also have getter and setter methods created for them using the less than < and greater than > symbols. Methods have arguments and variable declarations with the same syntax as in FunctionDefs.y_(7).x = 5. <>y = 0. var <>x = 0. p. Method definitions begin with the message selector. Methods however have an implicit first argument named this which is the 979 .x. Class variables like instance variables may only be directly accessed by methods of the class.y. b = p. Method definitions are similar to FunctionDefs in syntax. p. Class variable declaration lists are preceeded by the reserved word classvar and may be interspersed with instance variable declaration lists. // send setter message to set x to 5 // send setter message to set y to 7 // send setter message using setter assignment (See [03 Assignment]) // send setter message using setter assignment (See [03 Assignment]) // send getter message for x // send getter message for y Class Variables Class variables are values that are shared by all objects in the class. a = p. Instance Methods The messages of a class’ interface are implemented in the methods of the class.

Class Methods Class Methods are methods that implement messages sent to the class object. The variable ’this’ may be referred to just like any of the other arguments and variables in the method. 980 .Where: Help→Language→Classes receiver of the message. You may not assign a value to ’this’. A common example is the message new which is sent to the class object to create a new instance of the class. Class method names have an asterisk preceeding the message selector.

you can have /* nested */ comments */ 981 . examples: // single line comment // and go until the end of the line.Where: Help→Language→Comments ID: 279 Comments Comments begin with ited with /* and */. Comments can also be delim- /* multi line comment */ /* Unlike C.

If the falseFunc is not present and the expression is false then the result of the if message is nil. falseFunc). // true function { "expression was false".postln } // false function ) ( var a = 1.choose. syntax: if (expr. . The if message returns the value of the function which is executed. // Boolean expression (chooses one at random) { "expression was true".if (trueFunc. z. trueFunc. If Conditional execution is implemented via the if message. true]. The if message is sent to an expression which must return a Boolean value.. See [Syntax-Shortcuts] for the various ways expressions can be written. see also: the[if] helpfile examples: if ( [false..postln.or. { 100 }. Here are a few of those available. expr. z.{ 200 }). z = if (a < 5. ) 982 .Where: Help→Language→Control-Structures ID: 280 Control Structures Control structures in SuperCollider are implemented via message sends. In addition it takes two arguments: a function to execute if the expression is true and another optional function to execute if the expression is false. falseFunc).postln }.

For 983 . then the bodyFunc is evaluated and the process is repeated.while( bodyFunc ). while ( { i < 5 }. x. ) ’If’ expressions are optimized (i. While The while message implements conditional execution of a loop..or.Where: Help→Language→Control-Structures ( var x. If the testFunc answers true when evaluated. the loop terminates.postln }). Once the testFunc returns false. if (x. { i = i + 1.. ) ’While’ expressions are optimized by the compiler if they do not contain variable declarations in the testFunc and the bodyFunc.isNil. example: ( i = 0.postln. inlined) by the compiler if they do not contain variable declarations in the trueFunc and the falseFunc. syntax: while ( testFunc. . "boing".e. { x = 99 }). testFunc. bodyFunc ).

.Where: Help→Language→Control-Structures The for message implements iteration over an integer series from a starting value to an end value stepping by one each time. Positive Integers also respond to ’do’ by iterating 984 . syntax: forBy ( startValue. 7. function ) example: for (3. function ). endValue. function ). endValue.postln }). stepValue. . startValue.. // prints values 0 through 8 by 2’s Do Do is used to iterate over a collection. // prints values 3 through 7 ForBy The forBy selector implements iteration over an integer series with a variable step size. stepValue. i.. i. 8. syntax: for ( startValue. 2. { arg i.postln })..or. { argi. A function is evaluated each iteration and is passed the iterated numeric value as an argument. function ) . A function is evaluated each iteration and is passed the iterated numeric value as an argument. startValue.or.forBy ( endValue. example: forBy (0.for ( endValue.

i = i . Integers.10. Switch Object implements a switch method which allows for conditional evaluation with multiple cases.. Chars.postln.20). // iterates from eight to twenty (8. // a String is a collection of characters ’they’. with stepsize two Routine({ var i=10. Collections iterate. Other kinds of Objects respond to do by passing themselves to the function one time. so it should be very fast and scale to any number of clauses. item.. The function is called with two arguments. calling the function for each object they contain.do({ arg item.do({ arg item. 5.0. item.rand } }).postln }). // a Symbol is a singular item (8. item. syntax: do ( collection. true and if the functions have no variable or argument declarations. item.do({ argitem. // iterates from zero to four "you"..value) and corresponding functions to be evaluated if true.postln }).postln }). 2.do({ argitem. collection. i. The switch statement will be inlined if the test objects are all Floats.Where: Help→Language→Control-Structures from zero up to their value. while { i > 0 } { i.do({ argitem. the item.20). The inlined switch uses a hash lookup (which is faster than nested if statements).5. These are implemented as pairs of test objects (tested using if this == test. item. (3@4) ]. // iterates from eight to twenty. false. }).do({ arg item.. nil. "abc".postln }). [i.do({ arg item.postln }). function ) . item]. Symbols. item.or. and an iteration counter. 985 .do(function) example: [ 1.postln }).yield.

z. ) Case Function implements a case method which allows for conditional evaluation with multiple cases. { \wrong }. { \no }. x. 2]. x = switch (z.Where: Help→Language→Control-Structures ( var x. 1. { \wrong }. 1. z.1. 1.choose.1. x. 1.1. 1.5. 2.5. 1. 1. 1.3.postln.3.1} { \wrong } {1. x = case 986 . 1.postln. switch (z. 1. 1. ) or: ( var x.3} { \wrong } {1. Since the receiver represents the first case this can be simply written as pairs of test functions and corresponding functions to be evaluated if true. ( var i. 1.choose.5. { \wrong }. z. 0.5} { \wrong } {2} {0} { \wrong } { \true }.choose) {1} { \no } {1. Case is inlined and is therefore just as efficient as nested if statements. z = [0. i = z. 2]. 1.3. { \wrong }. 2]. 1. z = [0. 1. { \true } ).postln.3. z = [0. 1.5.1.

987 . many control structures can be defined like the ones above. Other Control Structures Using Functions.1 } { \wrong } { i == 1. ) { \wrong } { \true }.Where: Help→Language→Control-Structures { i == 1 } { \no } { i == 1.5 } { \wrong } { i == 2 } { i == 0 } x.postln. In the class Collection there are many more messages defined for iterating over Collections.3 } { \wrong } { i == 1.

9201660156 ] [ /tr. However. SendTrig / OSCresponderNode SendTrig is originally intended to send a trigger message back to the client.remove. freq = LFNoise1.addr. 0.ar(freq. 0. { | time. Each line of output is an array with four values: [’/tr’. you need to clean up the OSCresponderNode If you need to track multiple values. 800).add. msg| msg. 966.kr(4). resp.35247802734 ] [ /tr.Where: Help→Language→Debugging-tips ID: 281 Debugging tips Debugging synthdefs Debugging client-to-server communication Debugging client code Debugging synthdefs The challenge in debugging synthdefs is the invisibility of the server’s operations. 1000. you need to create an OSCresponderNode as follows: o = OSCresponderNode(myServer.3) ! }. 1000.play. 600. so the client can take further action on the server. [ /tr. 0. To print out the values. which can then be printed out.kr(2. { var freq.31628417969 ] 2 o. 1153.postln }). value (from SendTrig)]. 1340. id (from SendTrig). 0. // when done. 1000. 0. SinOsc. // Impulse is needed to trigger the /tr message to be sent SendTrig. 0. 629.8098144531 ] [ /tr. 0. you can store them in a collection of arrays and 988 . defNode. ’/tr’.kr(Impulse. freq). it can be used to send any numeric value back to the client. There are a handful of techniques to expose the output of various UGens. 1000.

0. 800). 0. on the client side.getSharedControl(0)).5. resp. use s. r.3) ! }.plot // view frequencies l[1].array. 0. If you want to track the value over time. Then. // when done.getSharedControl(num) to read the value. freq = LFNoise1.kr(0.remove. ’/tr’.plot // view amps Shared controls (Internal server only. Insert a SharedOut. 800).kr UGen into your synthdef. 989 .add(s. freq = LFNoise0.5). 0. l = List.add(msg[3]). control rate only) The internal server allocates a number of control buses whose memory addresses are shared with the client. amp). The client can poll these buses without using OSC messages.new } ! 2.kr(2. o = OSCresponderNode(myServer. 600.wait } }. 1.ar(freq.addr. l = { List.kr(4).stop. 0.Where: Help→Language→Debugging-tips differentiate them by assigning different IDs in the SendTrig UGen. { var freq.new. r = fork { loop { l.1.play. you need to clean up the OSCresponderNode l[0]. use a routine to poll repeatedly.3) ! }. 600.kr(8.play. SinOsc. freq).kr(4). { var freq.ar(freq. { | time.add.kr(Impulse. amp = LFNoise1. SharedOut. freq). }). msg| // msg[2] is the index l[msg[2]]. 0. SendTrig. // Impulse is needed to trigger the /tr message to be sent SendTrig.kr(10. 0. 0. 2 o.kr(Impulse. // no need for Impulse here 2 SinOsc. amp.array.

When a UGen’s output feeds into another’s input.1)) }).5).ar(0. { | freq = 440| var sig. // to view the results graphically Server-side trace The /n_trace message causes the server to print a list of all the UGens in the node as well as their input and output values. colors are used here to highlight signal flow. 0.. ffreq.kr(2. The trace comes out in monochrome.trace. 1. 0. sig = Saw.send(s). For a concrete example.1800) * ffreq. let’s look at a synthdef that doesn’t work.ar(sig.451348 unit 3 BinaryOpUGen #units: 21 990 . ffreq = LFNoise1. (800. freq+1].Where: Help→Language→Debugging-tips l. a. TRACE 1005 resonz unit 0 Control in out 440 unit 1 BinaryOpUGen in 440 1 out 441 unit 2 Saw in 441 out 0.array. a. the values will be the same at both ends. 0.ar([freq. Out.free.2).plot. 1000. The intent is to generate a detuned sawtooth wave and run it through a set of parallel resonant filters whose cut-off frequencies are modulating randomly. Signal flow can be identified by looking at the numbers at inputs and outputs. SynthDef(\resonz. a = Synth(\resonz). Resonz. We run the synth and generate the trace (reproduced below). but it’s the ultimate source of information when a synthdef is not behaving as expected. It takes some practice to read a synthdef trace.

14995e+10 unit 14 BinaryOpUGen in 1400 -0.367307 0.367307 unit 5 BinaryOpUGen in -0.42883 unit 16 BinaryOpUGen in 1600 -0.402 0.1 out 3.2 out 0.934 unit 9 Resonz in -0.Where: Help→Language→Debugging-tips in 0.934 0.168 unit 11 Resonz in 0.0902696 -336.336168 991 .336168 out -403.0734615 -403.0902696 unit 4 Saw in 440 out -0.336168 out -470.336168 out #ff0000-268.0734615 unit 6 LFNoise1 in 2 out -0.635 unit 15 Resonz in 0.2 out -0.02999e+08 #0000ff unit 12 BinaryOpUGen in 1200 -0.0734615 #ff0000-268.402 unit 13 Resonz in -0.836168 0.336168 unit 8 BinaryOpUGen in 800 #ff0000-0.1 out 843934 unit 10 BinaryOpUGen in 1000 -0.336168 out -336.635 0.1 out #00ff00-5.5 out #ff0000-0.168 0.836168 unit 7 BinaryOpUGen in -0.451348 0.0902696 -470.1 #996633 out 9.

where we expected both to go. Mix.ar(sig..1800) * ffreq. where we expected it to be 0. Tracing back (the red. all the outputs are well outside the audio range -1.ar(0.102 0.2)). 992 .1 out #ff800032785.869 unit 17 Resonz in -0. The resonance frequency derives from multiplying an array by a LFNoise1. 0.869 0.2 unit 20 Out in 0 843934 #0000ff3. Looking at the Resonz inputs.42883#ff00ff515.. which will blow up most digital filters. sig = Mix.506 unit 18 BinaryOpUGen in 1800 -0. 0.336168 out -605. the mul and add inputs are reversed! If you look very carefully at the trace.ar(Resonz. but we don’t mix them down into a single channel. The first is because we use multichannel expansion to produce an array of Resonz filters.506#ff80003278 out Two problems leap out from the trace: first.. into every Resonz. italicized numbers).5.5.kr(2. and second. the LFNoise1 is outputting a negative number.14995e+10#00ff00-5. 0.0734615 -537. we see that the frequency input is negative. But. SynthDef(\resonz.1. 1000.Where: Help→Language→Debugging-tips out -537. ffreq = LFNoise1. The above trace uses colors to track the source of each output signal. To fix it.1))) }). The two components of the detuned sawtooth go into alternate Resonz’es. Note that there are no out of range signals prior to each Resonz. you will see another problem relating to multichannel expansion.ar(Saw.0902696 -605. there are six channels of the output (there should be 1). ffreq. 1). { | freq = 440| var sig.send(s).ar([freq. freq+1]. the sawtooths need to be mixed as well.102 unit 19 Resonz in 0.1 out #ff00ff515. Out. combined.1.02999e+08#9966339.5. (800.

Server. ’i_out’. [ 9. 1 ] latency nil [ "/g_new".Where: Help→Language→Debugging-tips a = Synth(\resonz).default = s = Server.hfbk-hamburg.boot. // optional latency nil // these messages get sent on bootup [ "/notify". Debugging client-to-server communication Some bugs result from OSC messages to the server being constructed incorrectly.quit. 1 ] a = { SinOsc.free. "data[ 290 ]". a.ar(440.makeWindow. Messages will be dumped into a new document window. s.de:8888/MusicTechnology/710 To use it. a. "-1589009783". latency nil [ 11.4) ! 2 }. 0 ] ] a.trace. latency nil [ "/d_recv". 1. 1001 ] Debugging client code 993 . you need to quit the currently running local server. ’out’. 1001.new(’local-debug’. 0. 57110)). 0. 0. s. Julian Rohrhuber’s DebugNetAddr is a convenient way to capture messages. 0.play.free. The class may be downloaded from: http://swiki. then create a new server using a DebugNetAddr instead of a regular NetAddr. s. DebugNetAddr("localhost".

Error dumps often (though not always) contain a great deal of information: what the action was. See the [Understanding-Errors] help file for a tutorial.debug(caller) // post the object along with a tag identifying the caller 994 . There’s no significant difference between: if(a > 0) { positive. Common methods to use are: . they can be placed in the middle of the statement without altering the processing flow. and how the flow of execution reached that point.postln) { positive. Errors Learning how to read SuperCollider error output is absolutely essential. this will give you more information than a regular error dump. Since the normal printing methods don’t change the value of an expression. // enable Exception. Usually the regular error dump is sufficient.debug = false.value(a) }.postcs // post the object as a compile string . which makes debugging on the client side tougher. the graphic inspector is indispensable. Debug output using post statements The most common approach is to insert statements to print the values of variables and expressions. and if((a > 0). which is enabled with the following command: Exception. // disable In most cases.postln .value(a) }. which objects are being acted upon. There’s also a graphic Inspector for error dumps.debug = true. but not impossible.Where: Help→Language→Debugging-tips SuperCollider does not have a step trace function. If you are using Environments or prototype-style programming.

if (a > 0) { positiveFunc. however. To print multiple values at one time. By sprinkling these throughout your code. val3]. Another advantage of . val3].Where: Help→Language→Debugging-tips . It’s used like this: ( var positiveFunc. // or.debug is that it’s easier to search for debug calls and differentiate them from legitimate postln and postcs calls.debug or . it’s very helpful for tracing the origin of erroneous values. you can use the . the debugging output can give you a partial trace of which code blocks get visited in what order. dumpBackTrace If you discover that a particular method or function is being entered but you don’t know how it got there.dumpBackTrace method on any object. ) // output: positiveFunc-arg a: 50 5 The caller argument is optional. wrap them in an array before using . a*10 }. val2. You’ll get 995 . especially at the beginnings of functions or methods. so Linux and Windows users may not have access to it. positiveFunc = { | a| a.postcs.debug(’positiveFunc-arg a’).debug(\myMethod).debug is defined in the crucial library. a = 5. Use postcs if you expect to be posting collections. a Dictionary" etc. val1.value(a) }. [val1. Note that if any of the array members are collections. for a non-Crucial way: [\callerTag. postln will hide them behind the class name: "an Array.postcs. val2.

Where: Help→Language→Debugging-tips what looks like an error dump. it’s recommended to use "this. but without the error. 996 .trace method.dumpBackTrace". Execution continues normally after the stack dump.dumpBackTrace. a*10 }.debug(’positiveFunc-arg a’). In a method definition. a = 5. there is no "this" so you should pick some arbitrary object. a. Each output value from the pattern gets posted to the main output. in a freestanding function. ) // output: positiveFunc-arg a: CALL STACK: < FunctionDef in closed FunctionDef > arg a = 5 < closed FunctionDef > var positiveFunc = <instance of Function> Interpreter-interpretPrintCmdLine arg this = <instance of Interpreter> var res = nil var func = <instance of Function> Process-interpretPrintCmdLine arg this = <instance of Main> 50 5 This tells you that the function came from interpreting a closed FunctionDef (automatically created when evaluating a block of code). use the .value(a) }. Tracing streams To see the results of a pattern. if (a > 0) { positiveFunc. ( var positiveFunc. positiveFunc = { | a| a.

SynthDescLib. Sometimes this happens in your code and the reason isn’t obvious.play. If you want a more descriptive message. 0). func. \delta. p. p = Pbind(\degree. \default). you never see the output.halt. One useful approach is to insert statements that will cause execution to halt.value(f).throw. because posted output is held in a buffer until execution is complete.read.25. Pstutter(Pwhite(1. and reload your code just to try again. In Mac OS X. on the other hand. If execution never completes.boot. Prand(#[-2.throw later and try again. after a lot of heartache. inserting "post" or "debug" calls will not help with infinite loops or recursion. When debugging code that crashes. 0. inf). make up an error and throw it: Error("myFunction-halt"). If it crashes. It will lock up SuperCollider and you will have to force quit. This is a bad idea. 0. you know that the infinite loop is happening after the error–so move the error. Here is a rogues’ gallery of infinite loop gotchas–things that don’t look like infinite loops. you can zero in on the location.global. f = { | func| f. Infinite recursion. Eventually. inf). \sustain. Debugging infinite loops or recursion while(true). The easiest is . Pseq(#[-1. 2]. but they will kill your code quicker than you can wish you hadn’t just pushed the enter 997 .stop. relaunch SuperCollider. is more likely to cause SuperCollider to quit unexpectedly when the execution stack runs out of space.value(func) }. place a line like this somewhere in the code. you know the infinite loop is earlier.Where: Help→Language→Debugging-tips s. 1. 1]. -1.14). inf)). but it provides you with no information about where or how it stopped. \instrument..trace.2. 4. Debugging these situations is very painful because you might have to force quit. If you get the error output. Pwalk((0. or how it got there.

while (i < 10) { i.sched(2. doing nothing. // now one of the items of a is a itself a. // crash--postcs has to walk through the entire collection.do({ | item| } }).put(5. The above loop means to check whether i < 10 once.postln. i = i+1 }. The loop condition should be written inside a function. i = i+1 }. a). so the loop never stops.postln }).10). if the array is empty. If you have a data structure that is self-referential. eventually you will reach the end. Routines and empty arrays: a = Array. then loop if the value is true. So. Since the loop condition is evaluated only once.Where: Help→Language→Debugging-tips key: i = 0. // crash While loop syntax is different in SuperCollider from C. at the beginning of the loop. SystemClock. the outer loop{} runs forever. a = 0. But. the do loop never executes and yield never gets called. Tree structures are usually finite–no matter which branch you go down.next.postln. to wit: i = 0.yield }). r. you can easily get infinite recursion: a = (1. // crash item. a.postcs. which loops on itself Self-referential data structures are sometimes an indication of poor design.new. { a. avoid them. If this is the case.. while { i < 10 } { i. // crashes when scheduler fires the function 998 . r = Routine({ loop { a. it never changes. Recursion is often used to walk through a tree structure. This looks pretty innocent: iterate repeatedly over an array and yield each item successively.

if it returns a number. To fix it. // crash item.sched(2. r. SuperCollider code is usually indented. make sure the function returns a non-number.yield }). nil }). the function will be rescheduled for now + the number.new.postln.next. { a.do({ | item| } }). // this obviously sticks out a.Where: Help→Language→Debugging-tips When a scheduled function executes. they’re much easier to see. doesn’t stand out a. // looks like regular code. SystemClock.postln.new. 999 . r. // crash item. a = 0. r = Routine({ loop { "debugging".postln.next. r = Routine({ loop { "debugging".do({ | item| } }). Removing debugging statements Use formatting to help your eye locate debugging statements when it’s time to remove them. If the number is 0.yield }). a = Array. // vs: a = Array. If you write your debugging statements fully left-justified. it is effectively the same as an infinite loop.

Such a sequence may be used anywhere that a normal expression may be used. b + 5 acts as a single expression for the 1000 .Where: Help→Language→Expression-Sequence ID: 282 Expression Sequence A sequence of expressions separated by semicolons and optionally terminated by a semicolon are a single expression whose value is the value of the last expression. max( b = a * 2. b = a * 2. 10). // computes the maximum of b+5 and 10 In the above example. b + 5. the sequence: first argument tomax().

postln. 200). Arguments which are not explicitly initialized will be set to nil if no value is passed for them. b. If a function takes no arguments. then the argument list may be omitted. a function would be known as a lambda expression. Arguments must be separated by commas. An argument list either begins with the reserved word arg. In functional languages. 1001 . if any.value(10. a + b }. Argument declarations. Function definitions are enclosed in curly brackets {}. {}. d = a * b.postln. var d. 5).value. An expression follows the declarations. c. When evaluated. { arg a. f. c + d } Functions are not evaluated immediately when they occur in code. then all the remaining arguments that were passed will be assigned to that variable as an Array. Arguments An argument list immediately follows the open curly bracket of a function definition. but are passed as values just like integers or strings. follow the open bracket.postln. Names of arguments in the list may be initialized to a default value by using an equals sign. b. f.value(4. If the last argument in the list is preceeded by three dots (an ellipsis). Variable declarations follow argument declarations. the function returns the value of its expression. An empty function returns the value nil when evaluated. f = { arg a. or is contained between two vertical bars. A function may be evaluated by passing it the value message and a list of arguments.Where: Help→Language→Functions ID: 283 Functions A [Function] is an expression which defines operations to be performed when it is sent the ’value’ message.

900. d.geom(4. 2700 ].1))). // silence // but this is: ( SynthDef(\freqs. they may only be initialized to literals. z=0.. c=3| argx=’stop’..1)) }. c=3. 0.ar(freq. Mix(SinOsc. // any arguments after the first 3 will be assigned to d as an Array If you want all the arguments put in an Array arg . There can be 1002 . 100..ar(freq. but in the case of Function-play or SynthDef-play. }). ) See [Literals] for more information. 300. c .ar(0.Where: Help→Language→Functions examples: arga. 0.geom(4. { arg freq = #[ 100. Variable lists are preceeded by the reserved word var. In general arguments may be initialized to literals or expressions. // these args are initialised arga.. z. Variables Following the argument declarations are the variable declarations. a * 4 }. y. b. Mix(SinOsc. 100. // this is not: {arg freq = Array.play. // is equivalent to: | a. 0. // this is okay: {arg a = Array.value. 3). 0. Out. b. b. These may be declared in any order. 3).play.

Variable declarations lists may not contain an ellipsis. 1003 . ___________ See also [Function]. curve=1.Where: Help→Language→Functions multiple var declaration lists if necessary. [AbstractFunction]. examples: var level=0. slope=1. Variables may be initialized to default values in the same way as arguments. and [FunctionDef].

points. Messages The SuperCollider language is an object oriented language. rectangles. The means by which the operation is performed is determined by the object’s class. All entities in the language are objects. each appropriate to the class of the object. Many objects simply return themselves in response to ’value’. Instance Variables. A 1004 . graphical buttons. graphical windows. wave samples. An object is something that has data. Classes. The set of messages to which an object responds to is known as its interface. called the receiver. and a set of operations that can be performed on the object. Objects of different classes may implement the same message in different ways. A set of messages that implement a specific kind behaviour is known as a protocol. An object’s internal state may only be changed by sending it messages. This allows the implementation of the object to be hidden from the client. sliders and much more. but other objects such as functions and streams first evaluate themselves and return the result of that evaluation. For example all objects understand the ’value’ message. All objects are instances of some class which describes the structure of the object and its operations. An object’s interface may include several protocols which allow the object to interact in several different contexts. For example all objects implement the ’dependancy’ protocol which allow the object to notify other dependant objects that the object has changed and that the dependant should do any necessary action to update itself. object collections. Methods An object’s class contains the description of the object’s data and operations.Where: Help→Language→Intro-to-Objects ID: 284 Objects. A message is a request for an object. Objects in SuperCollider include numbers. The ability for different objects to react differently to the same message is known as polymorphism and is perhaps the most important concept in object oriented programming since it allows the object’s behaviour to be abstract from the point of view of the user of the object (the client). representing the object’s state. The advantage to this is that the client does not depend on the object’s implementation and that that implementation can be changed without having to change the client. unit generators. Operations upon objects are invoked by messages. to perform one of its operations. character strings.

Where: Help→Language→Intro-to-Objects class also describes how to create an object which is a instance of that class. These are named variables that describe the object’s state. Summary of Terminology object something that has data. protocol a set of messages that implement a specific kind of behaviour. The values of the instance variables are themselves objects. method a description of the operations necessary to implement a message for a particular class. The methods in a class tell how to implement messages sent to its instances. representing the object’s state. An object’s data is contained in its instance variables. 1005 . Others ask the receiver to make some change to its internal state. The author of a class may decide to expose instance variable access to clients by adding getter and/or setter messages to the class. An instance variable is only directly accessible from within the class itself. A method is a description of the operations necessary to implement a message for a particular class. Still others may ask the receiver to return some computed value. Some methods inquire about some property of the receiver. instances of class Point have instance variables named ’x’ and ’y’ which contain the coordinate values of the Point. message a request for an object to perform an operation. and a set of operations that can be performed on the object. receiver the object to which a message is sent. Methods generally fall into several categories. interface the set of messages to which an object responds. For example. polymorphism the ability for different kinds of objects to respond differently to the same message. class a description of the state and behaviour of a set of objects. A class contains a method definition for each message to which its instances respond.

Where: Help→Language→Intro-to-Objects instance one of the objects described by a class. instance variable a part of an object’s internal state 1006 .

do {| x| (1. [ 1.. y <.3).. y <.x) are treated as special cases and implemented as loops rather than making a collection. 0. Basically list comprehensions are for getting a series of solutions to a problem. 2 ] ] the list comprehension above is equivalent to the following code: all(Routine. [ 3.x.\b.. [ 5. A list comprehension in SC is really a Routine.isPrime } [ [ 1.5). b ]. A few examples all {: x/(x+1).(1.5) and (1.(1... in SC these are just a syntax macro for a longer expression.yield} }}})).. In the list comprehension compiler.3). y in 1.8.y]. [ 1. 3 ]. a ]. Haskell. [ 2.\c] } [ [ 1. x <. 1 ].5). x <.. 1 ]. b ]. 1 ]. c ]. c ] ] all {:[x..5) } [ 0.x).. [ 4. c ]..83333333333333 ] all {:[x. 2 ]. b ].. x <. and Erlang which were later copied into Python. // read this as "all [x.new({ (1. You can search the web for "list comprehensions" or "generator expressions" to learn more.Where: Help→Language→ListComprehensions ID: 285 List Comprehensions List comprehensions are a syntactic feature of functional programming languages like Miranda.do {| y| if ((x+y). a ]. [ 2.0) } 1007 .(0. [ 4.66666666666667.75.y] for x in 1. a ].isPrime) {[x. You can use the ’all’ message to collect all of the Routine’s results into a list. x <.y].but much more concise and much easier to keep in your head than writing it out. [ 2.y]..(1.x). y <.5. [ 3.. simple series like (1. all {:[x. 0. [ 3.5. [ 3.[\a. [ 2. such that x+y is prime. . 0. 0.(x. (x+y).(1.y].

[ 23. 1. 2047 ]. [ 2. var y = x..10]).Where: Help→Language→ListComprehensions [ [ 0.postln. [ 2.(x. 6. 1. [ 1.1) } [ 1.. 2. [ 29.4. qualifiers } There are several types of qualifier clauses that can appear after the body. 3. 4.nthPrime.30).3. intervals.lastIndex . 0 ].4).([0. var z = 2 ** y . chord. 3. 2 ]..chord[i]. [ 1.asInteger. 536870911 ] ] // mersenne numbers which are no primes Qualifier Clauses A list comprehension begins with clauses separated by commas.postln. {: and contains a body followed by several qualifier {: body .1.isPrime. [ 3. x<-(0. 0 ] ] all {:y. [ 3. 1 ]. z. 0 ]. generator clause 1008 . y <. [ 2.(0 .. 2. 3.gap) gap <.7]).lastIndex). intervals. i <. // a function to generate intervals between all pairs of notes in a chord voicing intervals = {| chord| all {: chord[i+gap] . 7.([0. 1 ] ( var intervals. [ 3. 2. 6. 1 ]. 2 ]. 3. [ 3. 7 ] all {:[y.(1 . 8388607 ]. 1 ]. } }. 3. 3 ]. 4. 2. chord.(1. z]. 10 ] [ 1.7..1. ) [ 4.not } [ [ 11. x <. 0 ].

2. Its syntax is name <. [ 1. c ] all {: x. [ 1. x <. [ 2.(1. \b. 10 ]. [ 2. 3. 2. 2. The name is a local variable whose scope extends to all clauses to the right.x) } [ 1.(1.(1. all {: x. all {: x. 2.(10. 1. The name is also in scope in the body. x <. 2.expr The expression should be something that can respond meaningfully to ’do’ such as a collection or a stream. 2.2). x <.(1. 3 ] all {: x. 20 ]. x <. y <. x <. y <. 3. The name takes on each value of the expression. 3 ] all {: x.. 30 ] ] generators can depend on previous values. x <..20.. b. 3 ] guard clause 1009 .[\a..y].3).(1.. [ 2.(1!3)++(2!2)++3 } [ 1.4-x) } [ 1.3). y <.3) } [ 1.Where: Help→Language→ListComprehensions The basic clause is the generator clause. 2. 10 ]. 30 ]. 1.30) } [ [ 1. 1.(1. \c] } [ a. 1. 3 ] multiple generators act like nested loops.. all {: [x.. 20 ].

2 ]. It should return a boolean value. 30 ] you can have multiple guards..30). 25. 10. 20. the name is bound to a single value. 2 ] ] var clause A var clause lets you create a new variable binding that you can use in your expressions. (x % 5 == 0) | | x. [ 5. 45.. 171 ] side effect clause 1010 . z.2). 3..odd } [ 1. all {: x. 2 ]. all {: z. (x+y). x <.(0. 91. [ 10. x.. [ 4.even } [ [ 0.(1. x <.. (x % 5 == 0) | | x. 21. var name = expr Unlike the generator clause. x <. [ 8. 1. [ 1.isPowerOfTwo. all {: [x. 2 ]. 5. 2 ]. 15. all {: x.10).10).(0. 9 ] x. 7.y].(0. The scope of the name extends to all clauses to the right and in the body.(1. 4. 1 ]. 15. x <. 3. 16.odd } [ 1. var z = (x*x-x) div: 2.odd is the guard and causes all even numbers to be skipped. 8. 2.20). 1 ]. y <. 105.Where: Help→Language→ListComprehensions A guard clause is simply an expression. 55. 5. 153.isPowerOfTwo } [ 0. [ 2. it doesn’t iterate. expr The guard acts as a filter on the results and constrains the search.

Miller. so does less work than the above. x <. // Baker does not live on the top floor.. x <.z]. var creates a new scope.20). z < 50 } // using a termination clause // this one stops searching. var z = (x*x-x) div: 2.postln.postln.(1.even } termination clause The termination clause is for stopping further searching for results. fletcher. Fletcher does not live on a floor adjacent to Cooper’s. the routine halts.z]. var z = (x*x-x) div: 2. so the ’floors’ on the left is a new // remove baker’s floor from the list. miller.(1.. Once the expression becomes false.(1.postln. :while expr // using a guard all {: z. Cooper. x <. Where does everyone live? ( z = {: [baker.. :: [x. var z = (x*x-x) div: 2. :while z < 50 } Constrained Search list comprehensions can solve constrained combinatorial problems like this one: Baker. cooper.z]. var floors = (1. Cooper does not live on the bottom floor. Miller lives on a higher floor than does Cooper. :: [x.Where: Help→Language→ListComprehensions This clause lets you insert code to do some side effect like printing. and Smith live on different floors of an apartment house that contains only five floors. Smith does not live on a floor adjacent to Fletcher’s. :: expr all {: z. 1011 . baker <. Fletcher does not live on either the top or the bottom floor. Baker does not live on the top floor.20). all {: z. smith] . :: [x. z.20). baker != 5.5).floors.. Fletcher.

miller > cooper.removing(fletcher). (absdif(fletcher. }. absdif(fletcher.next.zero or more <list_compre> ::= "{:" <body> ’. var floors = floors. cooper <.floors. cooper) > 1). // remove cooper’s floor from the list.Where: Help→Language→ListComprehensions binding. (fletcher != 5) &amp.&amp. 2. the most constrained person above is fletcher. [ ] .’ <qualifiers> "}" <body> ::= <exprseq> <exprseq> ::= <expr> { ".removing(cooper). you can reorder the above tests to make it run faster.removing(baker).floors. ) z.&amp. // nil. varfloors = floors. only one solution combinatorial problems can take a lot of time to run. fletcher <. 5. Grammar: Here is the BNF grammar for list comprehensions in SC.floors. // [3.next. // remove miller’s floor smith <. generally you want to search the most constrained variables first.removing(miller). so he should be searched first. &amp. etc. (fletcher != 1) // Fletcher does not live on either the top or the bottom floor. // Cooper does not live on the bottom floor. // Fletcher does not live on a floor adjacent to Cooper’s. 1 ] z. 4. // remove fletcher’s floor miller <.optional { } . cooper != 1." <expr> } 1012 . var floors = floors. var floors = floors. smith) > 1 // Smith does not live on a floor adjacent to Fletcher’s. // Miller lives on a higher floor than does Cooper.floors. then cooper.

Where: Help→Language→ListComprehensions <qualifiers> ::= <qualifier> { ’.’ <qualifiers> } <qualifier> ::= <generator> | <guard> | <binding> | <side_effect> | <termination> <generator> ::= <name> "<-" <exprseq> <guard> ::= <exprseq> <binding> ::= "var" <name> "=" <exprseq> <side_effect> ::= "::" <exprseq> <termination> ::= ":while" <exprseq> Code Generation: For each of the above clauses..do {| name| .. here is how the code is generated.. } guard: if (expr) { .next qualifier. By understanding these translations..next qualifier.value(expr) side effect: expr .... 1013 .next qualifier. generator: expr. you can better understand how scoping and control flow work in list comprehensions. }. } binding: {| name| .next qualifier. The body acts as the innermost qualifier.. .

next qualifier. }{ nil..Where: Help→Language→ListComprehensions termination: if (expr) { .alwaysYield } 1014 ..

This distinguishes floating point numbers from integer expressions like: 8.Where: Help→Language→Literals ID: 286 Literals Literals are values which have a direct syntactic representation. 1.5 Exponential notation is also supported. The following sections describe the types of literals that can be represented.39 98.25pi 1015 .2e4 1e-4 The constant pi can be appended to a number to create floating point constant: 2pi 0. You must have digits on both sides of the decimal point.6 1. examples of integers : -13 666 2112 96 A float is one or more decimal digits followed by a decimal point followed by one or more decimal digits. Numbers An integer is any series of digits optionally preceeded by a minus sign.5pi -0.0 -0.rand examples of floats : 0.

For example you can write hexidecimal numbers as follows: 16rF0 16rA9FF Binary numbers can be written as follows: 2r01101011 Floating point values may also be specified in any base: 12r4A. carriage return. The radix is specified in base 10 followed by the letter ’r’ followed by the value written in that radix using characters 0-9.A-Z. or a-z. for digit values from 0 to 35. examples of symbols: ’x’ ’aiff’ 1016 . linefeed. and backslash are preceeded by a backslash: $\t $\n $\r $\\ Symbols A symbol is written as a string enclosed in single quotes.A Characters Characters are preceeded by a dollar sign: $A $B $C Tab.Where: Help→Language→Literals Numbers can also be written in radices other than base 10 up to base 36.

then the new line characters become part of the string.Where: Help→Language→Literals ’BigSwiftyAndAssoc’ ’nowhere here’ ’somewhere there’ ’.’ A symbol consisting of a single word can be written with a preceeding backslash. If so. 1017 ." If two or more strings are lexically adjacent. \x \aiff \BigSwiftyAndAssoc Strings Strings are written in double quotes: "This is a string. followed by zero or more alphanumeric characters. example: "This" " is " "also a " "string. " Identifiers Names of methods and variables begin with a lower case alphabetic character." Strings may span more than one line. then they combine into a larger string. example: "This is also a string.+o*o+.

z = nil. This is not the case in regular Arrays. 2. bar] // this is only legal if foo and bar have been declared as variables Arrays and other collections may also be created dynamically which is explained in Collections. In literal Arrays names are interpreted as symbols. "def". Class Names Class names always begin with a capital letter followed by zero or more alphanumeric characters. False and Nil are written as the words true. nil and inf. 4] Literal Arrays must be used as is and may not be altered at run time. where they are interpreted as variable names: #[foo. bar] // this is legal.Where: Help→Language→Literals var abc.help. x = true. func. z123. Literal Arrays Arrays of literals are created at compile time and are written with a # preceeding the array as follows: #[1. y = false. an Array of Symbols [foo. Object Point Synth Special Values The singular instances of the classes True. ’abc’. false. 1018 .

When nesting literal arrays.1. table[(c ++ "s" ++ o). 5. var naturalNoteNames = ["c".asSymbol] = n + 2. gs4. 2.. }. #[[1. c5.atAll(#[c4. 9. (0. 5. table[(c ++ "b" ++ o). e5. value { var semitones = [0. gs5. "g". 11]. table[(c ++ "bb" ++ o). c6]) ) 1019 .asSymbol] = n .9). 4.do {| c. only the outermost literal array needs the ’#’ character. table[(c ++ "ss" ++ o).2.asSymbol] = n . 2. "a". "d". [4. "f". table[(c ++ o). 7. e4. }. // translate note names to midi keys table.do {| o| naturalNoteNames. }.Where: Help→Language→Literals Using a literal Array is faster than building an array dynamically every time you need it. i| var n = (o + 1) * 12 + semitones[i].asSymbol] = n + 1.asSymbol] = n. 3]. 6]] Literal Arrays can be useful for things such as tables of constants. "b"]. for example note names: ( // build a table of note names var table = (). "e".

All binary operators have the same level of precedence and associate from left to right. 1 + 2 // sum of one and two a . the expression: 1020 . a receiver to which the message is sent and in some cases a list of arguments which give additional information pertaining to the operation. * . Binary operator messages A binary operator selector is any string of characters from the list of legal binary operator characters: ! @ % &amp. The kind of result depends on the kind of message. 10 rrand: 100 Operator Precedence There is none. Messages may be written using binary operators. A message consists of a message selector which names the type of operation.0 // answer whether x is less than zero A binary operator can also be an identifier followed by a colon.b // difference of a and b x < 0. In the default case. A binary operator expression consists of two expressions with a binary operator between them. For example. A message always returns a result. the return value is the receiver itself. functional notation or receiver notation.+ = | < > ? / An exception is that no operator may begin with // or /* which are comment delimiters.Where: Help→Language→Method-Calls ID: 287 Messages Sending messages is the way things get done in an object oriented language.

c) is equivalent to : g(a. Functional notation messages The message selector preceeds the parenthesized argument list. The first argument in the list is actually the receiver.Where: Help→Language→Method-Calls a * b + c * d is equivalent to: ((a * b) + c) * d and not: (a * b) + (c * d) Therefore it is usually better style to fully parenthesize your expressions. sin(x) // sine of x max(a.max(b) is equivalent to : x.f(b). b). c) 1021 . b) // maximum of a and b Receiver notation messages A method call in functional notation may be converted to receiver notation by putting the receiver before the method name followed by a dot as shown below. max(a.sin another example: g(f(a. b) sin(x) is equivalent to : a.

(a is 10. b defaults to 2) z = x.value(10. b is 5) z = x. This syntax will be explained in the section on Functions. // z is set to 15. If fewer arguments are passed. When calling a method or function with zero arguments you can omit the parentheses: // x is declared to take two arguments a and b which default to 1 and 2 respectively. This warning may be turned off globally by making the 1022 . (a is 10. 9 is ignored) Keyword Arguments Arguments to Methods may be specified by the name by which they are declared in a method’s definition. // It returns their sum. (a defaults to 1. (a is 10. Such arguments are called keyword arguments. 5. Keyword arguments must come after any normal (aka ’positional’) arguments. b defaults to 2) z = x.g(c) is equivalent to : a. If a keyword is specified and there is no matching argument then it is ignored and a warning will be printed. b). // z is set to 3.value(10. // z is set to 15. b=2.Where: Help→Language→Method-Calls is equivalent to : f(a. a + b }. // z is set to 12. x = { arg a=1. those arguments not passed are set to a default value if one is given in the method or function definition. or otherwise to nil. and may be specified in any order. 5).f(b). If too many arguments are passed.g(c) Default Argument Values You may call a function or method with more or fewer arguments than it was declared to accept. b is 5. the excess arguments are either collected into an Array or ignored depending on whether or not the function or method has an ellipsis argument (explained in Functions). 9).value(10). Any argument may be passed as a keyword argument except for the receiver ’this’. z = x.value.

SinOsc.ar(800.ar(800. mul: 0. Cost of using keyword arguments When using keyword arguments there is a runtime cost to do the matching that you should be aware of. SinOsc.Where: Help→Language→Method-Calls following call: keywordWarnings(false) If a keyword argument and a positional argument specify the same argument. For example the ’ar’ class method of the SinOsc class takes arguments named freq. pi. b.perform(’ar’. phase. freq: 800). // function args may be specified by keyword.2). c].2. phase = pi. phase: pi. 0. 1023 .2. mul: 0.2. freq: 1200). mul: 0.ar(800. // invalid keyword prints warning The arguments to a Function may also be specified by keyword arguments when using the ’value’ message. SinOsc. // freq = 800.2. then the keyword argument value overrides the positional argument value. // all normal arguments: freq. SinOsc.ar(phase: pi. All of the following are legal calls to that method. mul = 0. 0).postln }. You may also use keyword arguments when using the ’perform’ method. and add in that order. others get default values. mul. { arg a=1. b=2.2. freq: 800). [a. c=3.value(b: 7. // keyword value of 1200 overrides the positional arg value of 800 SinOsc. SinOsc. phase. add // freq = 800.ar(zorg: 999). The cost can be worth the convenience when speed is not critical. mul = 0. add gets its default value of zero. mul. c: 8).

hash }.Where: Help→Language→Partial-Application ID: 288 Function Creation via Partial Application Partial application is a way to create a function by passing only some arguments to a method.isPrime). (except that there is no name ’x’ declared) g = Point(_.hash). (1.collect(_. for example: f = _ + 2. It only applies to a single method. g is a function of two arguments. g. 4). (1. not to a more complex nested expression.value(7).collect {| x| x. Here are some example usages of this in a collect message.. _).8).collect(_.8). 1024 . it is equivalent to having written: f = {| x| x + 2 }. list. (1.isPrime }.collect {| x| x.. (1. f..8). f is now a function of one argument.8). Below each is written the equivalent function. The _ character stands in for missing arguments and becomes an argument to the created function.. or dictionary call.value(3.

\b.8). g.8). // only the * gets partially applied._)).. b:y) } f..collect(Polar(_.8).x) }.8). \b. (1.(z. // nested expression won’t work..collect((a:_)). 5). 5) }.collect {| x| (a:x) }. (1..collect {| x| (1. // need to use a function for this. (1. f = (a:_. pi)). 1025 .8). (1.collect {| x| [\a.(7). (1..collect((1. 50) }.8). 50) ).(_. not the surrounding expression.. b:_)..value(7).8).collect( Point(100 * _.. pi) }...8).collect([\a. (1. // g is a partial application of f // get the answer // equivalent to this: f = {| x.. An example of what you can’t do: (1.collect {| x| Polar(x. g. _]). (1. y| g = {| z| (a:x..Where: Help→Language→Partial-Application (1.8). // f is a two argument function g = f.collect {| x| Point(100 * x. x] }. (1.8).

value() this. The value method is implemented by these classes (among others): Function : Object : Ref : this. A message generally has some underlying meaning and it is the responsibility of each class to respond in a way appropriate to that meaning. [1..2.3]. the object will respond to ’value’ by returning itself.postln.postln.value. For example. // posts itself // value returns itself 5. the ’value’ message means "give me the effective value of this object". 1026 . _FunctionValue // evaluate a function with args ^this. 5. //etc.Where: Help→Language→Polymorphism ID: 289 Polymorphism Polymorphism is the ability of different classes to respond to a message in different ways..value(args) this..postln.value.value.postln. ’a symbol’. In class Function the value method is a primitive.postln.value Let’s look at how these classes implement the value message. Since all classes inherit from class Object this means that unless a class overrides ’value’.primitiveFailed } args.. ’a symbol’. value { arg . Here’s the value method in class Object: value { ^this } It simply returns itself.

postln. stream << "‘(" <<< value << ")".squared }. The Ref class provides a way to create an indirect reference to an object.value.postln. ^this. *new { arg thing. stream << "‘(" << value << ")". ^super. It can be used to pass a value by reference. so it is not possible to know just by looking at it what it does.postln. However what it does is to evaluate the function and return the result. } storeOn { arg stream. // posts Instance of Function // posts 25 { 5.embedInStream(inval) } printOn { arg stream. 1027 .Where: Help→Language→Polymorphism _FunctionValue is a C code primitive.postln. Here is the class definition for Ref.value_(thing) } set { arg thing. The ’value’ method returns the value of the instance variable ’value’.value.squared }.value. { 5. Ref objects have a single instance variable called ’value’. } } Here is how it responds : Ref.new(123). Ref: { var <>value.new(123). Ref. value = thing } get { ^value } dereference { ^value } asRef { ^this } AbstractFunction //behave like a stream next { ^value } embedInStream { arg inval.new.

1028 . r. Many different kinds of objects know how to play themselves.squared }. Object : Ref : this.postln. { PinkNoise. }). r = Routine({ arg appClockTime.new(123). So that dereference of a Function is still the Function.1) }. The difference is that no other classes override this method. Ref. AppClock.postln. { 5.value. ["AppClock has been playing for secs:".postln.rand2).close. In class Object dereference returns the object itself. Yet another example of polymorphism is play.1pi)*0.rand2. As implemented in Ref.play.5.appClockTime]. w.05. 130)).postln. 5. { 5.dereference() this. dereference just returns the value instance variable which is no different than what the value method does.bounds. 0.new(123). again just like the value message. // AppClock w = SCWindow("trem".play(r).alpha = cos(i*0. 10.ar(0. 1.moveBy(10. w. 60.value.bounds = w. 256.front. So what is the need for it? That is explained by how other classes respond to dereference. // Function ( var w. Rect(512. }). w.yield.dereference. Ref.postln. w. 360.postln.5+0.squared }.dereference.dereference() 5.dereference.yield.value.Where: Help→Language→Polymorphism Ref also implements a message called ’dereference’ which is another good example of polymorphism.postln.do({ arg i. The dereference message means "remove any Ref that contains you".

Where: Help→Language→Polymorphism ) ( // SynthDef x = SynthDef("Help-SynthDef". 3]. 2. // Pattern Polymorphism allows you to write code that does not assume anything about the implementation of an object. ) Pbind(\degree. PinkNoise.inf)). { arg out=0.ar(out. but rather asks the object to "do what I mean" and have the object respond appropriately.play. Out.ar(0. 1. Pseq([0.play. 1029 .1)) }).

// posts 12 1030 .value. z = makeCounter. // x and z are functions which refer to different instances of the variables curVal and stepVal x.Where: Help→Language→Scope ID: 290 Scoping and Closure SuperCollider has nested scoping of variables.value.postln. For example : The function defined below within makeCounter can access all of the arguments and variables declared in makeCounter. stepVal in the // enclosing function are referred to here within.value. 100). stepVal=1. but also to those declared in any enclosing (defining) contexts. curVal = curVal + stepVal. // return result // each invocation of makeCounter creates a new set of variables curVal and stepVal x = makeCounter. // posts 199 x.value.value(10. // posts 10 x. Other code can call the returned function at some later time and it can access and update the values contained in makeCounter at the time when the inner function was instantiated.postln. // return a function : { var temp. A function can refer not only to its own arguments and variables.value. temp = curVal. 1).postln. temp } }. curVal &amp. makeCounter = { arg curVal=0. // posts 99 z.postln. ( var makeCounter. // temp is local to this function. // posts 11 z.postln.value(99.

postln.value.value.Where: Help→Language→Scope x. // posts 399 ) Note that even though the function which defines curVal and stepVal has completed execution. the capturing and availability of variables defined in outer contexts by inner contexts even when the outer contexts may have completed execution. its variables are still accessible to those functions that were defined within its context. 1031 .postln.value. // posts 13 z. This is known as lexical closure. // posts 299 z.postln.

number number * number number / number number % number number ** number addition subtraction multiplication division modulo exponentiation Bitwise arithmetic number &amp.Where: Help→Language→SymbolicNotations ID: 291 Catalog of symbolic notations in SuperCollider Arithmetic operators Math operators apply to many classes. 3] == [1. 3] 1032 . 2. [1. including arrays and other collections. Using a basic math operator on a Symbol swallows the operation (returns the symbol) \symbol* 5 symbol number + number number . number number | number number << number number >> number number +>> number bitwise and bitwise or bitwise left shift bitwise right shift unsigned bitwise right shift Logical operators object == object object === object object != object object !== object equivalence identity not equal to not identical to Objects may be equivalent but not identical. 2.

postln.choose } a != 1 or: { "second condition". true // a and b are the same array instance number < number number <= number number > number number >= number comparison (less than) comparison (less than or equal to) comparison (greater than) comparison (greater than or equal to) logical And logical Or Boolean &amp. 2.&amp. false].&amp. Boolean Boolean | | Boolean When a function is the second operand. no inlining will be done and performance will be slower.choose } a != 1 and: false { "second condition".postln. false].Where: Help→Language→SymbolicNotations true [1. 2. a == 1 and: { "second condition". a === b.postln. or | | . [true. 3] false // a and b are two different array instances with the same contents a = b = [1.. [true. This is recommended for speed.choose } second condition true 1033 . 3] === [1. If you use &amp. 2.postln. [true. false]. these operators perform short-circuiting (i. 3]. a = 1. [true. the function is executed only when its result would influence the result of the operation). false].choose } second condition true a == 1 or: true { "second condition".e. With and: and or: second-argument functions will be inlined.

setB) | (setB . the second condition will cause an error if a is nil. a.notNil is a safeguard to ensure the second condition makes sense.postln.postln.setB intersection of two sets union of two sets difference of sets (elements of setA not found in setB) symmetric difference set -.set (setA – setB) == ((setA . 3 ] 1034 .wrapAt(int) @| @ integer collection/array indexing: . 4. 6.setA)) a = Set[2. a.clipAt(int) Set operators set &amp. 9]. because nil does not understand addition.b Set[ 2. b = Set[5. 7].notNil and: false { "second condition". 5.at(index) or [index] @@ integer collection/array indexing: . 3. (a = a+1) < 5 } second condition false Array and Collection operators object ++ object collection +++ concatenation collection lamination (see [J_concepts_in_SC]) collection @ index collection collection collection collection/array indexing: . a.Where: Help→Language→SymbolicNotations In this case. 6. (a = a+1) < 5 } a = 10. a .foldAt(int) | @| integer collection/array indexing: .notNil and: { "second condition". 7. 8. set set | set setA . a = nil. 4.

3] [ 0. 2. 3 stream <<< object add the object’s compile string to the stream 1035 . 4. 2. 9. 3. 3] 0. 9 ] ((a-b) | (b-a)) Set[ 2. bottom-top) ugen @ ugen create a Point with 2 UGens number @ number intersection of two rectangles union of two rectangles (returns a Rect whose boundaries exactly encompass both Rects) rect &amp.rand << ". 8 ] Geometry operators x @ y returns Point(x.\n".Where: Help→Language→SymbolicNotations b . 2.a Set[ 8. 1. to write output to the post window. stream <<* collection add each item of the collection to the stream Post << [0. right-left. "<< 20. 4. rect rect | rect IOStream operators stream << object represent the object as a string and add to the stream A common usage is with the Post class. 8 ] a -.b Set[ 2. 1. 9. y) point @ point Point(left. 1. 1. top) @ Point(right. 3 ] Post <<* [0. top. Post<< "Here is a random number: Here is a random number: 13. bottom) returns Rect(left. 2. 3.

object !? function execute function if object is not nil a = [10. 20)) }.Where: Help→Language→SymbolicNotations Post<<< "a string" "a string" stream <<<* collection add each item’s compile string to the stream Conditional execution operators object ? object ?? object function nil check (no .new(parent. 5]. In this example. 1036 . Rect(0. or used.value) nil check (.postln }).choose ? 10. f = { | slider. { 20. the second expression’s value will be used. { SCSlider. ?? evaluates the function conditionally (only when needed). it will be the first object. parent| slider = slider ?? slider. }. ?? { } is generally recommended. a = [nil. ? always evaluates the second expression. If the first line inside the function instead read slider = slider ? SCSlider.choose ?? 20. 0. nil]. 20)).new(parent.postln }). 10.. 100.rand). Especially useful when the absence of an object requires a new object to be created.do({ (a. even if its value will not be used.do({ (a.value.choose.rand }). function is inlined) If the object is nil.value_(0). 100. 0. Rect(0. a new slider would be created even if it is not needed. otherwise. If the function defines no variables. the function will be inlined for speed. it’s critical that a new SCSlider not be created if the object was already passed in.

15. f = { | a| f. 0 ] object -> object creates an Association.value // error: nil does not understand + a + 5 }.value a !? { a+5 } }. // equivalent of: if (a. 0 // a is incremented twice.rand } ! 5 [ 8.dup(number) 15 ! 5 [ 15. f = { | a| f.value(2) 7 Miscellaneous operators object ! number object. a = 0.notNil) { "ran func".postln }.Where: Help→Language→SymbolicNotations a !? { "ran func". it behaves like Array. { 10. 15. 3. 15 ] If the object is a function. function). 9.fill(number. and returns the value of the first. 15. but the return value (1) // comes from the first increment (0 + 1) 1037 . used in dictionaries bypass value of second expression expression <! expression This operator evaluates both expressions. 8. Used when an operation requires a variable not to be empty.postln }. nil // no error f.

60 // == (10+2) * 5 a * 5 } <> {| a| a + 2 }..at(0) == $A ’’ or \ define a literal Symbol: ’abc’ === \abc "" define a literal String [item.Where: Help→Language→SymbolicNotations (a = a + 1) <! 1 (a = a + 1) a // a’s value reflects both increments 2 function <> function function composition operator This operator returns a new function.. \b -> 2]) ‘ (backtick or backquote) define a Ref: ‘1 == Ref(1). f = { | a| f.] define a Set – any Collection class name can be used other than Set #[item. 385.(10).([10..] define an Array containing given items Set[item. An array as argument is passed through the chain: f. item. 2570 ] // == ([10. item.. ‘(a+1) == Ref(a+1) $ \ inside a string or symbol... escapes the next character "abc\"def\"ghi" abc"def"ghi ’abc\’def\’ghi’ abc’def’ghi 1038 . 75. [ 60.] define a literal Array (a:1. 75. 512]+2) * 5 Symbolic notations to define literals/other objects character prefix: "ABC". which evaluates the second function and passes the result to the first function. b:2) define an Event (same as Event[\a -> 1. 512]). item.

at(index) – Instr.. c| define function/method arguments.Where: Help→Language→SymbolicNotations \t \n \l \r \\ { } #{ } (_ * 2) tab character newline character linefeed character carriage return character \character define an open function define a closed function define a function { | a| a * 2 } (see [Partial-Application]) Argument definition define function/method arguments | a.( ) SomeClass.method(*array) Class and instance variable access Inside a class definition (see [Writing-Classes]): classvar<a.method(obj2) or method(obj1. <>c. arguments after a and b will be placed into c as an array | a..at is a good example call the method with the arguments in an array obj1 method: obj2 same as obj. myObject. c = myArray #a. b . b.(anArgName: value) keyword addressing of function or method arguments f. Define a class variable with a getter method (for outside access) Define a class variable with a setter method Define a class variable with both a getter and setter method Define an instance variable with a getter method (for outside access) var <a. obj2) This works only with single-argument methods. c = assign consecutive elements of myArray to multiple variables myArray assign first two elements to a and b. the rest as an array into c Where f is a function evaluate the function with the arguments in parentheses f. b . b.(*argList) evaluate the function with the arguments in an array f. c| #a. 1039 .. >b..[index] Equivalent to SomeClass.

3. 3] * [2. except that the results of each operation are concatenated..copyRange(i. 3. 2..: a[1. [ 6. 3. [ 4.f 1040 . 3.b) (a. j. not added as another dimension) .envirGet abc = value compiles to \abc. 3.c) (. invoke the setter: (myObject. 4 ]. 9] produces an array 0 through b not legal (no endpoint given) a. 4] [ [ 2. <>c. 4] [ 2.. 7. ^someExpression Inside a method definition: return the expression’s value to the caller define a setter for an instance variable myObject. a.g..Where: Help→Language→SymbolicNotations >b.instVar = x. 6..9) produces [1.. Define an instance variable with a setter method Define an instance variable with both a getter and setter method These notations do not apply to variables defined within methods.copyRange(i.. 5. 8 ].g.: (1.s .instVar_(x).. 12 ] ] output length is the shorter of the two arrays use folded indexing instead of wrapped indexing .g. x) instVar_ { } Array series and indexing (a. 5. 3] *. 12 ] [1.envirPut(value) Adverbs to math operators (see [Adverbs]) e.b) (a.t [2.j] a[j.j] a[i. 9 a. 2.t table-style .] access an environment variable abc compiles to \abc. 7.. b.copyRange(0.size-1) (this is OK–Array is finite) a[i.) produces an array consisting of consecutive integers from a to b e.x cross (like table.9] retrieves array elements 1. 9.: [1. j) e.k] a[. 6. 3.. 3. j) a.

1041 .Where: Help→Language→SymbolicNotations .0 .1 operator depth (see [J_concepts_in_SC]) etc.

10). // function call syntax with trailing function arg (1..10).squared }. n..squared }. // receiver syntax with trailing function arg collect ((1. n.Where: Help→Language→Syntax-Shortcuts ID: 292 Syntax Shortcuts This file shows a number of syntax equivalences in the compiler..10). { arg n.10).10).. // function call syntax (1..collect { argn. // function call syntax with trailing function arg (1..squared }). n. __________________________________________________________________________ Example: multiple ways to write the same thing.10)) {| n| n. // receiver syntax collect((1. // receiver syntax with trailing function arg collect ((1.collect {| n| n.. some expressions can be written in many different ways. // function call syntax (1. // binary operator syntax // partial application syntax 1042 . {| n| n.10) collect: {| n| n.10) collect: { arg n. Because of the multiple syntax equivalences. // receiver syntax collect((1.10)) { argn. // new argument syntax (1..squared }. n..squared }.squared }.squared }).squared }).. All of the following do the same thing and compile to the same code.collect({| n| n.squared }).squared }. n.collect({ arg n.10). // binary operator syntax // old argument syntax (1.

squared .f you can write: defining instance variable accessor methods instead of writing: Thing { var x.x = y. This adds another 26 variations to the 13 variations above. x = z.squared ). // receiver syntax collect((1. 10)... // function call syntax (1. y) f(g(x)) x. nil.squared ).f(y) x. } } you can write: Thing { var <>x.10).10). you can write: use a selector as binary operator instead of writing: min(x.collect( _. // binary operator syntax You could even start expanding out the equivalent of (1.10) which is really a shortcut for series(1.g. __________________________________________________________________________ functional and receiver notation instead of writing: f(x.series(nil.10)..x_(y) p..10) collect: _. y) x min: y you can write: 1043 . x { ^x } x_ { arg z.Where: Help→Language→Syntax-Shortcuts (1. _. } calling an instance variable setter method instead of writing: p. This could also be written 1.

envirSet(9). you can write: Set[3. 4. while { a < b } { a = a * 2 }. {\def}).add(4).new. {\abc}.do {| x| x. you can write: if (x<3) {\abc} {\def} z.play }. 4) create a collection instead of writing: Set. you can write: # x. get environment variable instead of writing: ’myName’. z.at(0).at(1). while({ a < b }.do({| x| x.add(3). 1044 .play }). you can write: Point(3. you can write: myName = 9.add(5). instantiate object instead of writing: Point. y = z.envirGet myName you can write: set environment variable instead of writing: ’myName’.{ a = a * 2 }). 5] moving blocks out of argument lists instead of writing: if (x<3.new(3. y = z. 4).Where: Help→Language→Syntax-Shortcuts multiple assignment instead of writing: x = z.

new(thing) ‘thing you can write: calling the ’value’ method instead of writing: f.at(i) z[i] you can write: indexing with ’put’ instead of writing: z.value(x) f. z[i] = y. y).Where: Help→Language→Syntax-Shortcuts shorter argument lists instead of writing: { arg x.(x) you can write: indexing with ’at’ instead of writing: z.put(i. you can write: creating IdentityDictionaries instead of writing: you can write: 1045 . x < 2 } you can write: {| x| x < 2 } shorthand for Symbols instead of writing: ’mySymbol’ \mySymbol you can write: creating a Ref instead of writing: Ref.

performList(\method.msg(a..copyRange(4.] a. or Array. _) {| x| a + x } a + _ {| x| [a.Where: Help→Language→Syntax-Shortcuts IdentityDictionary[’a’->1.1. b.16) (1..11) (1. x.1.. b) } you can write: object.series(6.copyToEnd(4) a[4. *array) object.3.’b’->2] (a: 1. b.method(a.8) a[4.msg(a. array) partial application instead of writing: {| x| object..16) . _.. _] 1046 .4] calling performList instead of writing: you can write: object.2) series(1. x. b.y| object. b) {| x.1) you can write: series(1.series(16. or .8] you can write: a.nil.3.msg(a. b.msg(a. y) } object. x] } [a. b: 2) creating arithmetic series instead of writing: Array.11) accessing subranges of Arrays instead of writing: a. a.copyFromStart(4) a[. _.

Where: Help→Language→Syntax-Shortcuts {| x| (a: x) } (a: _) __________________________________________________________________________ 1047 .

fmt=01. 3. Reading error dumps Error objects and error handling Common primitive errors A common network error A common warning 1. set=00) 1048 . and/or any arguments of the method call . flg=11. 4.a dump of the receiver of the method that caused the error.blech // no class implements this method. therefore you’ll get an error // error text ERROR: Message ’blech’ not understood. there are usually three parts: . gc=01. 5. 2.a dump of the call stack to the point of the error For example: 1. // receiver and args RECEIVER: Integer 1 ARGS: Instance of Array { indexed slots [0] } // call stack CALL STACK: DoesNotUnderstandError-reportError arg this = <instance of DoesNotUnderstandError> Nil-handleError arg this = nil arg error = <instance of DoesNotUnderstandError> Object-throw (02207560.the error text .Where: Help→Language→Understanding-Errors ID: 293 Understanding errors 1. Reading error dumps When sc3 reports an error to the user.

showing how you can use the variables listed for each call in the call stack to help locate the error. Call stack: Order of execution in the call stack is in reverse: the top of the stack shows the most recent calls. Receiver and arguments: The method was applied to an integer (1). Here is a slightly more complex example. Most call stacks for errors will show the same top three calls as shown here (calling the method reportError on an error class. the code is compiled into a function definition and executed. Following is the meat: the error happened when an object was not understood. "Message ’xxx’ not understood" means that you attempted to use the method xxx on a class that does not implement it. it happened inside a function definition. In this case. You can ignore these three calls. with no arguments (the size of the arguments array is 0). 1049 . Continuing to read down. Error text: A string describing the error. calling handleError on Nil. and calling throw on the error object). this function definition simply refers to the text submitted to the interpreter. Debugging is much easier if you understand what the error output means. (Every time you highlight a block of code and press the enter key. it all began with the instruction to interpret and print a command line.Where: Help→Language→Understanding-Errors arg this = <instance of DoesNotUnderstandError> Object-doesNotUnderstand arg this = 1 arg selector = ’blech’ arg args = [*0] < closed FunctionDef > (no arguments or variables) Interpreter-interpretPrintCmdLine arg this = <instance of Interpreter> var res = nil var func = <instance of Function> Process-interpretPrintCmdLine arg this = <instance of Main> Each of these parts provides valuable information about the cause of the error. So.) And.

flg=11. a.075067 (02207560. } }). RECEIVER: Integer 6 ARGS: Instance of Array { indexed slots [0] } CALL STACK: DoesNotUnderstandError-reportError arg this = <instance of DoesNotUnderstandError> Nil-handleError arg this = nil arg error = <instance of DoesNotUnderstandError> Object-throw arg this = <instance of DoesNotUnderstandError> Object-doesNotUnderstand arg this = 6 arg selector = ’ecky_ecky_phtang’ arg args = [*0] < FunctionDef in closed FunctionDef > var b = 6 Function-loop arg this = <instance of Function> < FunctionDef in closed FunctionDef > var a = 5 Routine-prStart arg this = <instance of Routine> arg inval = 1542. fmt=01.postln. gc=01. // "NI!!!!" ERROR: Message ’ecky_ecky_phtang’ not understood. b.rand. set=00) 1050 .Where: Help→Language→Understanding-Errors Routine({ var a.wait. a = 5.ecky_ecky_phtang. loop { var b.play. b = 20.

postln }. you should look for a function defining the variable "b" that is called within another function defining "a" inside a routine. but inside a method in the class library? There may be a bug in the method. we do not rethrow the error." try .blech } { | error| "next line". 2. "oops". On an error. The second function can rethrow the error if desired. allowing you to decide which errors will be reported and which suppressed.postln. You can also catch exceptions that occur within functions by executing the function with "try" or "protect" instead of "value. the whole thing is selected. On an error. execute the second function before 1051 . Any code (whether in the class library or any user application) can throw an error any time as follows: Error("This is a basic error.throw. or you may have thought the method took a certain kind of argument when in fact it expects something else.. Note that there are two calls identified as "FunctionDef in closed FunctionDef" and that they can be distinguished by the variables contained within.execute the first function. but with a routine commencing within the scheduler (Routine({. If you double click on the construction "ClassName-methodName" in the call stack.Where: Help→Language→Understanding-Errors Reading from the bottom this time. execute the second function and suppress the error. execution did not begin with the command line. try { 1. Error objects and error handling sc3 implements error reporting using Error objects. then. Then you can press cmd-J to open the method definition and look at the source code.. oops next line protect . In this example. The earlier call (second from the bottom) defines the variable "a" while the other defines "b.play).})."). to trace the flow in chronological order: this time. which are instances of the class Error or one of its subclasses. What if the error occurred not inside a function definition that you wrote." To locate the error in the code.executes the first function. so the error is swallowed and execution continues to the end.

flg=11. fmt=01. oops // without protect. gc=01.Where: Help→Language→Understanding-Errors reporting the error. Common primitive errors 1052 . try { 1+1 } 2 // can’t add a Point to an integer . this would not be posted ERROR: Message ’blech’ not understood. Non-error objects can be thrown using the class Exception. 0) } { 2*5 } 10 3.binary op failed error // result of catch func is returned instead try { 1+Point(0.postln. try { 1+1 } a Function More recent builds (since early August 2004) do return the function’s value. This is useful when the steps before the protect make some changes that need to be undone if an error occurs. protect { 1. See the method Environment-use for an example. "oops". try and protect do not return the value of the function to the caller if there is no error. set=00) Prior to August 2004.postln }.blech } { | error| "next line". RECEIVER: Integer 1 ARGS: Instance of Array { indexed slots [0] } CALL STACK: DoesNotUnderstandError-reportError arg this = <instance of DoesNotUnderstandError> (02207560.

#[0.put(1. 1. { myGUIObject.defer. Literal arrays cannot be manipulated–they can only be indexed.Index not an Integer. Index not an Integer Arrays can be indexed only with integers (or. 2] is a literal array.value_(newValue) }. #[0. AppClock is the only clock that can execute GUI manipulation because it is a lower priority thread. you’ll get a "Does not understand" error! 1053 . Solution: write your GUI updates as follows. Solution: copy the array first. 2]. floats). 2 ] . If the CPU is busy with audio synthesis or maintaining accurate scheduling for musical events. .at(\1) ERROR: Primitive ’_BasicAt’ failed. 3) [ 0. 3) ERROR: Primitive ’_BasicPut’ failed. 3.asInteger—note that if the object cannot be converted into an integer. #[0.operation cannot be called from this Process. in builds since August 2004. 1. 2].Where: Help→Language→Understanding-Errors . This is usually the results of performing a GUI operation within a routine or scheduled function that is executing on some clock other than AppClock. They cannot be changed internally.put(1. #[0. 2]. AppClock events will be delayed until the CPU is free enough. Solution: use . Attempted write to immutable object. 1.Attempted write to immutable object.copy. defer schedules the function on AppClock. 1.

Arrays have a finite size. [ nil. 1.put(5. [0.newClear instead of . then the array will be truncated. nil. 2]. a. If you’re not sure. 5) ERROR: Primitive ’_BasicPut’ failed.put(3.at(\1.extend(max(i+1.new(4). 2]. 1. 1. 5 ] Note that if the argument to extend() is smaller than the array. Index out of range. 100). 1. a = [0. 1).Index out of range.put(5. use . 1. 2. 2 and 3 as indexes (4 elements starting with 0). use max: i = rrand(5. a. you’ll get this error. nil.asInteger) 1 . 5) [ 0. a. a. 10).put(i. If you try to put an object into an array slot but the slot does not exist because the array is too small. If it’s a new array.put(3.extend(6). nil. Solution: extend the array. nil. Why i+1? An array with size 4 allows 0. ERROR: Primitive ’_BasicPut’ failed.new. 2]. [0. 1). 2]. 1 ] 1054 . 1.newClear(4).size)).Where: Help→Language→Understanding-Errors #[0. Index out of range. a = Array. a = Array.

This warning can be safely ignored. left over from crashes. A common network error Exception in World_OpenUDP: unable to bind udp socket This is because you have multiple servers running.9 3FECCCCC CCCCCCCD // { 0.dumpByteCodes.rand. A common warning WARNING: FunctionDef contains variable declarations and so will not be inlined.killAll 5.postln } }.coin } SendSpecialUnaryArithMsgX ’coin’ (15) F9 00 09 JumpIfFalsePushNil 9 2C 0A 0D 25 C1 38 PushInt 10 // { 10. One can’t cause them to quit via OSC (the boot button). BYTECODES: (16) 0 1 3 6 8 10 12 15 40 0D 2C PushLiteral Float 0. // inlined { while { 0. even if you get this warning.coin } { 10. Your code will still run.9.Where: Help→Language→Understanding-Errors 4. Inlining is a compiler optimization that takes the operations inside a function and places them in the main line of the containing function. unexpected quits etc. For instance.9.rand. // use this to remove them: Server.postln } SendSpecialUnaryArithMsgX ’rand’ SendSpecialMsg ’postln’ (0) FD 00 0D JumpBak 13 F2 BlockReturn a FunctionDef in closed FunctionDef 1055 .def.

. The compiler renders this into a single code block. { synth = Synth("someSynth".loop. }). the other is the while loop’s action. }. optimized.args. // not inlined { while { 0.def.free. // inlined.. there’s no way around un-optimized code. To wit. In this case. it’s necessary for the compiler to push function definition objects onto the stack. If you’re very concerned about speed.9. If. 2. however.wait. One is the condition for the while loop. you can use this warning as an indicator that you might be able to optimize something in your code further.Where: Help→Language→Understanding-Errors This function contains two other functions.postln } }. then that function requires a separate execution frame. BYTECODES: (7) 0 2 4 6 04 00 04 01 C2 0C F2 PushLiteralX instance of FunctionDef in closed FunctionDef PushLiteralX instance of FunctionDef in closed FunctionDef SendSpecialMsg ’while’ BlockReturn a FunctionDef in closed FunctionDef Inlined code will run faster. but you’ll get stuck notes Routine({ var synth. one of the functions defines a variable. using jump instructions to handle the looping and exit.coin } { vara.clock. 1056 . [. thisThread.sched(10.])..rand.dumpByteCodes. a. // variable here prevents optimization a = 10.. because pushing and using different execution frames is extra work for the virtual machine. { synth. Sometimes.

( Routine({ var func. 2. }.clock.free.])..Where: Help→Language→Understanding-Errors }).value. [\free. but no stuck notes Routine({ { var synth. the synth variable changes on each iteration.play. The first routine can be optimized because there is no variable declaration inside the loop. // this variable is local to the function synth = Synth("default"). synth]. so the notes will be terminated as expected. { synth.play. But. [\play. // not inlined. { func. thisThread.5..sched(10. { synth. You get a warning. synth].free. ) 1057 . but it’s better because the results are correct. [. synth = Synth("someSynth".args. }).play..wait. }.postln.loop }).. Thus the first note will never terminate. meaning that by the time the first release happens.postln.clock. thisThread. In the second case.wait.loop. A solution to the above problem is to use a function with local variables. 1. }. }). each note has its own synth variable. you don’t have access anymore to the first note. func = { varsynth.sched(4. }).

Where: Help→Language→Understanding-Errors 1058 .

14 Linux 1059 .

PS/2. you can query another name than "/event" by passing an argument. // symbolic device name d = LID("/dev/input/trackball").deviceRoot+"/event". looking up its name and closing them again. tablet) and busses (serial. gamepad. // device name relative to LID. which supports many input devices (mouse. trying to open all that it finds.deviceTable. typically // /dev/input/event[0-9].Where: Help→Linux→LID ID: 294 // ========================================================= // LID – Linux Input Device // ========================================================= // // This class provides a way to access devices in the linux input // layer. When using a userspace daemon like udev. the results is returned and can later be accessed by LID.deviceRoot d = LID("gamepad").deviceRoot++"/"++name++"*") 1060 . (the search will be: LID. // meaningful names can be assigned to devices. // raw device name d = LID("/dev/input/event4"). USB).buildDeviceTable // // // // // buildDeviceTable builds a table of the devices found in LID. // ========================================================= // Opening a device // ========================================================= // // Input devices are accessed through device nodes. keyboard. // build a table of the available devices: LID. // joystick.

product.info. it is passed the event type.info.vendor.info.info. ( 1061 . d.asHexString(4). d.asHexString(4).h d. d.Where: Help→Linux→LID LID.caps.name. Event type and event code constants can be found in // /usr/include/linux/input. // is likely to give the info that the devices could not be opened. // ========================================================= // Querying device capabilities // ========================================================= // // Device capabilities are reported as event type and event code // mappings. code and current value. // ========================================================= // Event actions (raw events) // ========================================================= // // The device’s ’action’ instance variable can be used for event // notifications.dumpCaps.buildDeviceTable( "mouse" ). d. as "mouse" // uses another interface (you can of course access mice via the "event" interface) // ========================================================= // Querying device information // ========================================================= d.

specs via LID»*register. // button a 1062 .mouseDeviceSpec). 0x0120].postln } ) d. // rumble (toggles ff) mode: #[0x0001.action = { | evtType.Where: Help→Linux→LID d. evtCode.asHexString(4).action = nil.asHexString(4). ( // key rumble: #[0x0001.type.asHexString(4).action = { | slot | [slot.register(’Logitech Trackball’. LID. 0x0102]. ( d. evtValue]. 0x0120). slot. New specs can be added to LID.rawValue]. // mode (switches h and l) a: #[0x0001.asHexString(4). // Add a custom device spec for a Logitech gamepad ( LID.postln.slot(0x0001.code. 0x0103]. actions can be bound to specific events. slot. } ) // ========================================================= // Device specs // ========================================================= // // Device specs are mappings between event codes and symbolic control // names. evtCode. evtValue | [evtType. // ========================================================= // Event actions (raw slot events) // ========================================================= // // When ’action’ is nil.register(’Logitech WingMan RumblePad’. // Add a mouse device spec for a Logitech trackball LID.

( LID. 0x0125].postln }. // button c x: #[0x0001. 0x0011].value]. // button s // abs lx: #[0x0003. 0x0005]. // hat y slider: #[0x0003. 0x0000]. slot // actions can be assigned by using the symbolic control name.Where: Help→Linux→LID b: #[0x0001. // hat x hy: #[0x0003. 0x0001]. 0x0123]. // button b c: #[0x0001. 0x0121]. 0x0002] // slider )). 0x0124]. // There is also a default keyboard device spec. // button y z: #[0x0001.postln } } ) // ========================================================= 1063 .keyboardDeviceSpec. 0x0122]. // left joystick y rx: #[0x0003. slot. 0x0010]. 0x0127].action = { | slot | [\a. // left front button r: #[0x0001.value].action = { | slot | [key. slot. // right front button s: #[0x0001. // right joystick y hx: #[0x0003. // left joystick x ly: #[0x0003.keys. ) // ========================================================= // Event actions (symbolic slot events) // ========================================================= // // When a device spec was registered for a given device name. // button x y: #[0x0001. 0x0128]. d[\a]. // right joystick x ry: #[0x0003. // button z l: #[0x0001. 0x0006].do { | key | d[key]. 0x0126].

isGrabbed. 0 ) d. d. // setLEDState( evtCode. devices can be grabbed to prevent use in // other applications (including X).grab.caps as events of type 0x0011 d = LID("/dev/input/event0").Where: Help→Linux→LID // LED’s // ========================================================= // some devices have LEDs which can be turned on and off.close. // ========================================================= // Closing devices // ========================================================= d.close. These show up // with d.ungrab }. // LED’s can be turned on: d. Be careful when grabbing mouse or // keyboard! d[\b].setLEDState( 0x0. 1 ) // (LED 0x0 should be available on any keyboard) // and off: d. 1064 . d.action = { d.setLEDState( 0x0. evtValue ): value should be 1 or 0 // ========================================================= // Grabbing devices // ========================================================= // // Given proper permissions.

// ========================================================= 1065 .closeAll.Where: Help→Linux→LID LID.

15 Mark_Polishook_tutorial 1066 .

15.1 Debugging 1067 .

edu/ matloff/UnixAndC/CLanguage/Debug.Where: Help→Mark_Polishook_tutorial→Debugging→1_Debugging ID: 295 My code doesn’t work! Code doesn’t always run as one might hope.html go to 2_Syntax_errors 1068 .javaworld.cs. SuperCollider sometimes tells you why and some- When SuperCollider does supply information. it’s often because the code works but not as expected.html http://heather.html http://www. http://www. it’s usually to describe either a syn- tax or a runtime error.com/javaworld/jw-07-1996/jw-07-javascript. an effect) and adding instead of multiplying (biasing an amplitude instead of scaling it). instead of before. For context. In such cases. Ex- ample of this are synths (nodes) that execute in the wrong order (a source placed after. here are links that describe debugging (fixing errors in code) in languages other than SuperCollider. times it doesn’t.elanus.net/book/debugging. When SuperCollider doesn’t give information.ucdavis.

2. are all variable names and/or keywords spelled correctly in a program? Are state- ments terminated by semi-colons? If syntax or grammar errors are found. Use this when an error message identifies the line number on which a problem occured.. //////////////////////////////////////////////////////////////////////////////////////////////////// 1069 . a parenthesis or a square or curly brace is missing or used in the wrong context a required comma or semicolon is missing or used improperly //////////////////////////////////////////////////////////////////////////////////////////////////// Two helpful commands in the SuperCollider Edit menu: 1.• ----------------------------------• ERROR: Command line parse failed nil //////////////////////////////////////////////////////////////////////////////////////////////////// Common errors 1. the name of a class or a variable is mispelled a variable is used before being declared. 3..Where: Help→Mark_Polishook_tutorial→Debugging→2_Syntax_errors ID: 296 Syntax and grammar Before it actually runs a program. Such mes- • ERROR: Parse error in file ’selected text’ line 1 char 2 : 4. "Go to Line . For example. 4. Use "Find" to locate code that has been identified in error messages or to replace all instances of an improperly spelled word. SuperCollider writes a notification to the post window. SuperCollider examines the code to ensure that syntax and grammar are correct." transports you to the line number of your choice. 2. "Find" searches for words or phrases. sages are descriptive but terse.

Where: Help→Mark_Polishook_tutorial→Debugging→2_Syntax_errors go to 3_Runtime_errors 1070 .

are ERROR.Where: Help→Mark_Polishook_tutorial→Debugging→3_Runtime_errors ID: 297 Runtime errors Runtime errors occur while a program is executing. RECEIVER. set=00) 1071 . etc. ARGS. fmt=01. flg=11. RECEIVER: Integer 3 ARGS: Instance of Array { indexed slots [0] } CALL STACK: DoesNotUnderstandError-reportError arg this = <instance of DoesNotUnderstandError> Nil-handleError arg this = nil arg error = <instance of DoesNotUnderstandError> Object-throw (057E7560. multiplication. //////////////////////////////////////////////////////////////////////////////////////////////////// Common errors 1. and CALL STACK. 4.createRuntimeError SuperCollider prints a four-part error notification to the post window. 3. gc=01. as in The parts of the notification ERROR: Message ’createRuntimeError’ not understood. subtraction. an object receives a message which it doesn’t understand a binary operation (addition. 2.) can’t be performed a value other than true or false appears in a conditional (boolean) test a file can’t be opened (a primitive fails) //////////////////////////////////////////////////////////////////////////////////////////////////// Object doesn’t understand In the case of 3.

The RECEIVER section names the the class of the object to Read The ARGS section says how many arguments were included in the message. which the message was sent. the CALL STACK from the bottom to the top to see where the error happened.Where: Help→Mark_Polishook_tutorial→Debugging→3_Runtime_errors arg this = <instance of DoesNotUnderstandError> Object-doesNotUnderstand arg this = 3 arg selector = ’createRuntimeError’ arg args = [*0] < closed FunctionDef > (no arguments or variables) Interpreter-interpretPrintCmdLine arg this = <instance of Interpreter> var res = nil var func = <instance of Function> Process-interpretPrintCmdLine arg this = <instance of Main> //////////////////////////////////////////////////////////////////////////////////////////////////// The ERROR section explains what went wrong. means going from Reading from bottom to top Process-interpretPrintCmdLine to Interpreter-interpretPrintCmdLine to Object-doesNotUnderstand to Object-throw to Nil-handleError to 1072 .

ARGS. gc=C4. see how it works (how it prints the notification). fmt=01. and CALL STACK headers in the post window explain the problem: class Char have no knowledge of multiplication. //////////////////////////////////////////////////////////////////////////////////////////////////// DoesNotUnderstandError-reportError is the mechanism that prints the error notification to the post window. Instances of ERROR: Message ’*’ not understood. flg=00. RECEIVER.Where: Help→Mark_Polishook_tutorial→Debugging→3_Runtime_errors DoesNotUnderstandError-reportError which is the first line in the stack. RECEIVER: Character 97 ’a’ ARGS: Instance of Array { indexed slots [1] 0 : } CALL STACK: DoesNotUnderstandError-reportError arg this = <instance of DoesNotUnderstandError> Nil-handleError arg this = nil arg error = <instance of DoesNotUnderstandError> Object-throw arg this = <instance of DoesNotUnderstandError> Character 98 ’b’ (067F5470. //////////////////////////////////////////////////////////////////////////////////////////////////// The ERROR. set=01) 1073 . Select it and press cmd-j to //////////////////////////////////////////////////////////////////////////////////////////////////// Execute $a * $b to create another runtime error message.

wait. (the integer 10) time error. ) 1074 . // b declared but not initialized.postln }. do a * b // .start. the variable a is initialized to an integer and the variable b isn’t initialized. // a is declared and initialized varb. the value that SuperCollider uses for unitialized data) will create a run- ( vara = 10.postln } // print the value of i if it doesn’t equal 3 { (a * b). if(i != 3) { i. which is a problem if b is nil }) }). i. // when i equals 3.. Multiplying a by b (nil.. t. so it defaults to nil t = Task({ 4.Where: Help→Mark_Polishook_tutorial→Debugging→3_Runtime_errors Object-doesNotUnderstand arg this = $a arg selector = ’*’ arg args = [*1] < closed FunctionDef > (no arguments or variables) Interpreter-interpretPrintCmdLine arg this = <instance of Interpreter> var res = nil var func = <instance of Function> Process-interpretPrintCmdLine arg this = <instance of Main> //////////////////////////////////////////////////////////////////////////////////////////////////// Unitialized variable (binary operation fails) Here.do({ arg item. 1.

and CALL STACK headers describe the problem. fmt=01. //////////////////////////////////////////////////////////////////////////////////////////////////// a Task 0 1 2 ERROR: binary operator ’*’ failed. gc=CC.Where: Help→Mark_Polishook_tutorial→Debugging→3_Runtime_errors //////////////////////////////////////////////////////////////////////////////////////////////////// The printout shows the code ran successfully until the index. RECEIVER. flg=00. set=01) 1075 . The ERROR. which is when a * b happened. reached 3. ARGS. RECEIVER: nil ARGS: Instance of Array { indexed slots [2] 0 : 1 : } CALL STACK: DoesNotUnderstandError-reportError arg this = <instance of BinaryOpFailureError> Nil-handleError arg this = nil arg error = <instance of BinaryOpFailureError> Object-throw arg this = <instance of BinaryOpFailureError> Object-performBinaryOpOnSomething arg this = nil arg aSelector = ’*’ arg thing = 10 arg adverb = nil Integer-* arg this = 10 arg aNumber = nil arg adverb = nil < FunctionDef in closed FunctionDef > arg item = 3 arg i = 3 Integer 10 nil (067D92B0. i.

false.000000 (no arguments or variables) //////////////////////////////////////////////////////////////////////////////////////////////////// True. RECEIVER: Integer 4 CALL STACK: MethodError-reportError arg this = <instance of MustBeBooleanError> Nil-handleError arg this = nil arg error = <instance of MustBeBooleanError> Object-throw arg this = <instance of MustBeBooleanError> Object-mustBeBoolean arg this = 4 < closed FunctionDef > (no arguments or variables) Interpreter-interpretPrintCmdLine arg this = <instance of Interpreter> var res = nil var func = <instance of Function> Process-interpretPrintCmdLine arg this = <instance of Main> 1076 . as in if(x=4) { "this is ok"}.Where: Help→Mark_Polishook_tutorial→Debugging→3_Runtime_errors Integer-do arg this = 4 arg function = <instance of Function> var i = 3 < FunctionDef in closed FunctionDef > Routine-prStart arg this = <instance of Routine> arg inval = 758. or other A value other than true or false in a boolean test. produces ERROR: Non Boolean in test.

if(x==4) { "this is ok"}. flg=00. RECEIVER: Instance of File { instance variables [1] fileptr : } CALL STACK: MethodError-reportError arg this = <instance of PrimitiveFailedError> Nil-handleError arg this = nil arg error = <instance of PrimitiveFailedError> Object-throw arg this = <instance of PrimitiveFailedError> Object-primitiveFailed arg this = <instance of File> File-length arg this = <instance of File> < closed FunctionDef > (no arguments or variables) nil (067D9970. wrong (a C code primitive failed). //////////////////////////////////////////////////////////////////////////////////////////////////// Primitive fails Asking for the length of a non-existent file creates a runtime error. gc=C4. ERROR: Primitive ’_FileLength’ failed. f.Where: Help→Mark_Polishook_tutorial→Debugging→3_Runtime_errors //////////////////////////////////////////////////////////////////////////////////////////////////// Correcting the test clause fixes the problem. fmt=00. Failed. The notification shows what went f = File("i_don’t_exist". set=01) Interpreter-interpretPrintCmdLine arg this = <instance of Interpreter> var res = nil var func = <instance of Function> 1077 . "r").length.

Where: Help→Mark_Polishook_tutorial→Debugging→3_Runtime_errors Process-interpretPrintCmdLine arg this = <instance of Main> //////////////////////////////////////////////////////////////////////////////////////////////////// 1078 .

2 First_steps 1079 .15.

000000 0 UseSeparateIO?: PublishPortToRendezvous 0 57110 SuperCollider 3 server ready.. sampleRate=44100. NumPrimitives = 548 compiling dir: pass 1 done Method Table Size 3091264 bytes Number of Method Selectors 2880 Number of Classes 1744 Number of Symbols 6926 Byte Code Size 129989 compiled 299 files in 1. notification is on 1080 .1 addr 2130706433 RESULT = 256 Class tree inited in 0." More text. One is called "localhost server" and the other is "inThe words "localhost" in the black ternal server.0. The document functions as a "Post Window. init_OSC compiling class library. such as booting 57110 SC_AudioDriver: start numSamples=512.61 seconds compile done prGetHostByName hostname 127.Where: Help→Mark_Polishook_tutorial→First_steps→1_Startup ID: 298 To begin Navigate to the folder (the directory) in which SuperCollider resides and double-click on it (the red An untitled document with text such as and white balloon icon). //////////////////////////////////////////////////////////////////////////////////////////////////// Two more windows On the bottom of the screen are two more windows.." so-called because Su- perCollider uses it to "post" notifications." Click on the "boot" button on the localhost server. box of the button turn red and the word "Boot" on the button changes to "Quit.0.09 seconds ’/Applications/SuperCollider3/SCClassLibrary’ appears in the top left of the screen.

SuperCollider documents generally have .. however. or cmd-o.rtf) and several other formats.sc appended to their file names. as well. Use File->New or cmd-n to create new documents.. //////////////////////////////////////////////////////////////////////////////////////////////////// Workspace windows Open existing SC documents with File->Open.Where: Help→Mark_Polishook_tutorial→First_steps→1_Startup will print to the post window. Activate the internal server. The localhost server is now ready to be used. read //////////////////////////////////////////////////////////////////////////////////////////////////// go to 2_Evaluating_code 1081 . in the same way. if you wish. SuperCollider can and write documents in Rich Text Format (.

Then put the cursor anywhere on the line (shown The server will synthesize audio and text that looks something like Synth("-613784702" : 1000) will appear in the post window.kr(4. 102].15).ar([11. 401]. Press command-period (cmd-. 33].1). 1100). 0. above) and press <enter>.05 The server will synthesize audio and text that looks something like 1082 .) to stop synthesis. 0. select all the lines and press <enter>. examples with more than one line often are placed in enclosing parentheses. 0.play first make sure that the localhost server is booted.Where: Help→Mark_Polishook_tutorial→First_steps→2_Evaluating_code ID: 299 Synthesizing sound To run (evaluate) one line of code.kr(Env.ar( in: freq: rq: ) }. 700.ar([100. 0. In such cases.play ) Saw.1) * Saw. //////////////////////////////////////////////////////////////////////////////////////////////////// To run more than one line of code. Lag.kr(LFNoise0. left of the bottom one. Then press enter (to run the example). 1) * EnvGen. select the text by clicking immediately to the right of the top parenthesis or Or.ar([400. ( { RLPF. such as { SinOsc. 0. press cmd-shift-b. To help with the selection process.sine(10)) }. with the cursor to the right of the top parenthesis or the to the left of the bottom parenthesis.

0.5) }. Press command-period (cmd-.ar([400.5) }. send the scope message directly to the example. To The button on the default server of your choice intially will say Press it again to start recording." Press it once and it will say record >. 0. //////////////////////////////////////////////////////////////////////////////////////////////////// Scoping sound To scope whatever it is you’re synthesizing (create a graphical display of the waveform): 1.play 4. 1083 .Where: Help→Mark_Polishook_tutorial→First_steps→2_Evaluating_code Synth("-393573063" : 1000) will appear in the post window.5) * Saw. choose the a default server. 0. run { SinOsc. //////////////////////////////////////////////////////////////////////////////////////////////////// Recording sound The localhost and the internal server windows have buttons.ar([400. evaluate your code as described above. 401].ar([11. 33]. 401]. 0. record. to activate recording. 2. make sure the internal server is running (press its boot button) press the default button on the internal server window. { SinOsc. to stop sound synthesis. on the far right. 3. 33].scope(2) which will produce a window with the title of "stethoscope. For example. 0." As a shortcut to steps 2 through 4.) to stop synthesis. then evaluate s.5) * Saw. 0.scope(2) Press cmd-.ar([11. "prepare rec.

Where: Help→Mark_Polishook_tutorial→First_steps→2_Evaluating_code //////////////////////////////////////////////////////////////////////////////////////////////////// go to 3_Comments 1084 .

either precede text with // as in // Everything up to the end of the line is a comment or place text on one or more lines between /* and */ as in /* This is a comment */ If (when) evaluated. Program- It’s also the case that some find it help- ful to write programs by first notating comments and then filling in matching code. //////////////////////////////////////////////////////////////////////////////////////////////////// Use Format->Syntax Colorize (or cmd-’) to syntax-colorize comments. //////////////////////////////////////////////////////////////////////////////////////////////////// To write a comment in SuperCollider.Where: Help→Mark_Polishook_tutorial→First_steps→3_Comments ID: 300 Comments Comments are descriptive remarks that are meant to be read by humans but ignored by computers. 1085 . a comment will return nil. mers use comments to annotate how code works or what it does. which is the value SuperCollider uses for unitialized data.

Where: Help→Mark_Polishook_tutorial→First_steps→3_Comments //////////////////////////////////////////////////////////////////////////////////////////////////// go to 4_Help 1086 .

if one exists. cmd-shift-?.). Nil. Array. will open.help". //////////////////////////////////////////////////////////////////////////////////////////////////// To see every SuperCollider helpfile evaluate Help. and the Find command To see source code for class definitions. lect the name of a class and press cmd-shift-?. //////////////////////////////////////////////////////////////////////////////////////////////////// Class definitions.dumpToDoc("SuperCollider UGens (Unit Generators)") Each line of text in the document that appears contains a word to which is appended the suffix ". double-click on topics which you’d like to see a help file and press Another useful document is More-On-Getting-Help. select the name of a class and type cmd-j To see how a class or classes implement a particular message. such as SinOsc. there are help files for classes (capitalized words. To see the main help page.help" appended to the word when double-clicking to open the corresponding help file. Double-click any of the words to select them and press cmd-shift-? Omit the ". A help file. selecting anything). etc. Se- In general.all //////////////////////////////////////////////////////////////////////////////////////////////////// To see all unit generators helpfiles evaluate Help("Help/UGens"). select the message name and press cmd-y. 1087 .Where: Help→Mark_Polishook_tutorial→First_steps→4_Help ID: 301 Help SuperCollider has a built-in help system. message implementations. press cmd-shift-? (without first From that page.

net/pseudonym/ 1088 .create. application) For example.tar. as in // change the name of the path (the argument after the ’>’ sign.hfbk-hamburg. evaluate (in the Terminal grep -r LFSaw /Applications/SuperCollider_f Because lines in the terminal application break according to the size of the window and not through schemes that enhance readability.ucsb. An introductory course by Nick Collins and Fredrik Olofsson: http://www.de:8888/MusicTechnology/437 The SuperCollider user or developer lists (or both).psi-o.Where: Help→Mark_Polishook_tutorial→First_steps→4_Help Use the Find and Find Next commands. available through the Edit menu. to see all documents that use the LFSaw class.sicklincoln.edu/mailman/listinfo/sc-dev David Cottle wrote an extensive SC2 tutorial which he is now updating for SC3.ucsb.create.de:8888/MusicTechnology/6 The SuperCollider users mailing list archive: http://swiki.gz The pseudonym tutorial: http://www. http://www. to search for text in the frontmost document //////////////////////////////////////////////////////////////////////////////////////////////////// grep Use grep in the Terminal (in the Applications->Utilities folder) to search for all occurences of a given word or phrase.hfbk-hamburg.org/code/sc3tutorial. as appropriate grep -r LFSaw /Applications/SuperCollider_f/ > /Users/yourHomeDirectory/Desktop/grep_results //////////////////////////////////////////////////////////////////////////////////////////////////// Additional sources The SuperCollider wiki: http://swiki.edu/mailman/listinfo/sc-users http://www. it may be easier to write grep results to a file.

Where: Help→Mark_Polishook_tutorial→First_steps→4_Help The MAT tutorial (UC-Santa Barbara) tutorial: http://www.mat.ucsb.edu/ sc/ //////////////////////////////////////////////////////////////////////////////////////////////////// 1089 .

15.3 Miscellanea 1090 .

Where: Help→Mark_Polishook_tutorial→Introductory_tutorial ID: 302 For SuperCollider 3 //////////////////////////////////////////////////////////////////////////////////////////////////// First_steps 1_Startup 2_Evaluating_code 3_Comments 4_Help //////////////////////////////////////////////////////////////////////////////////////////////////// Synthesis 1_The_network 2_Prerequisites 3_SynthDefs 4_Rates 5_Buses 6_Controls 7_Test_functions 8_UnaryOp_synthesis 9_BinaryOp_synthesis 10_Subtractive_synthesis 11_Groups 12_Playbuf 13_Delays_reverbs 14_Frequency_modulation 15_Scheduling Please see the Japanese translation by Shigeru Kobayashi //////////////////////////////////////////////////////////////////////////////////////////////////// Debugging 1_Debugging 1091 .

edu 1092 . 2004 //////////////////////////////////////////////////////////////////////////////////////////////////// Mark Polishook polishoo@cwu.Where: Help→Mark_Polishook_tutorial→Introductory_tutorial 2_Syntax_errors 3_Runtime_errors //////////////////////////////////////////////////////////////////////////////////////////////////// last revised: August 2.

15.4 Synthesis 1093 .

dumpClassSubtree message Get a list of ugen filters in SuperCollider 3.dumpClassSubtree message to the Filter class.dumpClassSubtree. as of 19. (Object.04.Where: Help→Mark_Polishook_tutorial→Synthesis→10_Subtractive_synthesis ID: 303 Filtering The basic idea of subtractive synthesis is similar to making coffee: to remove unwanted components from the final product.5. as in Filter. includes [ DetectSilence Formlet Ringz SOS FOS Slew Median LPZ2 [ BRZ2 BPZ2 HPZ2 ] Slope LPZ1 [ HPZ1 ] MidEQ BPF [ BRF ] LPF [ HPF ] 1094 .dumpClassSubtree prints all SuperCollider classes) //////////////////////////////////////////////////////////////////////////////////////////////////// The list of Filters. something goes through a filter //////////////////////////////////////////////////////////////////////////////////////////////////// The . by sending the .

660. 1095 .Where: Help→Mark_Polishook_tutorial→Synthesis→10_Subtractive_synthesis RLPF [ RHPF ] LeakDC Lag [ Ramp Lag3 Lag2 ] Decay2 Decay Integrator TwoPole [ APF TwoZero ] OnePole [ OneZero ] Resonz ] Look in Help/UGens/Filters in the SuperCollider help system to see filter help files and numerous examples. LPF.1).5. 6) ) ) }). removes high-frequency content and emphasizes the cutoff frequency. ( SynthDef("subtractive". a low-pass filter to subtract high-frequency content from an input source.kr(8000.ar(440. //////////////////////////////////////////////////////////////////////////////////////////////////// Use LPF. { Out.load(s). 0.ar( Pulse.ar( 0. 0. // the source to be filtered Line. ) // control the filter frequency with a line Synth("subtractive") //////////////////////////////////////////////////////////////////////////////////////////////////// RLPF. a resonant low-pass filter.

) ( // activate left and right channels Synth("noiseToPitch". 1]). ) 1096 .kr(1. 0. LFNoise0.005] ) ) }). Out. ) Synth("passLowFreqs2") //////////////////////////////////////////////////////////////////////////////////////////////////// Resonz is a very. 2400)]. [\out. LFNoise0. [0. 221] + LFNoise0.kr(4. 2400).ar( 0.kr(3. 100.ar(mul). { arg out = 0.2). [LFNoise0. Transform noise into pitch with a sharp cutoff.ar( out. 660).1 ) ) }). RLPF. mul = 1. 1]). 0. 0. very. Resonz.load(s).ar( WhiteNoise.ar([220.Where: Help→Mark_Polishook_tutorial→Synthesis→10_Subtractive_synthesis ( SynthDef("passLowFreqs2".ar( Saw. very strong filter. { Out. ( SynthDef("noiseToPitch". 110.005. 0. 600. Use it to emphasize a frequency band. 1. \mul.kr(4. [\out. Synth("noiseToPitch".load(s). 600. 200). \mul.

Where: Help→Mark_Polishook_tutorial→Synthesis→10_Subtractive_synthesis //////////////////////////////////////////////////////////////////////////////////////////////////// go to 11_Compound_synthesis 1097 .

ar(500. linked list is a data structure that makes it easy to order and reorder nodes. 400.1) }. 0. are often best divided into component parts. which is the means to specify a collection of nodes. resusable.ar(Saw. because they use more than a few ugens. eg. 0. eg. Another feature of groups is they allow synths to receive messages from a single point of control.022) }. { Saw. Evaluate the follow- Help("Help/UGens").dumpToDoc("SuperCollider UGens (Unit Generators)") //////////////////////////////////////////////////////////////////////////////////////////////////// Many synthesis processes. or { Formlet. and easier to read.11. the head synth runs before the tail synth. one message to the group goes to all of nodes that belong to the group. //////////////////////////////////////////////////////////////////////////////////////////////////// Groups are linked lists The important technical feature of groups is that the nodes they contain are items in a linked list.01. This can make code modular.Where: Help→Mark_Polishook_tutorial→Synthesis→11_Groups ID: 304 The simplest synthesis processes use a single ugen.scope. list is the "head" and the last item is the "tail. The ability to order synths is essential when sending source audio through an effect. 0. The Group class. such as a reverb or a filter. ing line to see a list of all UGen help files.ar(22). allow synths to be placed in order so one synth verifiably executes before another. //////////////////////////////////////////////////////////////////////////////////////////////////// 1098 . provides a mechanism through which to control several synths at once. through their head and tail mechanisms. 0.scope Most of the SuperCollider help documents for the UGens show other such examples." A The first item in a linked Groups.

067. linked lists. The next two lines Group(0) Group(1) will appear in the transcript window. the localhost and internal servers each boot with two predefined groups: and the evaluate the RootNode default_group (see their help files). evaluate a synthdef ( SynthDef("ringModulation". Group(1) is indented to show that it //////////////////////////////////////////////////////////////////////////////////////////////////// New synths are attached by default to the head of the default_group.org/wiki/Linked_list http://en. branches from Group(0). 1) 1099 . trees See the Server-Architecture document for a definition of a node in SuperCollider or look to the Wikipedia for a general discussion of nodes. start the localhost server and then s. // 1st.org/wiki/Tree_data_structure //////////////////////////////////////////////////////////////////////////////////////////////////// RootNode and default_group By default. linked lists. 441. Group(0) is the rootnode group and Group(1) is the default_group. { Out.wikipedia. http://en.ar([440.queryAllNodes.ar( SinOsc. and trees.org/wiki/Node http://en.wikipedia. To see this. 0.ar( 0. Mix.Where: Help→Mark_Polishook_tutorial→Synthesis→11_Groups Nodes.wikipedia.013].

Group(0) | | default_node . Group(1) as the branching de- fault_node and Synth 1003 (or some such number) as a leaf attached to the default_node. ) // 3rd.load(s). Rootnode .Where: Help→Mark_Polishook_tutorial→Synthesis→11_Groups * SinOsc. Out. ) Group(0) Group(1) Synth 1003 will appear in the transcript window.queryAllNodes. 109]. evaluate a synthdef ( SynthDef("pitchFromNoise". { argout = 0. 0.Group(1) / / Synth 1003 //////////////////////////////////////////////////////////////////////////////////////////////////// An example with two synths.ar([111. 0. It shows Group(0) as the rootnode. make a synth ( Synth("ringModulation").ar( 1100 . // 1st.2) ) ) }). tell the server to list its nodes ( s. ) // 2nd.

to the head of a list: the "ringModulation" synth. tell the server to list its nodes ( s.Group(1) 1101 . [\out.Group(0) | | default_node . Synth("pitchFromNoise". Synth 1005 is Synth 1004. ) // 2nd.load(s).ar( WhiteNoise. first in the list because of the way nodes are attached.kr(2.005 ) ) }). Synth 1005 and 1004 (or similar such numbers) are leaves attached to the default_node. 660).ar(15).queryAllNodes. was evaluated and placed at the head of the list (in front of Synth 1004). ) // 3rd. ) The printout in the transcript window Group(0) Group(1) Synth 1005 Synth 1004 shows that Group(0) is the rootnode and Group(1) is the default_node. LFNoise0. the "pitchFromNoise"s synth. Resonz. 1]). Rootnode . was evaluated first and attached to the head of Group(1). 0. Then Synth 1005. by default. 110. make 2 synths ( Synth("ringModulation").Where: Help→Mark_Polishook_tutorial→Synthesis→11_Groups out.

1 ) ) ) }). 4. SynthDef("secondNode-filter". ) 1102 .001].kr( LFNoise0. 201]. the two synths below must be evaluated in the order in which they’re given .ar( In.load(s).ar( 0.ar(0. 500. 1000).05) ) }). Saw.ar([200. a filter that processes its input. LPF. Synth("firstNode-source"). Lag. ( SynthDef("firstNode-source".Where: Help→Mark_Polishook_tutorial→Synthesis→11_Groups / / \ \ Synth 1004 (tail) Synth 1005 (head) //////////////////////////////////////////////////////////////////////////////////////////////////// It’s the responsibility of the user to make sure that nodes on the server are ordered properly. 2). { ReplaceOut. 0.load(s).because the first synth is source material for the second synth.ar( 0. 0.kr([4. For this reason. { Out. ) // evaluate "secondNode-filter" first // "firstNode-source" will go at the head of default_node ( Synth("secondNode-filter").

( Synth.tail(s). Synth.tail(s.head(s.head( source.queryAllNodes. "secondNode-filter") ) ( s. use . can then be evaluated in any order as long as they’re attached to the appropriate group. ) The idea is that the groups are attached first to the default_group in the desired order.tail messages to attach the the nodes to the default_group).Where: Help→Mark_Polishook_tutorial→Synthesis→11_Groups ( s. The synths // run the code to see a diagram of the nodes ( s. Synth. ( source = Group. ) //////////////////////////////////////////////////////////////////////////////////////////////////// Or.head(s).queryAllNodes. // attach the group to the head of the default_node effect = Group. // attach the group to the tail of the default_node ) ( // add the synths to the appropriate groups Synth. ) //////////////////////////////////////////////////////////////////////////////////////////////////// Or. "firstNode-source"). ) 1103 . "firstNode-source"). assign the synths to groups.head and .head( effect.queryAllNodes. "secondNode-filter").

load(s).01]) ) }.Where: Help→Mark_Polishook_tutorial→Synthesis→11_Groups Rootnode | | default_node /\ / \ Group | | Synth Group | | Synth //////////////////////////////////////////////////////////////////////////////////////////////////// Set a control for all of the synths in a group.kr([0. Out. SynthDef("synthNumber3".1]). PinkNoise.kr([2.ar( 0. Out.ar( 0.2. SynthDef("synthNumber2".load(s).67]) ) }.2. [0. BrownNoise.ar(mul) * LFNoise0. 0. 3]) ) }.2.load(s). { arg mul = 0. { arg mul = 0. // each of the synthdefs below has a control for amplitude (mul) ( // build 3 synthdefs and a group SynthDef("synthNumber1".1]).ar(mul) * LFNoise2.1]). [0.ar(mul) * LFNoise1. ) ( // make a group 1104 . [0.99. 1. Out. { arg mul = 0. WhiteNoise.kr([1.79.ar( 0.

rrand(0.head( myGroup.set(\mul.Where: Help→Mark_Polishook_tutorial→Synthesis→11_Groups myGroup = Group. ) // set the \mul control of each of the 3 synths in the group myGroup. ) //////////////////////////////////////////////////////////////////////////////////////////////////// go to 12_Playbuf 1105 . ) ( // attach 3 synths Synth. Synth. "synthNumber3").queryAllNodes. &q