Overview

These are my note on control structures in SuperCollider.

Content

if-else, case, and switch

There are different ways of doing an if-else statement. The else-case is not necessary and can be omitted.

 
// Standard if
(
var x = 10;
if (x > 5, {
    "x is greater than 5".postln;
}, {
    "x is 5 or less".postln;
});
)
 
// Method style mit .if
(
var x = 10;
(x > 5).if({
    "x is greater than 5".postln;
}, {
    "x is 5 or less".postln;
});
)
 
// Only true case
(
var x = 10;
if (x > 5, {
    "x is greater than 5".postln;
});
)

The case statement executes the first true condition.

(
var x = 7;
case
    { x < 5 } { "x is small".postln }
    { x < 10 } { "x is medium".postln }
    { x >= 10 } { "x is large".postln };
)

The switch statement compares a value with different cases. The last case without a condition acts as a default.

(
var note = 60;
switch(note)
    {60} { "C".postln }
    {62} { "D".postln }
    {64} { "E".postln }
    { "Unknown note".postln }; // default case
)

Loops

The do loop repeats a block of code a specified number of times. An Iteration counter is passed to the loop body. You can also iterate over an collection, then the element is the first argument to the loop body and the index the second argument.

// Simple repetition
(
5.do({ |i|
    "Iteration: ".post;
    i.postln;
});
)
 
// Iterating over arrays
(
["C", "D", "E", "F", "G"].do({ |note, index|
    "Note ".post; index.post; ": ".post; note.postln;
});
)

The for loop iterates from a start value to an end value.

(
for(0, 10, { |i|
    i.postln;
});
)

The forBy loop iterates with a custom step size.

(
forBy(0, 20, 2, { |i|
    "Even number: ".post;
    i.postln;
});
)

The while loop repeats as long as a condition is true.

(
var i = 0;
while({ i < 5 }, {
    "i = ".post;
    i.postln;
    i = i + 1;
});
)

The loop creates an infinite loop. It is mostly used in Routines with .wait to create timed repetitions.

(
r = Routine({
    var count = 0;
    loop {
        "Count: ".post;
        count.postln;
        count = count + 1;
        1.wait; // wait 1 second
        if(count >= 5, { r.stop }); // stop after 5 iterations
    };
});
r.play;
)

Iteration over Collections

The collect method transforms each element of a collection and returns a new collection.

(
var numbers = [1, 2, 3, 4, 5];
var squared = numbers.collect({ |n| n * n });
squared.postln; // [1, 4, 9, 16, 25]
)

The select method filters elements that return true.

(
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var evens = numbers.select({ |n| n % 2 == 0 });
evens.postln; // [2, 4, 6, 8, 10]
)

The reject method removes elements that return true.

(
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var odds = numbers.reject({ |n| n % 2 == 0 });
odds.postln; // [1, 3, 5, 7, 9]
)

The detect method finds the first element that matches a condition.

(
var numbers = [1, 3, 5, 7, 8, 9];
var firstEven = numbers.detect({ |n| n % 2 == 0 });
firstEven.postln; // 8
)

Comparison Operators

Comparison operators test relationships between values.

(
var x = 10;
(x == 10).postln;  // true (equal)
(x != 5).postln;   // true (not equal)
(x > 5).postln;    // true (greater than)
(x < 20).postln;   // true (less than)
(x >= 10).postln;  // true (greater or equal)
(x <= 10).postln;  // true (less or equal)
)

Boolean Operators

Boolean operators combine or negate conditions.

(
var x = 10;
var y = 5;
(x < 5 || y < 10).postln;  // true (OR)
(x > 5 && y < 10).postln;  // true (AND)
(x > 5).not.postln;         // false (NOT)
)

Flow Control

The return statement (^) exits a Function early and returns a value.

(
f = { |x|
	if(x < 0, {
		^"Negative number!".postln; // ^ is return
	});
	x * 2;
};
)
 
f.value(-5).postln; // "Negative number!"
f.value(5).postln;  // 10

Exception Handling

The try block catches errors and prevents them from stopping the program.

// Basic error handling
(
try {
    10.foobar;  // "foobar" does not exist for integers
} {
    "Error caught!".postln;
};
)
 
 
// With error object
(
try {
  Error("Something went wrong").throw;
} { |error|
  "Caught error: ".post;
  error.errorString.postln;
};
)

Fork, Defer and Scheduling

fork returns a Routine and starts it. Runs in its own thread, non-blocking to the main thread.

(
fork {
    "Starting...".postln;
    2.wait;
    defer {
        "This runs in AppClock".postln;
        // GUI updates are safe here
    };
};
)

defer executes code in the AppClock thread. Useful for GUI updates from routines or other non-GUI threads.

AppClock.sched schedules code to run after a specified time.

(
AppClock.sched(2, {
    "This runs after 2 seconds".postln;
});
)