Using Buses in SuperCollider

Control Rate vs Audio Rate

SC works with two internal signal types or rates. When something is used with the extension .ar, this refers to audio signals (audio rate), whereas .kr uses the control rate. For both rates, buses can be created.


Creating Buses

An audio bus with a single channel is created on the default server s with the following command:

~aBus = Bus.audio(s,1);

A control bus with a single channel is created on the default server s with the following command:

~cBus = Bus.control(s,1);

Bus Indices

The variable ~aBus is the client-side representation of the Bus. The server only knows it by its bus index. Bus indices are counted upwards and can be queried with the following command:

~aBus.index
~cBus.index

The indices of user-defined audio buses start counting after all output an input buses. The number of input and output buses can be defined before booting a server. The default setting uses 2 input and 2 output buses.

Audio buses

Indices

Audio Buses

0...1

Outputs

2...3

Inputs

4

First user-defined bus

The number of input and output buses can be queried after boot:

s.options.numOutputBusChannels;
s.options.numInputBusChannels;

Audio Input

The SoundIn UGen makes it convenient to access the audio input buses without keeping track of the outputs. This node simply passes the first input to the firs output:

{ Out.ar(0,SoundIn.ar(0))}.play

Note that this is equivalent to using the proper offset with a regular audio input:

{ Out.ar(0,In.ar(s.options.numOutputBusChannels))}.play

Monitoring Buses

Any bus can be monitored with the builtin scope with the following command. The first argument defines the number of buses to be shown, the second the index of the first buses:

s.scope(1,~aBus.index,rate:'audio')

There is a short version, which has limitations and does not specify the bus type:

~aBus.scope()

Frequency Scope

Any bus can also be monitored with a frequency scope. The first arguments define the size. The third argument defines the bus to analyze, in this case the first output bus:

FreqScope.new(400, 200, 0, server: s);

Control Buses

This simple sawtooth node will be used for showing how to use control buses. It has one argument freq, which affects the fundamental frequency and uses the first hardware output:

~osc  = {arg freq=100; Out.ar(0,Saw.ar(freq))}.play;

Mapping a Control Bus

The map() function of a node can connect a control bus, identified by its index, with a node parameter:

~osc.map(\freq,~cBus.index);

Setting a Control Bus

After mapping the bus, the synth stops its sound., since the control bus is still set to the default value 0. This can be visualized with the scope command. A simple and quick way for changing the control bus to a different value is the set() function of a node. It can be used for all arguments of the node which are internally used for control rates:

~cBus.set(50);

Multichannel Buses

Both control and audio rate buses can be created as multi channel buses. A scope will automatically show all channels. Individual channels can be mapped with an offset in relation to the index of the first channel. The setAt() function can be used for changing individual channel values:

~mBus = Bus.control(s,8);

~mBus.scope;

~osc.map(\freq,~mBus.index+3);

~mBus.setAt(3,150);

Faust: Conditional Logic

The select2() directive can be used as a switch condition with two cases, as shown in switch_example.dsp

// switch_example.dsp
//
//
// Henrik von Coler
// 2020-05-28

import("all.lib");

// outputs 0 if x is greater 1
// and 1 if x is below 0
// 'l' is used as an implicit argument
sel(l,x) = select2((x>=0), 0, 1);

process = -0.1 : sel(2);

Filter Characteristics and Parameters

Filters have many applications in sound synthesis and signal processing. Their basic job is to shape the spectrum of a signal by emphasizing or supressing frequencies. They are the essential component in subtractive synthesis and their individual qualities are responsible for an instrument's distincive sound. Famous filter designs, like the Moog Ladder Filter, are thus standards in the design of analog and digital musical instruments.

Filter Characteristics

Regardless of the implementation details, both analog and digital filters can be categorized by their filter characteristics. These describe, which frequency components of the signal are passed through and which frequencies are rejected. This section describes the three most frequently used filer types.

The central parameter for most filter types is the cutoff frequency $f_c$. Depending on the characteristic, the cutoff frequency is that frequency which separates passed from rejected frequencies.

Lowpass

The lowpass filter (LP) is the most frequently used characteristic in sound synthesis. It is used for the typical bass sounds known from analog and digital subtractive synthesis. With the right envelope settings, it creates the plucked sounds. An LP filter lets all frequencies below the cutoff frequency pass. $f_c$ is defined as that frequency where the gain of the filter is $-3\ \mathrm{dB}$, which is equivalent to $50\ \%$. The following plot shows the frequency-dependent gain of a lowpass with a cutoff at $100\ \mathrm{Hz}$.

Highpass Filter

The highpass (HP) filter is the opposite of the lowpass filter. It rejects low frequencies and lets high frequencies pass. The following plot shows the frequency-dependent gain of a highpass with a cutoff at $100\ \mathrm{Hz}$.

Bandpass Filter

The bandbass (BP) filter is a combination of lowpass and highpass. It lets frequencies between a lower cutoff frequency $f_{low}$ and an upper cutoff frequency $f_{up}$ pass. The BP filter can thus also be defined by its center frequency

$f_{cent} = \frac{f_{up}+f_{low}}{2}$

and the bandwith of the so called passband

$b = f_{up}-f_{low}$.

The following plot shows a bandpass with a center frequency of $f_{cent} = 100\ \mathrm{Hz}$ and a bandwidht of $50\ \mathrm{Hz}$.

38

Fourier Series: Triangular

Formula

The triangular wave is a symmetric waveform with a stronger decrease towards higher partials than square wave or sawtooth. Its Fourier series has the following characteristics:

  • only odd harmonics

  • altering sign

  • (squared)

\begin{equation*} \displaystyle X(t) = \frac{8}{\pi^2} \sum\limits_{i=0}^{N} (-1)^{(i)} \frac{\sin(2 \pi (2i +1) f\ t)}{(2i +1)^2} \end{equation*}

Interactive Example

Pitch (Hz):

Number of Harmonics:

Output Gain:

Time Domain:

Frequency Domain:

Sampling & Aliasing: Sine Example

In the following example, a sine wave's frequency can be changed with an upper limit of $10\ \mathrm{kHz}$. Depending on the sample frequency of the system running the browser, this will lead to aliasing, once the frequency passes the Nyquist frequency:

Pitch (Hz):

Output Gain:

Time Domain:

Frequency Domain:

Sampling & Aliasing: Theory and Math

IEM Remote Control with PD

Controlling the IEM plugins with OSC messages, i.e. sent from another software or expressive interfaces, opens more possibilities than using only DAW automations. Each plugin in the suite comes with a OSC receiver, which can be enabled and listens to a defined set of messages.

All information for controlling the IEM plugins, including the defined OSC paths are included in the IEM documentation: https://plugins.iem.at/docs/osc/ The following example shows how to control the position of a virtual sound source, using the StereoEncoder plugin.


Setting up the Plugin

Open a UDP port for the plugin to listen on:

/images/spatial/iem-encoder-osc.png

Sending from PD

All parameters of the StereoEncoder can be controlled through OSC. The corresponding OSC paths and parameter ranges are listed here: https://plugins.iem.at/docs/osc/#stereoencoder

To assemble the complete OSC command, each plugin has an individual string: https://plugins.iem.at/docs/osc/#osc-messages The full OSC path for controlling the azimuth is:

/StereoEncoder/azimuth 40.0

The following PD patch uses no additional libraries and should work as it is. Both the IEM plugins and PD need to me running on the same machine. It snds to a port via netsend (click connect to localhost in the beginning) - it needs to be the same one opened by the plugin.

The OSC path is defined in the oscformat object. It can be changed, if other paramters should be controlled.

/images/spatial/pd_to_iem.png

NOTE:

Since a single encoder plugin opens an individual OSC port, each instance of the encoder plugin needs to open an individual port. The MultiEncoder allows the control of more sources (but in one channel). with a single port.

Max for Live: Live Object Model

Max's Live Object Model makes it possible to exchange data between Max for Live and any parameter of a Live session. The model is best described in the Max Online Documentation. and the Live API Overview

In the following examples, different Live parameters are controlled via LFOs or direct input to demonstrate the capabilities.


The Live Object Model

Working with the Live Object Model involves four objects:

  • The live.path object is used to select objects in the Live object hierarchy. It receives a message, pointing to the object which is to be accessed.

  • live.object is used to get and set properties and children of objects and to call their functions.

  • The live.observer object can subscribe to properties of objects and their children and gets regular updates on changes.

  • With the live.parameter~ object it is possible to control Live device parameters in real time.


Controlling the Live Set

This first example allows to change the playback speed of the Live session in BPM. The live object only needs the path to the Live set (live_set) and can then process the set tempo $1 message.

Setting the session tempo from Max for Live.

Setting the session tempo from Max for Live.


Triggering Clips

Each clip in Live's session view can be accessed with an individual path.

Once set with the goto ... message, the call fire message can trigger the sample.

Launching the first clip of the second channel from Max for Live.

Launching the first clip of the second channel from Max for Live.

This tutorial gives more insight on controlling all clip properties offered by Live: Hack Live 11 Clip Launching


Controlling Device Parameters

By controlling device parameters, any synth or effect inside a Live project can be automated from Max For Live patches. Although this is a very powerful feature, paths to the objects need to be tracked down by the indices of the channel, the plugin and the parameter.


Instrument Channels

In this example, the Granulator II is used. It can be installed via the Ableton Website. The first thing to do is find the right path for the device and parameter.

xxx.

oköas .


Main Channel

Main channel effects and plugins can be controlled in the same way as those in instrument channels, omitting the channel index.

Patch for controlling the cutoff frequency of a filter in the main channel.

Patch for controlling the cutoff frequency of a filter in the main channel.


Exercise

Exercise

Combine the above patches with the Max for Live sensor examples to directly control Live parameters with the Arduino.

Pure Data: Light Dependent Resistor

There is a variety of different approaches for receiving (and sending) data via a serial port in PD. The solution in this example relies OSC via serial and needs additional libraries for both the Arduino sender and the PD receiver. In return it offers a flexible approach for handling multiple sensors.


Breadboard Circuit

The breadboard circuit is the same as in the first Arduino sensor example:

/images/basics/ldr_input_fritzing.png

Arduino Code

For the following Arduino program, the additional OSC Library by Adrian Freed needs to be installed. It can be cloned from the repository or simply installed with the builtin package manager in the Arduino IDE (Tools->Manage Libraries). OSCMessage.h is included in the code. In addition, the type of serial connection is retrieved. The OSCMessage class is used in the main loop to pack the data and send it.

#include <OSCMessage.h>

#ifdef BOARD_HAS_USB_SERIAL
#include <SLIPEncodedUSBSerial.h>
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
#include <SLIPEncodedSerial.h>
 SLIPEncodedSerial SLIPSerial(Serial);
#endif

void setup() {

    Serial.begin(9600);
}

void loop() {

  int sensorValue = analogRead(A0);

  float voltage = sensorValue;

  // Serial.println(voltage);

  OSCMessage msg1("/brightness");
  msg1.add(voltage);
  SLIPSerial.beginPacket();
  msg1.send(SLIPSerial);
  SLIPSerial.endPacket();
  msg1.empty();

}

Pure Data Patch

The Pure Data receiver patch relies on the mrpeach externals: mrpeach GitHub Repository Like many externals, they can be installed by cloning the repository to one of PD'2 search paths - or by using Deken. The external is named mrpeach: Instructions for using Deken

Serial data is received with the comport object. All available devices can be printed to PD's console. The proper interface can be opened with an extra message or as first argument of the object. On Linux systems, this is usually /dev/ttyACM0. The slipdec object decodes the SLIP-encoded OSC message, which is then unpacked and routed.

/images/basics/pd-arduino-ldr.png