Supercollider tips, Q/A

waaat… that’s super frigging bizarre.

i can get other errors too, unless i’m being a dunce. something special about 2**25?

s = Server.default;
s.waitForBoot { Routine {

	SynthDef("test", {
		arg a=40000000, b=10.0, c=40000000;
		((a + b) - c).poll(2, "Difference"); // Expecting 10, seeing 8
	}).send(s);
	s.sync;

	postln('new default synth, difference should be "10"');
	x = Synth("test");

	2.wait;

	postln('restarting... ');
	x.free;
	s.sync;
	b = 10;
	a = 2 ** 25 - 1 - b;
	postln('new non-default synth, difference should be "10" (offset: ' ++ a ++ ')');
	x = Synth("test", [\a, a, \b, b, \c, a]);

	2.wait;

	postln('restarting... ');
	x.free;
	s.sync;
	b = 10;
	a = 2 ** 26 - 1 - b;
	postln('new non-default synth, difference should be "10" (offset: ' ++ a ++ ')');
	x = Synth("test", [\a, a, \b, b, \c, a]);

	2.wait;


// why does this work???
	postln('changing values... difference should be "200"');
	x.set(\a, 40000000);
	x.set(\c, 40000000);
	x.set(\b, 200);
}.play; }

dunno if this is the OSC layer or synth instantiation or what, but seems like a bug

Thanks for taking a look, you’re making me feel less crazy at least! I’ll open up an issue on the SC github and report back…

Got a quick reply: it is just a floating point precision issue. Will have to do some more thinking about how to get around it in my project though.

@markeats i am brianlheim on github. if you post more about what you’re trying to accomplish i might be able to help. :slight_smile: we also have a responsive community at scsynth.org.

4 Likes

ok, that makes sense. guess i forgot that IEEE-754 defines a 24-bit mantissa for 32b binary (in my head it was 26 or something - see? dunce).

BufRd does document that it only addresses 2^24 samples, which should have been a clue.

I wonder if anyone can help with a SC performance question?

I’ve built a simple sampler application. A stripped down version that shows the issue looks like this:

s.waitForBoot({
~b1 = Buffer.read(s, "1.wav");

SynthDef(\sampler, {
        arg obs=0, buf, rate=1, amp=1;
        var sig;
        sig = PlayBuf.ar(1, buf, rate, \t_tr.kr(1, 0), doneAction: Done.freeSelf);
        Out.ar(obs, sig);
}).add;

~handler = {
        arg msg, time, addr, recvPort;
        Synth(\sampler, [\buf, ~b1.bufnum]);
};

n = NetAddr.new("127.0.0.1");
o = OSCFunc(~handler, '/sampler/1', n, 49162);
});

I’m running this sclang script from the command line (on OS X 10.14 on a macbook pro) with sclang sampler.scd.

To reproduce the issue I’m seeing, in a separate terminal window I’m triggering the sample via OSC using sendosc in a steady pulse with while true; do sendosc 127.0.0.1 49162 /sampler/1; sleep 0.5; done.

If I do anything fairly intensive on my machine while this is running (for example open a new browser tab in FF), the audio stutters. It sounds like some of the OSC events are not arriving in time, and sometimes get backed up before all firing at once.

Is this just something to be expected when running SC under OS X with other things happening on the machine, or is there something wrong in the way I’m using SC? Are there any tips for achieving more solid timing?

That’s really weird, you should be able to trigger 100s of this kind of synths per second on any current machine.
Do you experience the same thing when running your scd from the SC IDE ?
Maybe ask for some help on scsynth.org forum.

Do you experience the same thing when running your scd from the SC IDE ?

Yes, it seems so. I notice that the CPU indication in the IDE is well below 1%. It doesn’t sound like the kind of crackle/glitch you get when the machine is under load, it’s almost as if the OSC messages are getting delayed and arriving late?

IMO this indicates that the issues may lie in the process running sclang. If you send the equivalent command directly to scsynth the issues may go away. So you might want to try that out.

I’ve never had issues like this with messages triggered every 0.5 seconds, though I mostly do the scheduling in sclang itself.

On the norns (raspberry pi) I’ve noticed OSC messages getting dropped between the different layers, but only when a lot of messages are sent in a short amount of time (practically at the same time). We haven’t narrowed down why that happens.

Thanks @jah that’s really helpful!

I took a look at the server command reference and was able to send the equivalent OSC commands directly to the server with:

while true; do sendosc 127.0.0.1 57110 /s_new s sampler i -1; sleep 0.5; done

(where 57110 is the port assigned to the supercollider server when it starts). Unfortunately the problem persists. I am planning to run this code on a raspberry pi eventually (I’m writing a sequencer in Rust with a SC backend) but it’d be nice to understand what’s happening on my (presumably much more capable) laptop :slight_smile:

Another idea: Try scheduling the same events from sclang instead of from the shell. If this resolves the issue it might be the terminal window command you’re using that’s stalling for some reason.

2 Likes

Just diving into sc this week and I’m eager to explore a more in-depth resource. Does anyone have any thoughts on Andrea Valle’s Introduction to SuperCollider? Looking for something detailed but relatively approachable for a newcomer.

I enjoyed this https://ccrma.stanford.edu/~ruviaro/texts/A_Gentle_Introduction_To_SuperCollider.pdf from Stanford’s music technology school as a free, thorough, and well-written resource

5 Likes

if you haven’t worked through this series, yet, this is the place to start:

6 Likes

On tutorial 8 now and loving it. I personally go back and forth on text-based learning (especially when it’s self-guided), but it seems like a good idea for something this dense :slight_smile:

1 Like

Supercollider: Pulsar synthesis with GrainSin

Using Pulsar synthesis with GrainSin to make harmonic spectrum and formants

In this video I discuss the use of sinusoidal grains to synthesize formants and harmonic spectrum. Also I present some tips on how to naturalize the signal and provide a degree of spatiousness.

Requirements

SuperCollider

These tutorials on SuperCollider are not beginner level. It’s assumed that viewer knows basics of SuperCollider language.

#supercollider

11 Likes

Just found this SuperCollider resource. Lots of stuff there!

2 Likes

Is it possible to modulate the Env or EnvGen parameters while the envelope is running similar to how one might the attack/decay on an analog envelope generator? From what I’ve seen so far, everything is fixed at initialization.

1 Like

Just diving into sc myself, but I think you’re able to modulate envelope parameters so long as you declare corresponding arguments in your SynthDef. I just wrote this as a test and it seems to be working just fine (I’m setting arguments for both the attack and release times, with initial values, and then using a pattern to modulate them):

(
SynthDef(\sine, {
	arg atk=0.01, dec=0.5, freq=440, amp=0.30;
	var sig, env;
	sig = SinOsc.ar({freq}!2);
	env = EnvGen.kr(Env.perc(atk,dec),doneAction:2);
	sig = sig * env * amp;
	Out.ar(0,sig);
}).add;
)

(
Pbind(
	\instrument, \sine,
	\dur, 3,
	\midinote, Pseq([45,50,55,60,65],inf),
	\atk, Pwhite(0.01,4.00,inf),
	\dec, Pwhite(0.5,2,inf),
).play;
)
2 Likes

@Olivier Thanks for the example! There’s some new stuff in here for me to learn about.

Does Pbind re-use/re-trigger a single synth instance or does it create a new one for each “note”? It sounds like it’s creating a new one with new parameters each time.

I’m trying to achieve something like this:

/* start new sound with 10 second decay */
s = Synth.new(\sine, [\dec, 10]);
/* a moment later, change running envelope decay to 1 second */
s.set(\dec, 1);

In this case my desired behavior would be to have the envelope scale the remaining decay time to the new total decay. So if I fired the envelope with a decay of 10 seconds and then changed it to 1 second after 1 second had already elapsed, I would expect it to decay for 0.9 more seconds (I think).

Instead, the envelope continues to decay for 10 seconds and I can’t change it while it’s running.

1 Like