Time-Frequency Domain

Compiling JackTrip

The SPRAWL System needs some additional features that are missing from the main branch of Jacktrip. To build the correct JackTrip version, the Jacktrip git repository must be cloned and checked out to the correct branch.

Therefor git must be installed. On MacOS git is often already installed. Linux users should install git through their package manager. Windows users download the installer from git-scm.

Getting the JackTrip Source Code

Now the JackTrip source code can be downloaded from the official JackTrip repository.

git clone https://github.com/jacktrip/jacktrip.git
git checkout nils

Changes in the remote repository have to get pulled.

git pull

Afterwards you can follow the official build instructions.

Moving Files with SCP

SCP (Secure copy protocol) is an SSH-based tool for transferring files between machines in local and wide area networks. It is a safe and quick way to exchange data.


Copying to a Remote Machine

The following command copies the file testfile.html from the local machine to the home directory of the user student on the server with the address specified address 11.22.33. Instead of the home directory (~/), any other target can be specified:

$ scp testfile.html student@11.22.33:~/

Add the -r flag to copy a directory recursively:

$ scp -r /foo/bar student@11.22.33:~/


.. admonition:: Exercise

  Select or create a short WAV file on your local machine and copy it to your personal directory on the server using SCP.

Copying From a Remote Machine

To copy a file from a remote server, the arguments' order needs to be swapped. The dot (.) copies the data to the recent directory. Any other path can be used as target.

$ scp student@85.214.78.6:~/WebAudioFreqGain.html .

Waveshaping Example

The following interactive example offers control over the pre-gain to add overtones to the sinusoidal source signal:

Pitch (Hz):

Pre-Gain:

Output Gain:

Time Domain:

Frequency Domain:

Using Python for Control

Python offers many useful tools for preparing data and controlling synthesis processes. Although it can also be used for actual digital signal processing, its versatility makes it a great tool for auxuliary tasks. Most notably, it can be used for flexible processing and routing of OSC messages, especially in the field of data sonification.


Python & OSC

A large variety of Python packages offers the possibility of using OSC. They can be installed using pip:

$ pip install python-osc
$ pip install pythonosc

An example project for controlling a Faust-built synthesizer with Python is featured in this software repository: https://github.com/anwaldt/py2faust_synth


Python & JACK

The JACK Audio Connection Kit Client for Python by Matthias Geier connects Python processes to the JACK server. This integration of Python in a JACK ecosystem can be helpful not only for audio processing, but also for synchronization of processes. Since the Python package also implements the JACK transport functions, it can be used to couple Python threads to the timeline of audio projects.

Using Buses in SuperCollider

Control Rate vs Audio Rate

Buses can be used to route and group signals for prjects with a more complex signal flow. SC works with two internal signal types: audio and control. This concept is also used in other computer music environments, such as PD or Max/MSP. Control signals work at a lower sampling rate and are used to control parameters, whereas audio signals carry what is audible. Audio- and control-rate signals can not be mixed arbitrarely but there are ways to convert them.

This duality affects various aspects in SC. Many UGens (like signal generators and oscillators) can be used in both rates. With the extension .ar they produce or process audio signals (at audio rate). When used with .kr they operate at control rate.


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 merely the the client-side representation of the Bus. The server only knows buses by their bus index. Bus indices are counted upwards (for every new bus created in the language) and can be queried with the following command:

~aBus.index
~cBus.index

Reserved Audio Buses

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;

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 bus:

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

There is also a short version, which does not specify the bus type but uses a client-side object:

~aBus.scope()

~cBus.scope()

The standard bus meter in SC only scales from -2 to +2 and is not efficient for monitoring higher values.


Audio Buses

Audio Output

Audio output was already used in the very first examples for creating a sound in SC. The UGen Out can be used at audio rate to output an audio signal to any bus by its index. With a stereo interface, this is the short version for sending a sine-wave to the left output/speaker:

{Out.ar(0, SinOsc.ar(1000))}.play;

And to the right output/speaker:

{Out.ar(1, SinOsc.ar(1000))}.play;

Audio Input

With In.ar() we can get the signal of any audio bus into a node on the sever. This will become interesting for routing signals between nodes and will be explored in the following chapters.

Most early stage applications will make use of the inputs from the audio interface (for microphones and instruments). The SoundIn - UGen makes it convenient to access the audio input buses directly. It is aware of the number of harware inputs and outputs and allows accessing all inputs directly with the input-index. This node simply passes the first input (usually 'left') to the first output (also 'left'):

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

Note that this is equivalent to using the proper offset with a regular audio input (which is more complicated, but can be more versatile in some cases):

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

Control Buses

Setting a Control Bus

A simple and quick way for changing the control bus on the language side is the .set() function of a bus:

~cBus.set(1);

The effect is visible when monitoring the bus.


Reading Control Buses in Nodes

Control buses can be read inside a node just like audio buses, using In.kr(). This simple sawtooth SynthDef will be used for showing how to use control buses as arguments. The first argument defines the output bus index. The second argument freq_bus (defaulted to 0) is used inside an In.kr(), reading the bus' value into the variable freq.

SynthDef(\saw,
{
  arg out_bus, freq_bus;

  var freq = In.kr(freq_bus);
  Out.ar(out_bus, Saw.ar(freq));
}).add;

When creating a node from the SynthDef, we pass a bus or a bus index as initiation argument:

~saw = Synth(\saw,[\out_bus, 0, \freq_bus, ~cBus]);

The pitch of the sawtooth is now linked to the value of ~cBus.


Mapping a Control Bus

Another way to use bus values inside a node is mapping. Any input arguement of a node can be mapped to a control bus after it has been created. This node does the same thing as the SynthDef above:

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

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

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

Control Bus Output

Out.kr() can be used to output control-rate signals to arbitrary buses, just as outputs are used in the audio domain. The following node creates a sinewave LFO with a center frequency of 100 Hz, a modulation depth of 20 Hz and an LFO frequency of 1 Hz. The control bus ~cBus is used as the first argument of the Out.kr():

~mod =
{
  |
  freq   = 1,
  center = 100,
  depth  =  20
  |
  Out.kr(~cBus, depth+(shift*SinOsc.ar(freq)));
  }.play;

If we have one of the above sawtooth synths running and connected to the control bus. the modulation will be effective immediately. Since all LFO parameters are arguments, we can change them now by setting node parameters:

~mod.set(\freq,3)
~mod.set(\depth,50)

Multichannel Buses

Both control and audio rate buses can be created as multi channel buses by using the second creation argument:

~mc_Bus = Bus.control(s,8);
~ma_Bus = Bus.audio(s,8);

A scope will automatically show all channels. Individual channels can be used in UGens, set and mapped with an offset in relation to the index of the first channel of the bus.

Using the \saw SynthDef from above, we can now use any bus from those multichannel buses:

~saw = Synth(\saw,[\out_bus, ~ma_Bus.index+4, \freq_bus, ~mc_Bus.index+5]);

We are now sending the audio output to an internal SC bus. It is thus not audible, but can be checked with the scope:

~ma_Bus.scope

To change a single channel in a multichannel bus, use setAt(). The first argument defines the offest (channel index) - the second one the value:

~mc_Bus.setAt(5,1)

In a similar way, we can get all values from the multichannel bus:

~mc_Bus.getn(8)

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: