Using the Git Repository

Git is a distributed version control system. Changes to (text) files are grouped in chunks called commits. You can create new branches of a repository for specific features or tasks and merge those branches after you finished your changes.

Cloning a Git Repository

git clone https://github.com/anwaldt/SPRAWL.git

This creates a directory with the name SPRAWL and clones the git repository locally.

With git log you can see all recent commits.

Create Branches, Adding Changes and Committing

Let's create a new branch for our changes:

git checkout -b new_changes

Now we are on a new created branch called new_changes. If you omit the -b you checkout a branch that is on the remote repository.

The easiest way to committing changes is to commit every changes of files.

git add file.txt
git add file2.txt
git commit -m "Fixes wording of file.txt and file3.t wsgh s"

Sometimes it happens that you commited your changes too early but didn't pushed your changes to the remote server. If you only want to change the commit message you can use git commit --amend. The same command works for adding more changes to the last commit. Don't forget to use git add filename.

Pushing Changes to the Remote Server

With git you can have more than one remote repository. After you cloned the sprawl repository you will have a remote repository with the name origin.

student@h2912420:~/SPRAWL$ git remote -v
origin  https://github.com/anwaldt/SPRAWL.git (fetch)
origin  https://github.com/anwaldt/SPRAWL.git (push)

But you don't have any push access to this repository. To get your changes into the mainline SPRAWL repository you have to fork the project on github. At the right top corner at the sprawl's repo you must click on fork. Then you can add your own repo to your local SPRAWL clone:

$ git remote add ntonnaett https://github.com/ntonnaett/SPRAWL.git
$ git remote -v
ntonnaett       https://github.com/ntonnaett/SPRAWL.git (fetch)
ntonnaett       https://github.com/ntonnaett/SPRAWL.git (push)
origin  git@github.com:anwaldt/SPRAWL.git (fetch)
origin  git@github.com:anwaldt/SPRAWL.git (push)
git push ntonnaett

Exchange ntonnaett with your personal remote name. After you committed all your changes you can open a pull request on the mainline sprawl repository.

Using Arrays in SuperCollider

Simple Arrays

In SC, arrays are collections of objects of any kind. They can be defined and accessed using brackets:

// define simple arrays:
a = [0,1,2,3];
b = [0,1,2,"last_value"];

// access indices:
a[3];

Dynamic Creation

The array class offers numerous methods for creating arrays, including fill():

c = Array.fill(4,{arg i; 10/(i+1) });

Arrays of Buses

Especially in multichannel projects and larger mixing setups, arrays of buses can be helpful. Make sure to boot the server to actually use (scope) the buses:

// an array of 16 buses, each with 4 channels:
~busArray = Array.fill(16,{Bus.control(s, 4)})

// scope the second bus in the array:
~busArray[1].scope

// set the third bus of the second bus in the array:
~busArray[1].setAt(2,0.5);

Array of Nodes/UGens

The same array approach can be used to generate multiple nodes, for example sine waves at different frequencies and amplitudes:

// an array of 16 sine oscillators:
~sineArray = Array.fill(16,{arg i;{SinOsc.ar(200*i)}.play})

Array of Synths

The previous example can also be used with SynthDefs, which is a good starting point for additive synthesis:

// a simple synthdef
(
SynthDef(\sine,
{|f = 100, a = 1|

   Out.ar(0, a * SinOsc.ar(f));

}).send(s);
)

~busArray = Array.fill(16,{arg i;Synth.new(\sine,[f:200*(i+1),a:0.2])})

Warning

The second argument of fill has to be a function in curly brackets. If not, the array will contain multiple pointers to the same object (try)!

Wavetable Oscillator with Phase Reset

The Faust oscillators.lib comes with many different implementations of oscillators for various waveforms. At some point one might still need a behavior not included and lower level approaches are necessary.

This example shows how to use a phasor to read a wavetable with a sine waveform. This implementation has an additional trigger input for resetting the phase of the oscillator on each positive zero crossing. This can come handy in various applications, especially for phase-sensitive transients, as for example in kick drums.

The example is derived from Barkati et. al (2013) and part of the repository:

import("stdfaust.lib");

// some basic stuff
sr = SR;
twopi = 2.0*ma.PI;

// define the waveform in table
ts =  1<<16; // size = 65536 samples (max of unsigned short)
time = (+(1) ~ _ ) , 1 : - ;
sinewave =  ((float(time) / float(ts)) * twopi) : sin;

phase = os.hs_phasor(ts,freq,trig);

// read from table
sin_osc( freq) = rdtable(ts ,sinewave , int(phase)) ;

// generate a one sample impulse from the gate
trig =  pm.impulseExcitation(reset);

reset = button ("reset");
freq = hslider("freq", 100, 0, 16000, 0.00001);

// offset = hslider("offset", 0, 0, 1, 0.00001);

process = sin_osc(freq);
  • Karim Barkati and Pierre Jouvelot. Synchronous programming in audio processing: a lookup table oscillator case study. ACM Computing Surveys (CSUR), 46(2):1–35, 2013.
    [BibTeX▼]
  • Sending OSC from SuperCollider

    For sending OSC from SuperCollider, a NetAddr object needs to be generated. It needs an IP address and a port:

    ~out_address  = NetAddr("127.0.0.1", 6666);
    

    Sending Values Once

    This first example sends an OSC message once when the following line is evaluated. The previously created NetAddr object can be used to send OSC messages with its sendMsg method:

    ~out_address.sendMsg('/test/message', 1);
    

    Sending Values Continuously

    Based on the previous example, a routine can be created which continuously reads values from control rate buses to send their instantaneous value via OSC. The osc_routine runs an infinite loop with a short wait interval to limit the send rate and the CPU load:

      ~cBus = Bus.control(s,1);
    
      ~osc_routine = Routine({
    
            inf.do({
    
          // read value from bus
                      var value      = ~cBus.getSynchronous(~nVbap);
    
          // send value
                      ~out_address.sendMsg('/oscillator/frequency', value);
    
                      // wait
                      0.05.wait;
    
              });
    });
    

    Once created, the routine can be started and stopped with the methods play() and stop(). While running, bus values can be changed to test the functionality:

    ~osc_routine.play();
    
    ~cBus.set(300);
    
    ~cBus.set(700);
    
    ~osc_routine.stop();
    

    Exercise

    Exercise

    Run the PD patch osc-receive.pd to receive values from SuperCollider via OSC and control the pitch.

    Additive & Spectral: IFFT Synthesis

    The calculation of single sinusoidal components in the time domain can be very inefficient for a large number of partials. IFFT synthesis can be used to compose spectra in the frequency domain.

    /images/Sound_Synthesis/ifft/ifft-0.png

    Main lobe kernel for \(\varphi = 0\)

    /images/Sound_Synthesis/ifft/ifft-1.png

    Main lobe kernel for \(\varphi = \pi/2\)

    /images/Sound_Synthesis/ifft/ifft-2.png

    Main lobe kernel for \(\varphi = \pi/4\)

    /images/Sound_Synthesis/ifft/ifft-3.png

    Main lobe kernel for \(\varphi =c3 \pi/4\)

    Laplace Transform

    Receiving OSC in SuperCollider

    OSCFunc

    By default, a running instance of sclang listens to incoming OSC messsages on the port 57120. For listening to a specific OSC message, an OSC function can be defined with a specific path. SC will then evaluate the defined function when OSC messages are received at the default port with the matching path:

    ~osc_receive = OSCFunc(
    
    { arg msg, time, addr, recvPort;
    
    post('Revceived message to path: ');
    msg[0].postln;
    
    post('With value: ');
    msg[1].postln;
    
    }, '/test/message');
    

    OSCdef

    OSCdef is slightly more flexible and allows to change definitions on the fly, without deleting nodes:

    OSCdef(\tester,
            {|msg, time, addr, recvPort|
    
            post('Revceived message to path: ');
            msg[0].postln;
    
            post('With value: ');
            msg[1].postln;
    
    },'/test/another', n);
    

    Exercises

    Exercise I

    Use a SuperCollider OSC receiver with the first PD example on sending OSC for sending OSC to change the value of control rate bus and monitor the bus with a scope. The section on buses is helpful for this. Keep in mind to set the correct port (57120) and path in the PD patch.

    Exercise II

    Use a SuperCollider OSC receiver with the PD example for controlling the subtractive synth in the previous example. This can be done with control rate buses or by a direct set() to the synth nodes.

    Managing Jack Connections

    When JackTrip clients connect corresponding jack clients are created on the server side that may have a name defined by the connecting client. In the SPRAWL system every client connects with a remote name that starts with AP_ followed by the user's name. Those jack clients must be connected to the right inputs and outputs of the sprawl system. There are several solution to do this automatically. With aj-snapshot you can create a snapshot of all current jack connections and reconnect that state later. You can even running aj-snapshot as a daemon to constantly watch that all connections of a snapshot are set.

    In the sprawl system we don't know the full name of connecting jacktrip clients. With jack-matchmaker we are able to write pattern files that use regular expressions to connect jack clients:

    #
    # Direct Input
    
    /AP_.*_1:receive_1/
       SPRAWL_Server:in_1
    /AP_.*_1:receive_2/
       SPRAWL_Server:in_2
    /AP_.*_2:receive_1/
       SPRAWL_Server:in_3
    /AP_.*_2:receive_2/
       SPRAWL_Server:in_4
    

    Those regexes in slashes are conforming `python's regex syntax <https://docs.python.org/3/library/re.html>'_. Jack-Matchmaker can show you all current connections:

    System Message: WARNING/2 (<string>, line 30); backlink

    Inline interpreted text or phrase reference start-string without end-string.
    $ jack-matchmaker -c
    AP_Nils_1:receive_1
        SPRAWL_Server:in_1
    
    SPRAWL_Server:out_1
        AP_Nils_1:send_1
    
    SPRAWL_Server:out_2
        AP_Nils_1:send_2
    
    SPRAWL_Server:out_33
        AP_Nils_1:send_1
    
    SPRAWL_Server:out_34
        AP_Nils_1:send_2
    

    As you see I'm sending one audio channel to the server that connects to the first input of the SPRAWL_Server SuperCollider application. The next two connections are the direct outputs to my receiving channels. The last two connections are the binaural rendered spatialised mix.

    Jack-Matchmaker user service

    Right now the jack-matchmaker user service loads the pattern file located in /home/student/SPRAWL/matchmaker/sprawl_server_stereo.pattern. This might be changed in the future with a template instantiated service.

    Physical Modeling: Advanced Models

    More advanced physical models can be designed, based on the principles explained in the previous sections.


    Resonant Bodies & Coupling

    The simple lowpass filter in the example can be replaced by more sophisticated models. For instruments with multiple strings, coupling between strings can be implemented.

    /images/Sound_Synthesis/physical_modeling/plucked-string-instrument.png

    Model of a wind instrument with several waveguides, connected with scattering junctions (de Bruin, 1995):

    /images/Sound_Synthesis/physical_modeling/wind_waveguide.jpg

    References

  • Stefan Bilbao, Charlotte Desvages, Michele Ducceschi, Brian Hamilton, Reginald Harrison-Harsley, Alberto Torin, and Craig Webb. Physical modeling, algorithms, and sound synthesis: the ness project. Computer Music Journal, 43(2-3):15–30, 2019.
    [BibTeX▼]
  • Chris Chafe. Case studies of physical models in music composition. In Proceedings of the 18th International Congress on Acoustics. 2004.
    [BibTeX▼]
  • Vesa Välimäki. Discrete-time modeling of acoustic tubes using fractional delay filters. Helsinki University of Technology, 1995.
    [BibTeX▼]
  • Gijs de Bruin and Maarten van Walstijn. Physical models of wind instruments: A generalized excitation coupled with a modular tube simulation platform*. Journal of New Music Research, 24(2):148–163, 1995.
    [BibTeX▼]
  • Matti Karjalainen, Vesa Välimäki, and Zoltán Jánosy. Towards High-Quality Sound Synthesis of the Guitar and String Instruments. In Computer Music Association, 56–63. 1993.
    [BibTeX▼]
  • Julius O Smith. Physical modeling using digital waveguides. Computer music journal, 16(4):74–91, 1992.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 1. Journal of the Audio Engineering Society, 19(6):462–470, 1971.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 2. Journal of the Audio Engineering Society, 19(7):542–551, 1971.
    [BibTeX▼]


  • Contents © Henrik von Coler 2021 - Contact