SuperCollider 3.9

We are proud to announce the arrival of SuperCollider 3.9.0! Apologies for being so far behind schedule; we hope the improvements you’ll find here will more than make up for it. In 3.9.0, determined contributors have fixed some of SuperCollider’s major cross-platform compatibility demons, addressed longstanding issues in the IDE and language, and added new features and bugfixes across the board.

The full changelog is very long. Here are the most important changes:

  • Breaking change: The application binary interface (ABI) for server plugins has changed. This has an important impact: plugin binaries compiled for SuperCollider 3.8 will not work with SuperCollider 3.9 and vice versa. You will need to use a new version of sc3-plugins as well if you are upgrading SC.
  • Breaking change: Rests in the patterns system have been restructured. Instead of using the isRest event property, events are considered rests if one of their properties is a Rest object. You must use instances of Rest rather than the rest class itself – use of Rest instead of Rest() is now deprecated.
  • The UnitTest quark has been incorporated into the main repository. If you already have UnitTest installed, you should uninstall it to prevent duplicate class errors.
  • Support for multiple sclang clients connecting to the same server is greatly improved.
  • A new UGen, Sanitize, replaces infinities, NaNs, and subnormals with another signal, zero by default.
  • Fixed numerous instances of UGens outputting an initial sample of garbage.
  • Fixed help files failing to open on Windows if the user’s name contains a non-ASCII character.
  • New aliases for done actions, e.g. Done.freeSelf == 2, are introduced for better readability. See the Done helpfile for details.
  • Deprecated OSCresponder, OSCresponderNode, OSCpathResponder, AudioIn, and Speech.
  • Some Linux systems had unreadable font colors in the autocomplete tooltips. This has been (finally) fixed.

You can grab the latest version from the release page. Thanks for using SuperCollider!

Baking sound in supercollider

Problem? I want to synthesize gorgeous pad sounds in supercollider. This is possible using additive and/or subtractive synthesis, but it takes a lot of CPU power. Approach 't Is the season to be bakin' fa-la-la-la-laaaaa la-la-la-laaaaa. How about we pre-render the sound into a wavetable and then loop the generated wave table? This moves most of the work to startup time. In the blender 3d

2017 in a nutshell

How was your year? It’s always exciting to look forward to a new year, making and setting up a fresh plan with a full of motivation! At the same time, it is very important to think about the past year, what are the achievements, and what I have missed. 

This post is about my memorable activities of the year 2017. I selected 4 activities:

  1. DELETION at International Film Festival Rotterdam


    ‘DELETION’ is a short film made by Esther Urlus, who I met two years ago for Light Leak project with Filmwektplaats. She’s a special filmmaker in The Netherlands, who create DIY 16mm experimental films. The length of the film is around 10 minutes, completely abstract, accordingly there was enough space for me to explore with sounds. The film is about a murder scene -accordingly, a horror movie!- but you don’t see or recognize anything through the screen. The story is behind the complete abstract scenes. The soundtrack therefore has a big role for audience to follow the story line.
    Thankfully this film was nominated at Tiger Competition for Short Films 2017 at IFFR, which gave me a totally new experience to attend the festival, sitting there with other amazing filmmakers and actors/actresses. Even though the film wasn’t the winner, it was for me a great achievement. I hope to have more opportunities working on films. I quite like it.

  2. Azimuth #3

    ‘Azimuth’ is a foundation that their multichannel system offers composers/artists to create spatial music/arts with the system. Azimuth #3 was my first experience with it. The piece I wrote is ‘Punky-Pulse-Pool’ for 32 channels.
    The materials were created from a short theme, a gesture using pulse oscillator, and as in variations on a theme, it was developed, manipulated, and re-synthesized into diverse forms. Then instead of presenting them one after another, they were massively and randomly thrown in time and in space. As if one freely plays a puzzle with multiple different blocks, the layered and squeezed sound materials are then sculpted and re-organized not only musically but also spatially. In that way new relationships between sound events are revealed, and the allied, survived sound parts are newly developed from there with a found connectivity.
    I wrote the blog post about my experience in more detail.

     

  3. ‘Bamboos’ for Bamboos


    Some might remember those Bamboo instruments that I made a piece for some years ago. Then I wanted to do something different with it, and here I made a live piece using them. Here I use(make) them as resonating ‘electronic flutes’ using audio feedback system. When I close the holes, their original tone varies. The feedback works like ‘breathes.’ Then I apply a number of signal processing. Together with it, I attached small metal rings on the holes that are wired to Arduino that gives a low voltage flow. My touch could change its voltage as I am also connected to another analog circuit. In other words, the voltage flows throughout my body and whenever the contact is made between me and the instruments, it changed. The variation is chaotic, unpredictable. Then this signal is added to the feedback sound, which is related also to the movement of my fingers. The program note for the piece is below.

    Notes on “Bamboos”: Bamboos, their bodies, their own resonating voices. Every other gesture drives from there, as the performer continuously tries to distort, differentiate, and control them until the instruments and performer become strongly linked together. The whole space, occupied by bamboos’ stubborn voices whose struggles are running and jumping all over, later on becomes part of the resonating body, singing and breathing all together.

  4. Staff at the Institute of Sonology


    Probably the most surprising news was that I became a staff member in Sonology, where I studied and achieved Master Degree, for which I came here in The Netherlands. Somehow, probably it was my dream, one day, teaching here. Luckily and thankfully I got this opportunity.
    The subject I am teaching is ‘Spatial Music Composition for WFS system.’ The course is designed for students to plan and proceed their project with the WFS system and I give lectures on Spatial music with tons of musical examples of other composers, history on spatial music and spatialization system/tools, the meaning of space, musical space, and practical knowledge on how to use the WFS system. It demands quite some research that I enjoy very much. It is definitely a new experience for me, and there is far more to become better.

Well, that’s it. Now it’s the beginning of the new year 2018. I am very much looking forward to seeing what will come to my life. Hopefully it becomes a very creative, more musical, and inspiring year. It’s mostly up to me. 

I wish all of the readers a very happy new year!

 

PS Quartet No.1 - for game controllers and computers

PS Quartet No.1 is a piece for Sony DualShock 4 Controllers and computers. All sound and graphics were created with SuperCollider. The piece is written for laptop ensembles.

The piece was premiered and recorded by EMEWS (Electronic Music Ensemble of Wayne State). In the recording above, the piece was performed by the following members (from left to right)
  • Sean Monaghan
  • Laura Apolloni
  • James VanRysseghem
  • Joey McLennan
  • Charles Moore
This piece can be performed by anyone with a PlayStation controller and a computer. Scores, instructions, and necessary codes are available at the following link:

https://app.box.com/s/xnivx2nxyisjzsiydeb8t9zgkrhtvph1

I am particularly happy with the score of the piece!
demopage

f0mid

wireless midi <-> osc bridge using an esp8266-01. this circuit is extremely cheap to build. schematics, arduino code and examples for supercollider below.

i'm using the great Arduino MIDI Library that allows for both sending and receiving a multitude of midi messages including sysex, system realtime and time code messages. my arduino code just converts all these to/from osc and send or broadcast them over wifi network.

note: sending midi over wifi udp is generally a bad idea. there will be delays, glitches and even lost messages (hanging notes). this is specially problematic for midi time code (sync) messages. that said, in many situations this is ok and in my tests with simple note on/off messages + bend and control, things seem to work just fine.

f0mid

the circuit takes in 5v and then the regulator steps this down to 3.3v. notice the huge 220uF capacitor that's needed to provide power for the esp8266 during its infamous current draw spikes. it wouldn't be hard to add a midi thru section if needed.

f0mid_schematics

supercollider example code...

//http://arduinomidilib.fortyseveneffects.com/a00041.html
//http://arduinomidilib.fortyseveneffects.com/a00043.html

OSCFunc.trace(true, true);  //your laptop should have ip x.x.x.99 to receive - check in the arduino code
OSCFunc.trace(false);

n= NetAddr("192.168.1.100", 18120);  //ip of esp8266

n.sendMsg(\noteOn, 66, 127, 1);  //(note, velo, chan)

n.sendMsg(\noteOff, 66, 0, 1);  //(note, velo, chan)

n.sendMsg(\afterTouchPoly, 50, 60, 3);  //poly pressure (note, press, chan)

n.sendMsg(\controlChange, 1, 64, 3);  //(num, val, chan)

n.sendMsg(\programChange, 10, 4);  //(num, chan)  note the -1 offset

n.sendMsg(\afterTouchChannel, 40, 2);  //(press, chan)

n.sendMsg(\pitchBend, -8000, 1);  //(bend, chan)  -8192 - 8191

n.sendMsg(\sysEx, 240, 14, 5, 0, 5, 247);  //(sysex) - 240 a b c d e ... 247

//realtime
(
var clock= 0xf8;  //248
var start= 0xfa;  //250
var continue= 0xfb;  //251
var stop= 0xfc;  //252
Routine.run({
        n.sendMsg(\realTime, start);
        100.do{
                n.sendMsg(\realTime, clock);
                0.02.wait;
        };
        n.sendMsg(\realTime, stop);
        1.wait;
        n.sendMsg(\realTime, continue);
        100.do{
                n.sendMsg(\realTime, clock);
                0.02.wait;
        };
        n.sendMsg(\realTime, stop);
});
)
n.sendMsg(\realTime, 0xfe);  //active sensing
n.sendMsg(\realTime, 0xff);  //system reset

n.sendMsg(\songPosition, 100);
n.sendMsg(\songSelect, 3);
n.sendMsg(\tuneRequest);

n.sendMsg(\beginNrpn, 10, 3);  //(number, channel)
n.sendMsg(\nrpnDecrement, 40, 3);  //(amount, channel)
n.sendMsg(\nrpnIncrement, 30, 3);  //(amount, channel)
n.sendMsg(\endNrpn, 3);  //(channel)

n.sendMsg(\beginRpn, 10, 4);  //(number, channel)
n.sendMsg(\rpnDecrement, 40, 4);  //(amount, channel)
n.sendMsg(\rpnIncrement, 30, 4);  //(amount, channel)
n.sendMsg(\endRpn, 4);  //(channel)

//--simple midi synth example
(
s.latency= 0.02;
s.waitForBoot{
        var busBend= Bus.control(s);
        var busCF= Bus.control(s);
        var busRQ= Bus.control(s);
        var busVol= Bus.control(s);
        var busPan= Bus.control(s);
        busBend.value= 0;
        busCF.value= 1000;
        busRQ.value= 0.5;
        busVol.value= 0.5;
        busPan.value= 0;
        SynthDef(\note, {|freq= 400, amp= 0.5, gate= 1, busBend, busCF, busRQ, busVol, busPan|
                var env= EnvGen.ar(Env.adsr(0.01, 1, 0.85, 0.1), gate, amp, doneAction:2);
                var bend= In.kr(busBend).lag(0.01);
                var cf= In.kr(busCF).lag(0.01);
                var rq= In.kr(busRQ).lag(0.01);
                var vol= In.kr(busVol).lag(0.01);
                var pan= In.kr(busPan).lag(0.01);
                var src= BLowPass4.ar(VarSaw.ar((freq+bend).midicps), cf, rq);
                OffsetOut.ar(0, Pan2.ar(src*env, pan, vol));
        }).add;
        d= ();
        OSCdef(\f0mid, {|msg|
                switch(msg[1],
                        \activeSensing, {},
                        \noteOn, {
                                d.at(msg[2]).set(\gate, 0);
                                d.put(msg[2], Synth(\note, [
                                        \freq, msg[2],
                                        \amp, msg[3].lincurve(0, 127, 0, 0.75, 4),
                                        \busBend, busBend,
                                        \busCF, busCF,
                                        \busRQ, busRQ,
                                        \busVol, busVol,
                                        \busPan, busPan
                                ]));
                        },
                        \noteOff, {
                                d.at(msg[2]).set(\gate, 0);
                                d.put(msg[2], nil);
                        },
                        \pitchBend, {
                                busBend.value= msg[2]/8192;
                        },
                        \controlChange, {
                                switch(msg[2],
                                        1, {
                                                busCF.value= msg[3].linexp(0, 127, 400, 4000);
                                        },
                                        7, {
                                                busVol.value= msg[3].lincurve(0, 127, 0, 1, 0);
                                        },
                                        10, {
                                                busPan.value= msg[3].linlin(0, 127, -1, 1);
                                        },
                                        74, {
                                                busRQ.value= msg[3].linlin(0, 127, 2, 0.1);
                                        },
                                        {("todo control: "+msg).postln}
                                );
                        },
                        {("todo command: "+msg).postln}
                );
        }, \f0mid);
        CmdPeriod.doOnce({
                busBend.free;
                busCF.free;
                busRQ.free;
                busVol.free;
                busPan.free;
        });
};
)

//mtc - receive
(
var a= MIDISMPTEAssembler({|time, format, dropFrame, srcID|
        [time, format, dropFrame, srcID].postln;
        //time.postln;
});
OSCdef(\f0mid, {|msg, time, addr|
        var chan, valu;
        if(msg[1]==\mtcQF, {
                chan= msg[2].rightShift(4);  //nibble high
                valu= msg[2].bitAnd(15);  //nibble low
                if(chan==7, {
                        valu= switch(valu,
                                6, {valu= 96},  //30fps
                                4, {valu= 64},  //30fps drop
                                2, {valu= 32},  //25fps
                                0, {valu= 0}     //24fps
                        );
                });
                a.value(addr.addr.bitAnd(255), chan, valu);
        });
}, \f0mid);
)

//mtc - send (kind of works - wslib quark required)
(
var startSec= 0;
var t= Main.elapsedTime-startSec;
var a= SMPTE(0, 30);
Routine.run({
        var chan= 0, valu= 0;
        inf.do{
                a.newSeconds(Main.elapsedTime-t);
                switch(chan,
                        0, {valu= a.frames.asInteger.bitAnd(15)},
                        1, {valu= a.frames.asInteger.rightShift(4)},
                        2, {valu= a.seconds.asInteger.bitAnd(15)},
                        3, {valu= a.seconds.asInteger.rightShift(4)},
                        4, {valu= a.minutes.asInteger.bitAnd(15)},
                        5, {valu= a.minutes.asInteger.rightShift(4)},
                        6, {valu= a.hours.asInteger.bitAnd(15)},
                        7, {
                                valu= a.hours.asInteger.bitAnd(1).rightShift(4);
                                switch(a.fps,
                                        30, {valu= valu.bitOr(6)},  //30fps
                                        //30fps drop not supported
                                        25, {valu= valu.bitOr(2)},  //25fps
                                        //24, {valu= valu.bitOr(0)}     //24fps
                                );
                        }
                );
                n.sendMsg(\mtcQF, chan.leftShift(4)+valu.bitAnd(15));
                chan= chan+1;
                if(chan==8, {
                        chan= 0;
                });
                (1/(a.fps*4)).wait;
        };
});
)

AttachmentSize
Package icon f0mid_firmware.zip3.49 KB

f0dim

this simple addition/hack lets me control the velleman k8064 dc dimmer kit via wireless osc or serial. it's based on an esp8266. the kit is isolated, can dim 220v/110v and is rated for up to 750w loads.
normally one control it using 0-12v but by replacing a resistor (R16) it's possible to do it with the 0-3.3v pwm signal that the esp outputs.

f0dim

i probably should cut some air ventilation holes, but so far it hasn't gotten hot inside.

f0dim_schematics

arduino code for the esp8266...

//f.olofsson2017

// * install OSC from https://github.com/CNMAT/OSC
// * edit where it says EDIT below
// * choose board: "Generic ESP8266 Module" 160 MHz

//osc protocol: /dim pwm fade
//  pwm should be 0.0-1.0
//  fade should be 0.0-1.0 (1.0=instant)
//serial protocol: 253 254 pwmhi pwmlo fadehi fadelow 255
//  pwm hi and lo should be 0-1023
//  fade hi and lo should be 0-1023 (1023=instant)

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <OSCMessage.h>

#define PORT 15551  //receiving osc port
#define PINPWM 0
#define PAYLOAD 4
#define UPDATERATE 16
#define TRIES 100  //how many times try check for wifi connection at startup

const char *ssid = "wifinetwork"; //EDIT your accessPoint network name
const char *password = "wifipassword";  //EDIT your password
const char *espname = "f0dim";
WiFiUDP Udp;
bool wifi;

byte serial_index = 0;
byte serial_data[PAYLOAD];
unsigned long next_time;
float dim = 0.0, dim_target = 0.0, dim_fade = 1.0;

void setup() {
  analogWriteFreq(5000);   //5khz pwm
  Serial.begin(115200, SERIAL_8N1, SERIAL_RX_ONLY);
  pinMode(BUILTIN_LED, OUTPUT);
  pinMode(PINPWM, OUTPUT);
  analogWrite(PINPWM, 0);
  delay(10);
  WiFi.mode(WIFI_STA);
  WiFi.hostname(espname);
  WiFi.begin(ssid, password);
  byte cnt = 0;
  wifi = false;
  while ((WiFi.status() != WL_CONNECTED) && (cnt < TRIES)) {
    delay(100);
    cnt++;
    digitalWrite(BUILTIN_LED, cnt % 2);
  }
  if (WiFi.status() == WL_CONNECTED) {
    Udp.begin(PORT);
    wifi = true;
  }
  digitalWrite(BUILTIN_LED, !wifi); //blue led on if connected to wifi
}

void oscDim(OSCMessage &msg) {
  dim_target = msg.getFloat(0);
  dim_fade = msg.getFloat(1);
}

void loop() {

  //--serial input
  while (Serial.available() > 0) {
    byte val = Serial.read();
    if ((serial_index == 0) && (val == 253)) {
      serial_index = 1;
    } else if ((serial_index == 1) && (val == 254)) {
      serial_index = 2;
    } else if ((serial_index >= 2) && (serial_index < (PAYLOAD + 2))) {
      serial_data[serial_index - 2] = val;
      serial_index++;
    } else if ((serial_index == (PAYLOAD + 2)) && (val == 255)) {
      dim_target = ((serial_data[0] << 8) + serial_data[1]) / 1023.0;
      dim_fade = ((serial_data[2] << 8) + serial_data[3]) / 1023.0;
      serial_index = 0;
    } else {
      serial_index = 0;
    }
  }

  //--osc input
  if (wifi) {
    int packetSize = Udp.parsePacket();
    if (packetSize) {
      OSCMessage oscMsg;
      while (packetSize--) {
        oscMsg.fill(Udp.read());
      }
      if (!oscMsg.hasError()) {
        oscMsg.dispatch("/dim", oscDim);
      }
    }
  }

  //--fading
  if (millis() >= next_time) {
    next_time = millis() + UPDATERATE;
    if (dim < dim_target) {
      dim = dim + dim_fade;
      if (dim > dim_target) {
        dim = dim_target;
      }
    } else if (dim > dim_target) {
      dim = dim - dim_fade;
      if (dim < dim_target) {
        dim = dim_target;
      }
    }
    analogWrite(PINPWM, int(dim * 1023));
  }
}

supercollider example code...

//f0dim can be controlled either via osc or serial
n= NetAddr("192.168.1.105", 15551);
n.sendMsg(\dim, 1.0, 1.0);  //set 100% instantly
n.sendMsg(\dim, 0.5, 1.0);  //set 50% instantly
n.sendMsg(\dim, 0.0, 1.0);  //set 0% instantly
n.sendMsg(\dim, 1.0, 0.001);  //slow fade in
n.sendMsg(\dim, 0.0, 0.0005);  //slower fade out

SerialPort.listDevices;
(
~port= SerialPort("/dev/tty.usbserial123", 115200, crtscts: true);  //EDIT serialport
CmdPeriod.doOnce({~port.close});
f= {|pwm= 1023, fade= 1023|
        Int8Array[253, 254, pwm>>8, pwm%256, fade>>8, fade%256, 255];
};
)

~port.putAll(f.value(1023, 1023));  //set 100% instantly
~port.putAll(f.value(512, 1023));  //set 50% instantly
~port.putAll(f.value(0, 1023));  //set 0% instantly
~port.putAll(f.value(1023, 3));  //slow fade in
~port.putAll(f.value(0, 2));  //slower fade out

~port.close;

ParkJones - New Album with Molly Jones

Composer/Saxophonist/Technologist extraordinaire Molly Jones and I made an album. It is released by NoRemixes. Here are two video previews of the album as well as the link to the Bandcamp site. All tracks in the album were recorded live. 
Enjoy!








Episode 1: Thy Holy Cities Are A Wilderness

This track was made entirely in Supercollider. I created a feedback patch and let it run for about 3 minutes with no interference. Then I started reducing levels to make it fade out.

Supercollider file: mhc_060516.sc (6K)
mp3 file: Thy Holy Cities Are a Wilderness (8M)

Episode 2: We Are the Clay

mp3 file: We Are the Clay (5.4M)

I figured out how to make percussive noises with feedback. The trick is to shut the level of each feedback channel way down whenever it makes a noise, and boost it way up whenever it doesn't. To make a rhythm, I added a delay so the boost waits for a specified time before starting another cycle.

Some notes on running the Supercollider patch: In order to reduce duplication, I've moved some of the code into a class called FeedbackMatrix. To run this episode's patch in Supercollider:
  • Download FeedbackMatrix.sc and eyeballsun_060603.sc.
  • Go into your SuperCollider directory, and create a subdirectory under SCClassLibrary. Call it eyeballsunClasses.
  • Put FeedbackMatrix.sc in eyeballsunClasses.
  • If Supercollider is running, recompile the libraries.
  • Open eyeballsun_060603.sc in Supercollider and execute each block in order.

Episode 3: My Usual Size

mp3 file: My Usual Size (9.8M)
Supercollider file: eyeballsun_061026.sc (6K)

Yes, it's been a long time since the last track and it could be a long time until the next one. But I've finally managed to recreate the Unsound Machine in Supercollider. I got an iMic for my birthday so now I can hook the computer up to my other equipment.

The sc file won't give you the same results as I got this time, since it uses a sample (not included) and connects to some external effects. However, I've abandoned the FeedbackMatrix library for now so you only need the one file.