[[SuperCollider]] is a free music programming language. It's a great tool for exploring [[Just Intonation]]. We're going to learn the basics of Additive Synthesis. In Additive Synthesis you layer sine waves to create more complex sounds. We'll create drones using sine waves in different ratios to hear the intervals. ## Installing SuperCollider 1. Download from [GitHub](https://supercollider.github.io) and open it. 2. From the Server menu, choose **Boot Server**. ### The sample rate mismatch error The most common error upon booting the server is this: ``` ERROR: Input sample rate is 48000, but output is 44100. Mismatched sample rates are not supported. To disable input, set the number of input channels to 0. could not initialize audio. Server 'localhost' exited with exit code 0. ``` To solve it (on a Mac), open your Audio MIDI Setup utility (`/System/Applications/Utilities`) Make sure the Audio Devices window is open (under the `Window` menu). Find the items with the microphone and the speaker, and make their Format settings match (44,100 Hz is fine). ![[audio-device-sample-rates.png]] ## Essential SuperCollider key commands ``` SHIFT-RETURN Run a line of code COMMAND-RETURN Run a block of code (multiple lines between parentheses) COMMAND-D Bring up the help file for the item at the text cursor. COMMAND-PERIOD Stop sound. ``` ## Making Tones: Three versions of the same code ``` // 1. Short form {SinOsc.ar(100,0,0.1)}.play // .(argument,argument,argument) must match order in documentation // 2. Same statement, long form: arguments are named explicitly. // Line breaks and white space are ignored. ( // parenthesis start a block of code intended to run together { // curly braces start a function (functions can make sound) SinOsc.ar( // sine wave oscillator, audio rate freq: 100, // pitch in Hz! human hearing is ~20-20,000 phase: 0, // ignore for now mul: 0.1) // volume. 1 is MAX & very loud. 0.1-0.2 is good }.play // close function -- play! ) // close block for easy COMMAND-RETURN execution of 2+ lines // 3. Same statement, one line. Explicit arguments can go in any order and skip arguments (like phase) that you don't need to change (default values listed in the documentation). {SinOsc.ar(mul: 0.1, freq:100)} // COMMAND-PERIOD Stop sound. ``` ### Listening to the Harmonic Series The [harmonic series](https://en.wikipedia.org/wiki/Harmonic_series_(music)) above any frequency f is: `f 2*f 3*f 4*f 5*f 6*f 7*f ...` This produces these notes: ![[full-harmonic-series-1.svg]] Let's hear them all one at a time: ``` f = 100; // single lowercase letters are global variables {SinOsc.ar(f, mul:0.1)}.play; // remember mul:0.1 -- volume low! {SinOsc.ar(f*2, mul:0.1)}.play; {SinOsc.ar(f*3, mul:0.1)}.play; {SinOsc.ar(f*4, mul:0.1)}.play; {SinOsc.ar(f*5, mul:0.1)}.play; {SinOsc.ar(f*6, mul:0.1)}.play; {SinOsc.ar(f*7, mul:0.1)}.play; {SinOsc.ar(f*8, mul:0.1)}.play; ``` ### Working with pitch letters instead of Hz To convert note names (A4 B4 C5 etc) to Hz, use `.midicps` on a midi note. `60.midicps // 60 is middle C on the piano` You can use arithmetic to find other MIDI notes. For example, if you want the F plus two octaves higher: `(60+12+12+5).midicps // middle C, (+12) is 12 semitones up, an octave, (+5) takes you from C to F` ## Just Intervals Let's hear a Just third. Look on the harmonic series again – where is a third? ![[Pasted image 20250109101109.png]] There are many, but the simplest relationships are the lowest, so let's use 4 and 5. Their relationship is a **5/4** ratio. (Why not 4/5? If the fraction < 1, it's an interval going down. If it's > 1, it's an interval going up.) Pick a starting note. ``` f = 60.midicps // MIDI note 60 is middle C {SinOsc.ar(f, mul:0.1)}.play; // listen to middle C {SinOsc.ar(f*5/4, mul:0.1)}.play; // multiply by the 5/4 ratio to get Just M3rd ``` Now let's compare that third from the harmonic series with the major third in equal temperament: ``` f*5/4 // the frequency of the Just major third (f+4).midicps // the frequency of the equal tempered major third ``` And let's hear the difference: ``` {SinOsc.ar(f*5/4, mul:0.1)}.play; // Just major third {SinOsc.ar(64.midicps, mul:0.1)}.play;` // equal tempered third ``` ### Mixing Many Tones `Mix.ar` lets you combine multiple frequencies into a single statement: ``` {Mix.ar( SinOsc.ar([f, f*5/4, f*3/2, f*7/4, f*9/4], 0, 0.1) )}.scope; ``` It adds all the waves together in a single channel. To make it stereo, wrap it in `Pan2.ar()` ``` {Pan2.ar( Mix.ar( SinOsc.ar([f, f*5/4, f*3/2, f*7/4, f*9/4], 0, 0.1) ) )}.scope; ``` Or you can use `Splay.ar()` to spread a list of tones evenly across the stereo field. No `Mix.ar()` needed. ``` {Splay.ar( SinOsc.ar([f, f*5/4, f*3/2, f*7/4, f*9/4], 0, 0.1) )}.play ``` ## Adding Motion Let's add some motion and life to our drones. Here, the volume is multiplied by a slowly moving sine wav. .kr means 'control rate' aka 'slow mode' 0.1 is cycles per second (0.1 hz is 1 sine wave every 10 seconds) We are multiplying our base `mul` value (volume) by the output of the `SinOsc.kr` which is a stream of numbers oscillating between `-1` and `1`. ``` {SinOsc.ar(f, mul:0.1 * SinOsc.kr(0.1))}.play; ``` Here, many slow sine waves move at slightly different speeds. Frequency `f` goes at `0.1`, `f * 5/4` at `0.15` and so on: ``` {Splay.ar( freq: SinOsc.ar([f, f*5/4, f*3/2, f*7/4, f*9/4], phase: 0, mul: 0.1 * SinOsc.kr([0.1, 0.15, 0.09, 0.13, 0.111])) ) }.scope; ``` Here we use a second, slow SinOsc.kr to modulate the frequency instead of the volume. Vibrato. f is our center frequency we are now **adding** the output of the SinOsc normally the SinOsc outputs a stream of numbers oscillating between `-1` and `1` but a `2 hz` spread is very narrow for vibrato. So we'll increase `mul: 5` **to the modulating SinOsc.kr, not the sound-producing SinOsc.ar (which always must be <1 because 1 is maximum volume)** Therefore this code will oscillate the frequency between `495` and 505. ``` f = 500; {SinOsc.ar(f + SinOsc.kr(freq: 3, mul: 5), mul: 0.2)}.play; ```