Reading/understanding dense code with symbolic notation

Hi all, first post on here.

I’m quite new to supercollider and have been going through Eli Fieldsteel’s tutorials, but along the way I’ve come across some of redFrik’s bite-sized patches, like this one:

play{a=LFTri;c=perform(Splay,x=\ar,perform(Resonz,x,perform(VarSaw,x,5,0,d=perform(a,x,0.15,b=(1..5)),perform(EnvGen,x,Env.perc(f=15e-4,0.05,d,d*5),perform(a,x,b/1.5))),1.5**b*(50*perform(a,x,0.015,b/5).round+150),d+1.15*f,150));c+perform(PitchShift,x,c,1.5,0.5)}

I’d love to be able to figure out exactly how and why these do what they do, but they’re so dense that it’s a little hard to get past the first steps.

Does anyone have any tips for getting your head around dense, symbolic and quite heavily nested code like this for beginners?

The downside of any extremely shortened code is that readability suffers heavily. The very first step has to be to entangle it visually, i.e. put it into a text editor and add as many line breaks and as much indentation as required. Then try to replace variables that are reused at different places with their actual value and remove constructs that might add extra confusion like perform:

perform(LFTri, \ar, 440)

is equivalent to

LFTri.ar(440)

but as a beginner, I find the second one much easier to read, especially if the perform-operation is nested.

If I’m not mistaken, The code should end up somewhat like this:

play{
    b = (1..5);
    d = LFTri.ar(0.15, b);
    f = 15e-4;
    c = Splay.ar(
            Resonz.ar(
                VarSaw.ar(5, 0, d),
                EnvGen.ar(Env.perc(f, 0.05, d, d*5), LFTri.ar(b/1.5)),
                1.5 ** b * (50 * LFTri.ar(0.015, b/5).round + 150),
                d + 1.15 * f,
                150
            )
        );
    c + PitchShift.ar(c, 1.5, 0.5);
}

which is still a lot to unpack, but at least not as uncomfortable to read (at least to me).

4 Likes

Also, nesting UGens like this is an evil thing to do.

The code above can be rewritten using successive assignments to a variable representing the audio signal (in this case c). I’m not at SC right now, but you could rewrite some of the nesting like this:

c = VarSaw.ar.....
c = Rezonz.ar(c, .....
c = Splay.ar(c, ....

I’m happy to rewrite this fully if you’d find it helpful, but I can only do it once I get home.

Cheers

2 Likes