Supercollider tips, Q/A


#21

Thanks, I appreciate that :slight_smile:


#22

this is super awesome and I discovered it during a SC research spree two months ago

thanks for re-posting for lines peeps


#23

Ok, stupid question time. Just going through some tutorials, and I ended up with this code:

(
var tempoclock = TempoClock(120/60);

{
inf.do {
Synth(\event, [\freq, 60.midicps]);
tempoclock.beatDur.wait;
};
}.fork(tempoclock)
)

Why does the synth trigger at what seems to be 240 bpm instead of 120 bpm? If I change the TempoClock argument to 60/60 it’s 1/4 of the speed of this.

Yes, I know there’s other / better ways to sequence stuff but I’m just scratching my head trying to figure out why this is working the way it is…


#24

TL/DR:
if you want to specify durations in absolute time, you don’t need a Clock.
if you’re using a Clock, you probably want to specify durations in musical time.


i think it’s going something like this.

the fork method, with a Clock as argument, wraps the function in a new Routine and plays it on the Clock

fork { arg clock, quant, stackSize;
        ^Routine(this, stackSize).play(clock, quant);
    }

the value given to wait or yield is interpreted by the Clock as the number of beats to wait before rescheduling.

so i think what you want is either this (wait one beat and modify the tempo of the clock):


(
var tempoclock = TempoClock(120/60);
{
	inf.do {
		Synth(\event, [\freq, 60.midicps]);
		1.0.wait;  // <<<<----- 
	};
}.fork(tempoclock)
)

or this (use the default TempoClock and modulate the wait time):

(
var beatDur = 0.5;
{
	inf.do {
		Synth(\event, [\freq, 60.midicps]);
		beatDur.wait;
	};
}.fork; // <<<---
)

#25

Ok, I see now.

So if my understanding is correct, when you schedule a task against TempoClock the time is expressed in beats. When you schedule against a SystemClock, it’s expressed in seconds.


#26

Correct.

The problem is that beatDur returns the duration in seconds of a current whole beat, and as zebra wrote you typically specify your wait durations in beats for functions forked to TempoClocks.


#27

super pedantic clarification:

when you use Function.fork with no clock argument, (or Routine.play) it still uses a (default) TempoClock. you can change the default TempoClock. you can use static methods to access the default TempoClock.

one reason this is significant is that TempoClock has meter and other stuff that SystemClock doesn’t:

s = Server.default;
s.waitForBoot({

    t = TempoClock(5);
    TempoClock.default = t;

    {
        SynthDef.new(\event, { arg freq;
            Out.ar(0, SinOsc.ar(freq) * EnvGen.ar(Env.perc, doneAction:2) * 0.1);
        }).send(s);
        s.sync;
        
        TempoClock.beatsPerBar = 5;
        /// these do the same thing:
        // TempoClock.default.beatsPerBar = 5;
        // t.beatsPerBar = 5;

        inf.do {
            Synth(\event, [\freq, (60 + (3 * TempoClock.beatInBar)).midicps]);
            1.0.wait;
        };

    }.fork;
});

and you can, say, modulate everything on the default clock at once:

s = Server.default;
s.waitForBoot({

    t = TempoClock(5);
    TempoClock.default = t;

    {
        SynthDef.new(\event, { arg freq, pan=0;
            var snd = SinOsc.ar(freq) * EnvGen.ar(Env.perc, doneAction:2) * 0.1;
            Out.ar(0, Pan2.ar(snd, pan));
        }).send(s);
        s.sync;

        TempoClock.beatsPerBar = 5;

        {
            inf.do {
                Synth(\event, [\pan, -0.5, \freq, (60 + (3 * TempoClock.beatInBar)).midicps]);
                1.0.wait;
            };
        }.fork;

        {
            inf.do {
                Synth(\event, [\pan, 0.5, \freq, (69 + (5 * TempoClock.beatInBar)).midicps]);
                0.75.wait;
            };
        }.fork;


    }.fork;
});

w = Window.new("tempo", Rect(0, 0, 100, 300));
Slider.new(w, w.bounds).action_( { |sl|
    TempoClock.default.tempo_(sl.value * 20.0)
});
w.front;

i’m trying to think of a scenario where it’s better to explicitly schedule something on the SystemClock. in theory:

  • if you’re calling stuff that isn’t thread safe.
  • if you want to make sure its timing can never be messed with by something like the 2nd example above.

#28

This is very typical of SuperCollider. It relies very (too?) much on implicit defaults. That was tricky for me as a newcomer to SuperCollider.

For instance, for Events you can do this and get a sound (of course assuming server is booted).

().play;

Adding some other supported property to the event will override the default for that property, but use defaults for other stuff.

(degree: 3).play;

The same applies to Pbinds. Without arguments you still get a sequence - it uses the default synthdef, note, duration:

Pbind().play // press Cmd-. to stop the sequence

Override one argument, otherwise use defaults:

Pbind(*[degree: Pseq([0, 3, 7, 10], inf)]).play

Override two arguments, otherwise use defaults:

Pbind(*[
	degree: Pseq([0, 3, 7, 10], inf),
	dur: Pseq([0.15, 0.1], inf)
]).play
)```

Another default: All Pbinds are by default also played using the default TempoClock for tempo, so changing its tempo will affect the pattern:

```TempoClock.default.tempo*60; // post current tempo in bpm
TempoClock.default.tempo = 80/60; // change pattern tempo to 80 bpm
TempoClock.default.tempo = 100/60; // ... 100 bpm
TempoClock.default.tempo = 120/60; // ... 120 bpm```

[quote="zebra, post:27, topic:3185"]
i'm trying to think of a scenario where it's better to explicitly schedule something on the SystemClock
[/quote]

SystemClocks and TempoClocks have the same priority so I believe it's mostly a matter of whether you want to be able to determine / change tempo dynamically (use a TempoClock) or just schedule by regular time.

AppClock, a third option, is of lower priority and typically used for UI updates. That's why you as a newcomer also run into errors that mean having to ```{}.defer``` stuff that's scheduled on a SystemClock or TempoClock that is supposed to update GUI widgets.

Since SystemClock has no variable tempo I believe only one exists and is used but with TempoClocks you can create as many as you want if you need multiple apps with differing tempos.

How nice we got SuperCollider discussions going on here...

#29

SystemClocks and TempoClocks have the same priority

this is getting deeper into the dark waters of the SC scheduler implementation, which i’m not very familiar with.

but, i am pretty sure that creating a TempoClock always attempts to create a new thread as well:

whereas SystemClock (which is singleton) always runs on the interpreter’s main process (calls schedRunFunc() directly in that same source, instead of passing the function to a pthread.)

i am 90% sure i’ve run into situations where things failed to work as expected in a TempoClock. (stuff like filesystem, network, pipes, serial drivers…) and needed to be scheduled explicitly on the SystemClock. presumably because of pthreads.

but i could be wrong about this. there is probably better information to be had on this in the sc-users, sc-devel mailing lists.


It relies very (too?) much on implicit defaults

totally agreed. can be very confusing. i spent many years in ignorance of what i was actually doing in common SC patterns. ctl-D is always informative.


#30

You’re more experienced in low level stuff and probably right in that they’re not of the same OS priority. Thanks for correcting me.

Let me rephrase. What I meant was that SystemClock and TempoClock are for timing critical stuff, whereas AppClock is not.


#31

can’t recall if I shared this already
https://twitter.com/search?q=supercollider+play

interesting challenge that I’ve tried learning bits from

140 char SC compositions


#32

Is anybody using sclang without scide? I’m running Supercollider on raspbian stretch lite and therefore do not have X windows. The sclang REPL works fine, but I’d like to use vi or emacs. Been having a little trouble getting scvim to work, and while I’m really more comfortable in vi than emacs, I’d be willing to switch if it made working with Supercollider easier. But before I did that I thought I’d find out what others are doing, if anything.


#33

yeah i’ve been doing that on raspbian.

only real gotcha that comes to mind is this issue; a bug in AppClock with the terminal client that interferes with server .statusWatcher:

(check top, you may be seeing 100% cpu usage on sclang.)

here’s what i do to work around it… (Crone is a singleton class that always keeps a running server and a bunch of “boilerplate” busses, synths and defs…)

Crone {
	// the audio server
	classvar <>server;
	// current CroneEngine subclass instance
	classvar <>engine;
	// available OSC functions
	classvar <>oscfunc;
	// address of remote client
	classvar <>remoteAddr;
	// port to send OSC on
	classvar <>txPort = 8888;
	// an AudioContext
	classvar <>ctx;

	*initClass {
		StartUp.add { // defer until after sclang init

			postln("\n-------------------------------------------------");
			postln(" Crone startup");
			postln("");
			postln(" \OSC rx port: " ++ NetAddr.langPort);
			postln(" \OSC tx port: " ++ txPort);
			postln("--------------------------------------------------\n");

			server = Server.local;
			server.waitForBoot ({
				Routine {
					// this is necessary due to a bug in sclang terminal timer!
					// GH issue 2144 on upstream supercollider
					// hoping for fix in 3.9 release...
					server.statusWatcher.stopAliveThread;
					server.initTree;
					server.sync;
					CroneDefs.sendDefs(server);
					server.sync;
					// create the audio context
					// sets up boilerplate routing and analysis
					ctx = AudioContext.new(server);
				}.play;
			});
...
        }
...
}

as for vim / emacs, i use scel all the time (including on pi) but have never used scvim…


Approaching: norns
#34

OK, cool, I’ll give scel a whirl. About time I learned emacs anyway.

Thanks for the Crone tip!


#35

just to be clear, Crone is a thing i made that is not normally part of supercollider. i’m just showing it as a pattern; a strategy i’ve found useful over the years (making some kind of singleton that boots a server and creates a consistent boilerplate audio environment whenever sclang is launched.) and in this case its a good place to work around weird environment-specific issues


#36

Weee, scel is really quite nice, especially with sclang-extensions

I really should have bothered to learn emacs sooner.


#37

never gets old https://xkcd.com/378/


#38

I’m using Atom with atom-supercollider and vim-plus from time to time. But Atom is a cpu hog so I guess it’s not a good fit for the raspberry pi.

I’d like to get scvim working on Windows 10, since I’m mostly using that platform. Not sure it’s possible.

I believe the latest vim 8 release includes asynchronous io and background jobs, perhaps that facilitates a cross-platform scvim.

I think I’ve used sclang with readline (ctrl-r, etc) support some time by just starting the sclang from command line.


#39

hi guys…

Ive just added SuperCollider support to Organelle, so we can launch SC patches from its OLED.

Im now starting to work on some demo patches and also the general setup, and wondered if the more experienced SC users out there had some suggestions on SC settings that I should configure as defaults.

current thoughts are:

  • increase number of connections allow, so remote control is possible, even when running the local patch via sclang
  • configure extensions/plugins directory to point to sdcard/usbdrive so users can add there own extras
  • add some default extensions (?) that will provide easy access to oled/knobs/keys

background:
Organelle, is an Arm device, its running SC headless
idea is to run a single patch, currently when starting, it kicks off jackd;scsynth and sclang
most of the time, users will just be running the patch , ‘in performance’ where the patch is controlled via the knobs/keyboard and oled… however, I will also make it such that a laptop could run the SC ide and connect to the organelle SC instance, to have further fun.
i want the patches to be as self contained as possible, eases distribution (via patch storage)

thoughts? ideas?
also any suggestions on structuring patches?
defaults extensions to provide? (sc3-plugins?)


#40

Wow, I just might have to buy an Organelle now.