Superdirt synths

I’m getting back into performing more, and would love more superdirt synths to play with, but don’t know enough about synthesis to make my own. Does anyone have some synths that play well with tidal to share, or links to any collections online?

Didi you already try MI-Ugens? I think, they offer high sound quality and variety. mi-ugens Otherwise, for example: GitHub - loopier/synthdefs: A collections of Supercollider synths · GitHub

Hi Alex! First of all, I’d like to congratulate you on your great contributions to live coding. Thanks to your videos on Tidal, I was able to discover this wonderful world—I even had to put my hardware gear on hold for a while to fully take it all in. The possibilities are truly endless!

Regarding synthdefs, I’ve been building some of my own (with the help of my friend GPT, since I’m not very experienced with SuperCollider yet). My sound explorations are focused on finding the widest possible range of timbres, and fortunately I’ve been getting very promising results. As I build more, I’ll keep sharing them. For now, these are the ones I’m using the most:

FM SIMPLE

This is a simplified FM synthesizer with 4 operators and a single algorithm (where direct modulation is generated as OP4 ⇒ OP3 ⇒ OP2 ⇒ OP1). This means that by only modifying the amplitude or the ratio of the 4 operators (a total of 8 parameters), you can achieve a wide range of timbres. I also added two envelopes: one for amplitude and another for the filter, along with its own cutoff and resonance parameters, with the filter being modulated by its envelope.

Example usage in Tidal:

d1
$ fast 2
$ note "20 3 7 10 15 19"
# s "fmsimple"
# ratio1 1
# ratio2 "5.9 2.1"
# ratio3 "3.3 1.1"
# ratio4 "9.1 4.5"
# index1 1.6
# index2 1.6
# index3 1.9
# index4 1
# atk 0 -- amp envelope
# dec 0.5
# sus 2
# rel 1
# synthCutoff 200
# synthResonance 0.5
# famt 2000 -- filter envelope amount
# fatk 0.1 -- filter envelope parameters
# fdec 0.5
# fsus 1
# frel 1
# amp 0.5
# room 0.4
# size 0.5

Parameters to add in BootTidal.hs:

-- COMMON PARAMETERS (reused across other synths)
freq = pF "freq"
amp = pF "amp"
atk = pF "atk"
dec = pF "dec"
sus = pF "sus"
rel = pF "rel"
res = pF "res"
fatk = pF "fatk"
fdec = pF "fdec"
fsus = pF "fsus"
frel = pF "frel"
famt = pF "famt"
synthCutoff = pF "synthCutoff"
synthResonance = pF "synthResonance"

-- FM SIMPLE

ratio1 = pF "ratio1"
ratio2 = pF "ratio2"
ratio3 = pF "ratio3"
ratio4 = pF "ratio4"
index1 = pF "index1"
index2 = pF "index2"
index3 = pF "index3"
index4 = pF "index4"

Synthdef:

(
SynthDef(\fmsimple, {
|out=0, freq=220,
ratio1=1, ratio2=2, ratio3=3, ratio4=0.5,
index1=5, index2=3, index3=2, index4=1,
atk=0.01, dec=0.3, sus=0.5, rel=1.0, amp=0.2,
synthCutoff=1000, synthResonance=0.3,
fatk=0.01, fdec=0.2, fsus=0.3, frel=0.5, famt=2000,
pan=0, gate=1|

var op1, op2, op3, op4;
var envAmp, envFilt;
var sig;

// Envolopes
envAmp = EnvGen.kr(Env.adsr(atk, dec, sus, rel), gate, doneAction: 2);
envFilt = EnvGen.kr(Env.adsr(fatk, fdec, fsus, frel), gate);

op4 = SinOsc.ar(freq * ratio4) * (freq * index4 * envAmp);
op3 = SinOsc.ar(freq * ratio3 + op4) * (freq * index3 * envAmp);
op2 = SinOsc.ar(freq * ratio2 + op3) * (freq * index2 * envAmp);
op1 = SinOsc.ar(freq * ratio1 + op2);

// Filter
sig = RLPF.ar(
op1,
(synthCutoff + (envFilt * famt)).clip(20, 20000),
synthResonance.clip(0.05, 0.99)
);

sig = LeakDC.ar(sig) * envAmp * amp;

// out
Out.ar(out, Pan2.ar(sig, pan));

}).add;
)

ACID 303

This is an attempt at a 303-style synth. Honestly, it sounds pretty good—the only thing I couldn’t fully replicate is the characteristic slide/glide effect. Still, I use it quite a lot and think it’s worth sharing. It includes both selectable waveforms (saw or square), distortion, accent, the characteristic just-decay envelope, and its own filter.

Example usage in Tidal:

d1 $
  n "[0 3 7 10]*4"
  # octave 4
  # s "acid303"
  # synthCutoff 200
  # synthResonance "0.10"
  # envAmt 500
  # accent "0 2 5"
  # slide 0.1
  # decay 2.18
  # amp 0.3
  # wave "0" -- 0 saw 1 square
  # dist 0.1
  # room 0.4
  # size 0.5

Parameters to add in BootTidal.hs:

-- ACID 303
envAmt  = pF "envAmt"
accent  = pF "accent"
slide   = pF "slide"
wave    = pF "wave"
dist    = pF "dist"

Synthdef:

(
SynthDef(\acid303, {
    |out=0, freq=110,
     synthCutoff=800, synthResonance=0.85, envAmt=2000,
     decay=0.2, accent=0, slide=0.05,
     wave=0, dist=0, amp=0.2|

    var osc, env, filtEnv, sig, f, drive;

    f = freq;

    osc = Select.ar(wave, [
        Saw.ar(f),
        Pulse.ar(f, 0.5)
    ]);


    drive = LinExp.kr(
        dist.clip(0,1),   
        0, 1,
        1, 12             // 1 = clean, 12 = high acid
    );

    // Pre-filter drive (303 style)
    osc = (osc * drive * (1 + accent)).clip2(1);

    env = EnvGen.kr(
        Env.perc(0.001, decay),
        doneAction: 2
    );

    filtEnv = EnvGen.kr(
        Env.perc(0.001, decay)
    );

    sig = RLPF.ar(
        osc,
        synthCutoff + (filtEnv * envAmt * (1 + accent)),
        synthResonance.clip(0.05, 0.99)
    );

    // Post-filter saturation (solo si dist > 0)
    sig = (sig * drive).clip2(1);

    sig = sig * env * amp;

    Out.ar(out, sig ! 2);
}).add;
)

PHASEMORPH

A synthesizer with waveform morphing and phase modulation. It sounds really nice—honestly, I’m not very familiar with this style of synthesis. It came about while chatting with my friend GPT, exploring types of synthesis that can generate a wide range of timbres (and it definitely does). Basically, by changing the "morph" and "pmIndex" parameters, you can achieve a huge timbral variation. Aside from that, it works like any other synthesizer, with its own filter and two envelopes.

Example usage in Tidal:

d1
  $ fast 2
  $ note "20 3 7 10 15 19"
  # s "phaseMorph"
  # morph 1 -- timbre parameter
  # pmIndex 2 -- timbre parameter
  # atk 0 -- amp envelope
  # dec 0.5
  # sus 2
  # rel 1
  # synthCutoff 200
  # synthResonance 0.5
  # famt 2000 -- filter envelope
  # fatk 0.1
  # fdec 0.5
  # fsus 1
  # frel 1
  # amp 0.5
  # room 0.4
  # size 0.5

Parameters for BootTidal.hs:

-- phaseMorph

morph   = pF "morph"
pmIndex = pF "pmIndex"

SynthDef:

(
SynthDef(\phaseMorph, { |out=0, freq=220, morph=0.5, pmIndex=3,
    cutoff=1200, res=0.3,
    atk=0.01, dec=0.3, sus=0.5, rel=1.0, amp=0.2,
    fatk=0.01, fdec=0.2, fsus=0.3, frel=0.5, famt=2000,
    pan=0, gate=1| 

    var osc, envAmp, envFilt, filtered;

    envAmp = EnvGen.kr(Env.adsr(atk, dec, sus, rel), gate: gate, doneAction: 2);

    envFilt = EnvGen.kr(Env.adsr(fatk, fdec, fsus, frel), gate: gate);

    osc = SinOsc.ar(freq, SinOsc.ar(freq * pmIndex, 0, morph * pi * envAmp));

    filtered = RLPF.ar(
        osc,
        (cutoff + (envFilt * famt)).clip(20, 20000),
        res.clip(0.01, 0.99)
    );

    filtered = LeakDC.ar(filtered) * envAmp * amp;

    Out.ar(out, Pan2.ar(filtered, pan));
}).add;
)

I hope you find them useful, feel free to modify or improve them, and if you do, let me know so I can enjoy your versions too! :slight_smile:

2 Likes

Hello community, I’m sharing a SynthDef I recently created: a percussion generator based on basic synthesis, inspired by analog drum machines.

It can produce a wide range of sounds (kicks, snares, hi-hats, various percussive and experimental textures).

It combines an oscillator with a pitch envelope, filtered noise, a transient click layer, a resonant filter, and saturation, all shaped by an amplitude envelope to create analog-style drum machine sounds controllable from TidalCycles.

Note: For correct envelope behavior, always set # sustain 1.

Hope you find it useful! Cheers.

Example usage in Tidal:

      d2
      $ slow 2
      $ n "0(9,12)"
      # s "percGenerator"
      # freq "120 60"
      # spg_attack 0.001
      # spg_decay "0.35 2 1.5 1.8!3"
      # spg_pitchEnvAmt "220 100 300 100 200"
      # spg_pitchDecay 0.05
      # spg_wave "3 3 0!2"
      -- tipo de oscilador:
      -- 0 sine | 1 saw | 2 pulse | 3 FM osc
      # spg_tone 0.7
      # spg_fm "9 <1.6 3> <2.7!2 9>"
      # spg_fmFreq "420 100 900"
      # spg_noise 0.1
      # spg_noiseTone "4800 200 1000"
      # spg_noiseBand "0.5 2 1.5 1"
      # spg_cutoff "5000 4500 7000!4"
      # spg_resonance "0.3 0.5 0.7 0.1!5"
      # spg_drive "0.4 0.1 0.2 0.5"
      # spg_click "2 0.35 0 1"
      # sustain 1
      # cut 1
      # amp 0.5
      # gain 0.7
     --  # verb 0.7 (slow 2 "0.5 0.7 0.5!2 0.6 0.5") 0.5 0.5 (optional, MI verb required)

Parameters to add in BootTidal.hs:

-- percGenerator

let spg_attack      = pF "spg_attack"
let spg_decay       = pF "spg_decay"

let spg_pitchEnvAmt = pF "spg_pitchEnvAmt"
let spg_pitchDecay  = pF "spg_pitchDecay"

let spg_wave        = pF "spg_wave"
let spg_tone        = pF "spg_tone"

let spg_fm          = pF "spg_fm"
let spg_fmFreq      = pF "spg_fmFreq"

let spg_noise       = pF "spg_noise"
let spg_noiseTone   = pF "spg_noiseTone"
let spg_noiseBand   = pF "spg_noiseBand"

let spg_cutoff      = pF "spg_cutoff"
let spg_resonance   = pF "spg_resonance"

let spg_drive       = pF "spg_drive"

let spg_click       = pF "spg_click"

Synthdef:

SynthDef(\percGenerator, {
    |out=0, freq=120,
    spg_attack=0.001, spg_decay=0.3,
    spg_pitchEnvAmt=200, spg_pitchDecay=0.05,
    spg_wave=0, spg_tone=0.5,
    spg_noise=0.0, spg_noiseTone=8000,
    spg_cutoff=8000, spg_resonance=0.3,
    spg_drive=0, spg_click=0.0,
    amp=0.3|

    var osc, noiseSig, env, pitchEnv, sig, clickSig, driveAmt;
    var freqEnv, cutoff, res;

    pitchEnv = EnvGen.kr(Env.perc(0.001, spg_pitchDecay));
    freqEnv = freq + (pitchEnv * spg_pitchEnvAmt);

    osc = Select.ar(spg_wave, [
        SinOsc.ar(freqEnv),
        Saw.ar(freqEnv),
        Pulse.ar(freqEnv, 0.5)
    ]);

    noiseSig = (spg_noise > 0) * BPF.ar(
        WhiteNoise.ar(spg_noise),
        spg_noiseTone,
        0.5
    );

    clickSig = (spg_click > 0) * (
        HPF.ar(WhiteNoise.ar(spg_click), 5000)
        * EnvGen.kr(Env.perc(0.0005, 0.01))
    );

    sig = (osc * spg_tone) + noiseSig + clickSig;

    cutoff = spg_cutoff.clip(60,18000);
    res = spg_resonance.clip(0.05,0.95);

    sig = RLPF.ar(sig, cutoff, res);

    driveAmt = LinExp.kr(spg_drive.clip(0,1), 0,1, 1,10);
    sig = (sig * driveAmt).tanh;

    env = EnvGen.kr(
        Env.perc(spg_attack, spg_decay),
        doneAction:2
    );

    Out.ar(out, (sig * env * amp)!2);
}).add;