# Supercollider tips, Q/A

#21

Thanks, I appreciate that

#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

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;
// 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.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

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.