/* The SuperCollider programming language */
/* Celia says: "Everything is an Object!" */

/*
Before we start making any sound, a basic understanding of the language and its controls is needed. First of all, certain things will NOT work on the language side of the program... namely, UGens. UGens and the classes that describe them are meant only for the server so it can access the UGen plug-in code. As a general rule, the language side of SC can't deal with anything that is appended with .ar or .kr. e.g. SinOsc.ar is worthless on the language side.
In SuperCollider, EVERYTHING is an object, and multiple instances of an Object can be created. Objects can execute functions that are defined for that Object, can store data for an instance of that object, and also inherit characteristics from super classes. Here is an example (along with the class definitions of List).
First, we will create an instance of a List object of size 10, and assign it to the variable 'l'. We can see from the class definition that the 'new' message in the class definition returns us a new object (the * symbolizes this).
*/
l = List.new(10); // return a new object with space for 10 values
/* we can now send the 'add' message to the list. List-add takes one argument, an element to add to the list */
l.add(100);
l;
/* the *new message is special... if an object doesn't receive a message and if it repsonds to 'new', then the interpreter will assume it is there. Below, we create a new List with 20 slots for information, and store it to the variable 'l' */
l = List(20);
l;
/* Notice that the previous List that was assigned to 'l' is overwritten. Once a reference to an object is no longer needed, SC garbage collects it and reuses its memory. This previous data is lost!
You can also append messages to each other. Here, a new List is created, and its slots are set to 'nil'. Then, those slots are filled with the value '120'
*/
l = List.newClear(20).fill(120);
// this is the same as the above:
l = List.newClear(20);
l.fill(120);
l.add(130); // add the value 130 to the list. .add will grow the list if it needs to.
l.add(\first);
// List objects also respond to methods that it inherits from! In this case, SequenceableCollection
l.sort;
l; // notice that this changes 'l'
l.sqrt; // and math
l; // doesn't change 'l', returns a new List
l = l.pow(2) * 100; // operate with and change 'l'
l;
l.size;
l.put(0, 8734);
l.put(0, l.at(0) * 2)
// a GUI that shows what List will respond to... its Super-class as well as its sub-classes
List.browse;
// exploring a class's inheritance structure can show what a class can really do.
l = List.fib(10).addUniqueMethod(\josh, {"Hello".postln; "Josh"});
// whatever is evaluated last in a function is returned.
z = l.josh;
z.value;
m = List.fib(10);
m.josh; // throws an error! There is no method called 'josh' in this instance of List
// the array instance var for list has a getter < and a setter >
l.array;
l.array = [1, 2, 3];
l; // l's data has been changed.
l.array;
// check if l is a certain kind of Object
l.isKindOf(Object); // => true... everything is an Object
l.isKindOf(List); // => true... it is a List
l.isKindOf(SimpleNumber); // => false...not a SimpleNumber
// access just part of the data... List at the 0th element.
l.at(0).isKindOf(SimpleNumber); // TRUE!, the 0th element of l is a Simple Number
// you can also check to see what kind of object a var represents
l.class; // => List
l.class == List; // you can also check and see if the class equals a List
/*
In general, we have been executing one line of code at a time and using the global variables a-z (minus s) for examples. However, when you design a program that will run on its own, you are more likely to create a block of code that will be executed, with additional timing and functionality all declared and built into that block, along with variables that are only local to that block of code. To do this, you should start enclosing your code inside a set of parens.
I should also mention that the paren checker in SC's editor is a little weak. I suggest adding the program 'Text Extras' to your set of tools.
All SC code in parens must first declare variables with the 'var' statement.
*/
( // start of my block;
// declare variables... vars MUST start with a lowerCase letter (no numbers)
var val1, val2;
// you can have multiple lines of variables, and you can make some basic
// assignments to those variables
var fixedval = 250, aFunc;
// Functions can be described within your code block with curly braces {}
// Unlike a block of code, they can take an argument declaration, (also
// starting with a lower case letter) followed by var declarations. args
// and vars are local to the function. Here, the var aFunc is described as
// a function.
aFunc = {arg firstval, secondval;
var product;
product = firstval * secondval;
};
val1 = aFunc.value(fixedval, 10);
val2 = aFunc.value(fixedval, 200);
// re-assign a val to fixedval
fixedval = val2;
// compile data as an array of values and post them
[val1, val2, fixedval].postln;
);
/*
Iteration: while, for, forBy, do, and Arrays
*/
// while takes 2 args, a test-function and a body-function. Useful for looping.
// MAKE sure you control the values involved in your test... failure to
// do so can create endless loops!
i = 0;
while( {i < 10}, {i.postln; i = i + 1;} );
// while also has a 'shortcut' mode. Give it one function arg, where what is
// is a true/false boolean
i = 0;
while({
i.postln;
i = i + 1;
i < 10};
);
// for takes a start value, an end value and a function, and iterates over it.
// The current value (on each turn of the loop) is made available to the function as
// its first arg. The initial value of the for loop is returned from the
// function. The increment is by 1
z = for(2, 10, {arg me; me.postln});
z.value; // the start value is returned
// forBy can alter the step increment:
forBy(2, 10, 3, {arg me; me.postln});
// do can be used to control the number of times something loops (if an integer is the
// receiver) or it can iterate over a collection. Two values are available
// to the function associated with do... the items it is iterating over, and an incremented value
// Integer.do will step from 0 below the Int. for funtions have two args, a value that is
// passed in, and an incrementer. With int.do, the first and second args will be the same value
5.do({arg me, inc; [me, inc].postln;}); // in this case, 5 expands to [0, 1, 2, 3, 4]
// iterate over an array of values. Returns the collection that is iterated over.
y = Array.newClear(5);
z = [2, 4, 6, 8, 10].do({arg me, inc; [me, inc].postln; y[inc] = me * inc});
z;
y; // the array 'y' now has values
y = y * 200; // change those values (for next example)
// decalred vars have a 'scope'
(
var y, z; // this y and z only exist within the scope of this block
y = Array.newClear(5);
z = [2, 4, 6, 8, 10].do({arg me, inc;
[me, inc].postln;
y.put(inc, (me * inc));
y.postln;
});
);
y; // this y refers to the global var y...
// Arrays can be very handy for storing data that you may need to iterate over at a later
// time. Storing values to an array and accessing those values is an important skill.
// create an empty Array
a = [];
// or ..
a = Array.new;
// create an Array of a specific size, and set its values to nil
a = Array.newClear(10);
// craete an Array and fill it with the result of a function:
a = Array.fill(10, {arg me; me}); // notice the function takes an argument, similar to do
a = Array.fill(10, {10.rand}); // 10.rand will give ints between 0 and 9
// access the values of the Array with .at, based on the size of the array
(a.size).do({arg i; a.at(i).postln});
// use [] as a shortcut to .at:
(a.size).do({arg i; a[i].postln});
// or, iterate over the Array (which is a Collection!)
a.do({arg me; me.postln;});
// iterate AND operate on elements of the Array
a.do({arg me, i; var newval; newval = 100.rand; me.postln; a.put(i, newval)});
a; // is filled with new values
// multi-dimensional Arrays
a = Array.fill(10, Array.fill(10, {100.rand})); // 10 instances of the same array
a = Array.fill(10, {Array.fill(10, {100.rand})}); // 10 instances of different arrays
a.at(0).at(4); // accessing
a[0][4];
b = a.flat; // flatten the multi-dimensional array into a single array
b;
a;
a.sqrt; // will calculate the sqrt of all elements of the array
a.flat.clump(3); //flatten, then arrange in groups of 3
a;
/* Some handy operations on Numbers */
// math ops
2.reciprocal; // 1/number => 0.5
0.3.neg; // negative => 0.3
-0.3.abs; // absolute value => 0.3
0.3.ceil; // next integer up => 1
0.3.floor; // integer down => 0
0.3.round ; // round => 0
0.7.round(0.25); // round to the nearest 0.25 => 0.25
-0.7.sign; // returns 1 or -1 (depending on neg or pos) => -1
0.7.squared; // squares the number => 0.49
0.7.cubed; // cubed => 0.343
0.7.pow(7); // number to power of => 0.0823543
0.7.sqrt; // sqrt =>0.83666002653408
0.7.log; // base e log => -0.35667494393873
0.7.log2; // base 2 log => -0.51457317282976
0.7.log10; // base 10 log => -0.15490195998574
0.5pi.sin; // sin => 1
0.5pi.cos; // cos => 6.1230317691119e-17
0.5pi.tan; // tan => 1.6331778728384e+16
// also arcfuncs - asin, acos, atah
// also hyperbolicfuncs - sinh, cosh, tanh
0.2.isPositive; // returns true or false
0.2.isNegative;
2.odd; // true or false
2.even;
// pitch
60.midicps; // midi num to hertz => 261.6255653006
60.5.midicps; // quartertones! => 269.29177952702
60.06235.midicps; // 32nd tones! (you get the point) => 262.5695025797
440.cpsmidi; // hertz to midi => 69.0
12.midiratio; // scale factors for transposition => 1.99999... or 2
440 * -3.midiratio // transpose a hertz value down a minor 3rd => 369.99442271189
// amplitude - SC works with linear amplitudes (0 - 1)
0.dbamp; // convert dB to amp => 1
-6.dbamp; // => 0.5011872
0.5.ampdb; // amp to dB => -6.0205999132796
// If the items of an array can accept an operation, you can also apply that operation
// to the array itself
a = Array.series(10, 0, -3).postln.dbamp;
a;
/* For tonight
Explore the Array helpfile and class def, then its superclasses to see the methods that Array will respond to.
[Intro-to-Objects]
[Literals]
[Method-Calls]
[Assignment]
[Comments]
[Expression-Sequence]
[Functions]
[Scope]
[Control-Structures]
[Classes]
[Syntax-Shortcuts]
[SimpleNumber]
*/