Gabbercore music

Hi

Could anyone point me out to more gabber, hardcore kind of music made with SC, where I can learn from.
I’ve saw almost every youtube clip with breaks and beats, and this forum.

Are there maybe other channels to get more in this genre to learn from?

Thanks!

EVOL maybe?

1 Like

@nathan has some gabber stuff on sccode:
https://sccode.org/1-58T

Server.default.boot;

(
SynthDef(\gabberkick, {
    var snd, freq, high, lfo;
    freq = \freq.kr(440) * (Env.perc(0.001, 0.08, curve: -1).ar * 48 * \bend.kr(1)).midiratio;
    snd = Saw.ar(freq);
    snd = (snd * 100).tanh + ((snd.sign - snd) * -8.dbamp);
    high = HPF.ar(snd, 300);
    lfo = SinOsc.ar(8, [0, 0.5pi]).range(0, 0.01);
    high = high.dup(2) + (DelayC.ar(high, 0.01, lfo) * -2.dbamp);
    snd = LPF.ar(snd, 100).dup(2) + high;
    snd = RLPF.ar(snd, 7000, 2);
    snd = BPeakEQ.ar(snd, \ffreq.kr(3000) * XLine.kr(1, 0.8, 0.3), 0.5, 15);
    snd = snd * Env.asr(0.001, 1, 0.05).ar(2, \gate.kr(1));
    Out.ar(\out.kr(0), snd * \amp.kr(0.1));
}).add;

SynthDef(\hoover, {
    var snd, freq, bw, delay, decay;
    freq = \freq.kr(440);
    freq = freq * Env([-5, 6, 0], [0.1, 1.7], [\lin, -4]).kr.midiratio;
    bw = 1.035;
    snd = { DelayN.ar(Saw.ar(freq * ExpRand(bw, 1 / bw)) + Saw.ar(freq * 0.5 * ExpRand(bw, 1 / bw)), 0.01, Rand(0, 0.01)) }.dup(20);
    snd = (Splay.ar(snd) * 3).atan;
    snd = snd * Env.asr(0.01, 1.0, 1.0).kr(0, \gate.kr(1));
    snd = FreeVerb2.ar(snd[0], snd[1], 0.3, 0.9);
    snd = snd * Env.asr(0, 1.0, 4, 6).kr(2, \gate.kr(1));
    Out.ar(\out.kr(0), snd * \amp.kr(0.1));
}).add;
)

(
var durations;
durations = [1, 1, 1, 1, 3/4, 1/4, 1/2, 3/4, 1/4, 1/2];
Ppar([
    Pbind(*[
        instrument: \gabberkick,
        amp: -23.dbamp,
        freq: 60,
        legato: 0.8,
        ffreq: Pseq((0..(durations.size * 4 - 1)).normalize, inf).linexp(0, 1, 100, 4000),
        dur: Pseq(durations, inf),
        bend: Pfuncn({ |x| if(x < (1/2), 0.4, 1) }, inf) <> Pkey(\dur),
    ]),
    Pbind(*[
        instrument: \hoover,
        amp: -20.dbamp,
        midinote: 74,
        dur: durations.sum * 2,
        sustain: 7,
    ])
]).play(TempoClock(210 / 60));
)
2 Likes

A hijacked tweet i modded. Halfway from Noise to Gabber. Sorry I forgot how to post code correctly in the forum.

Ndef(\x,{{a=LFTri.ar(1/3);17.do{a=BAllPass.ar(a,PinkNoise.kr(0.001,40),1);a=BAllPass.ar(a,LFNoise0.kr(7/8,2400,2200),2);a=(a*LFNoise0.kr(3/4,7,2)).tanh;a=LeakDC.ar(a)};a/30}!4}).play;

3 Likes

That one by roc is also great:

https://boomkat.com/products/makina-trax-2013-2023

1 Like

With a Pulse at 3Hz and some tweaking of the rq and freq of the filter, it leans more in to techno territory.

Ndef(\x,{{a=LFPulse.ar(3,0,0.95);17.do{a=BAllPass.ar(a,PinkNoise.kr(0.001,4),1);a=BAllPass.ar(a,LFNoise0.kr(3/5,20,70),0.21);a=(a*LFNoise0.kr(0.3,7,2)).tanh;a=LeakDC.ar(a)};a/30}!4}).play;

The basis of gabber is in my opinion the distorted bassdrum. For the typical dutch 90ies kick the decay for the freq has to be much faster than the decay of the amplitude.

The sound can be generated by an ringing filter that is excited by an impulse or short burst of noise. Or with an oscillator. Triangle or Sine sounds best to my ears when adding distortion. You can go square wave without distortion, but then you loose all the transient and distortion fun.

For distortion use tangens hyperbolicus. It’s a softclip, very much like tube saturation. Then simply add distortion level before and output level after.

Simple Distortion: signal.tanh

1 Like

Small other question

I’ve started puzzling with different pieces of code.
But I don’t understand why the last part of my code doesn’t loop “forever”
It’s not a very clean code, still learning. But I thought I got the gist of it and for some reason now I don’t anymore.

(
s.waitForBoot {
    var mel, beat, synthOne, duration;
 
    // Load your melody and drum samples buffer here    
    mel = Buffer.read(s, "/Users/nameSupercollider/Shout/police-shout-japan-style_102bpm_F_major.wav");
    beat = Buffer.read(s, "/Users/name/sonicpi/kicks/gabber-aggressive-kick-one-shot.wav");
    
    // Play the initial sample for 30 seconds
    // sampleSynth definition remains the same
    synthOne = {
        var trig, rate, pos, sig, rec;
        trig = Dust.ar(3);
        rate = TChoose.kr(trig, [-2, 1, 2, -3, -0.75]);
        pos = TRand.ar(0, BufFrames.ir(mel), trig);
        sig = PlayBuf.ar(2, mel, rate, startPos: pos, loop: 1);
        rec = Phasor.ar(trig, K2A.ar(rate), 0, BufFrames.ir(mel), pos);
        BufWr.ar(sig, mel, rec);
        sig
    }.play;
    duration = 20;
    duration.wait;
    
    // Play the single kick
    { PlayBuf.ar(2, beat) }.play;
    beat.sampleRate.reciprocal.wait;
	
	
    5.wait; 
    
    // Play the single kick again
    { PlayBuf.ar(1, beat) }.play;
    beat.sampleRate.reciprocal.wait; // Wait for the duration of the kick sample
    

    0.8.wait;
	
	// Play the single kick again
    { PlayBuf.ar(2, beat) }.play;
    beat.sampleRate.reciprocal.wait; // Wait for the duration of the kick sample
    

    0.4.wait;
	// Play the single kick again
    { PlayBuf.ar(1, beat) }.play;
    beat.sampleRate.reciprocal.wait; // Wait for the duration of the kick sample 

    
    0.2.wait;
	{ PlayBuf.ar(1, beat) }.play;
    beat.sampleRate.reciprocal.wait; // Wait for the duration of the kick sample 
    
    // After the 0.2.wait, start playing the Synthdef \playDrums
    SynthDef(\playBeat, {
        arg buf=0, rate=1, spos=0, loop=1, pan=0.4, amp=0.5, out=0;
        var sig;
        sig = PlayBuf.ar(
            numChannels: 2,
            bufnum: buf,
            rate: BufRateScale.kr(buf) * rate,
            startPos: spos,
            loop: loop
        );
        sig = Pan2.ar(sig, pan, amp);
        Out.ar(out, sig);
    }).add;
	
	beat = Synth(\playBeat, [\buf, ~drums]);
	beat.set(\loop, 1); // This stops the loop, adjust as needed

};
)
1 Like

It takes a short time to prepare the SynthDef for play – that is, the following (in any context) will never work:

SynthDef(\something, { ... anything ... }).add;

x = Synth(\something);

If you’re in a routine (as you are, in your example), you can do this, but then x will be a few ms later, which may not be acceptable for musical timing.

// must be in a routine
SynthDef(\something, { ... anything ... }).add;

s.sync;

x = Synth(\something);

Best practice is to make your SynthDefs in advance, before they are needed.

You’re using { }.play a lot, which will result in inaccurate musical timing, which is likely to be especially noticeable in a highly rhythmic context at fast tempo. There’s a help file about server timing; I’d recommend reading it, and then applying latency to your outgoing messages to have more precise timing.

hjh

For sequenced drums one can use many different approaches. I see two main methods.

The classic method: Make SynthDefs and sequence them through Pbind. For info browse the Helpfiles: “Streams-Events-Patterns”, look at examples and tutorials. Most people sequence stuff via the Pattern Class.

The retro method: reverse engineer a 70ies drum machine: With masterclock, dividers, counters etc. and excite sounds with the raw trigger/clock. Here are two fun experiments exploring the swing of non linear drumming styles. Sounds like a cheesy drum machine:) add brazilian spice with the swing parameter!

http://sccode.org/1-5dg
http://sccode.org/1-5de

3 Likes

Really nice code examples and great use of Resonz. Great to see how a master clock can be used in this way!

I was trying to create a SynthDef to play similar drum sounds as the one in your code but I was struggling to get similar results. Would it be possible to capture all the different drum sounds in a do-all synthdef or would you need to split it up in several synthdefs?

If you want to do it in one SynthDef with “analogue triggers” you can send via several buses or multichannelstream the clock/trigger signals to the SynthDef. For external sounds “SoundIn.ar”, for SC-internal routing “In.ar”

The order of the nodes plays a role: first the SynthDef then the clock/trigger signal. Like doing FX in SC. Always run the FX first :slight_smile:

In my example the raw clock that gets bent via the swingfactor and multiplied via the modulo (%) creates nonlinear behavior. The reason I did it the analogue way was to adjust the swing on the fly and getting the funny behavior while bending the non band limited (dc.coupled) sawtooth.

If you want to trigger sound like in a regular drummachine the object orientated way with Synthdefs and Patterns is probably more promising.

You find old school drummachine sounds all over the place in SC-examples: check the “pieces” folder. On sccode.org and probably on github you’ll find some too.

1 Like

This is really cool.

Just trying to figure out routines, forks, tasks

To make like a break and then make like a composition.

Everything helps :slight_smile:

Now I’m going in the maze of server or routine timings. See you in a few years! :slight_smile:

you can create a swinging measure phasor and derive BPM synced event triggers from it.
Here with 16th note swing:

(
var rampRotate = { |phase, offset|
	(phase - offset).wrap(0, 1);
};

var rampFromBPM = { |bpm, beatsPerMeasure, reset|
	var beatsPerSec = bpm / 60;
	var measureRate = beatsPerSec / beatsPerMeasure;
	var measurePhase = Phasor.ar(reset, measureRate * SampleDur.ir);
	rampRotate.(measurePhase, SampleDur.ir);
};

var rampToTrig = { |phase|
	var history = Delay1.ar(phase);
	var delta = (phase - history);
	var sum = (phase + history);
	var trig = (delta / sum).abs > 0.5;
	Trig1.ar(trig, SampleDur.ir);
};

var rampToSwing = { |measurePhase, stepsPerMeasure, swing, div|
	var swingCount = stepsPerMeasure / div;
	var swingPhase = (measurePhase * swingCount).wrap(0, 1);
	var swingIndex = (measurePhase * swingCount).floor;
	var swingPhaseShaped = swingPhase.linlin(0, 1, swing.neg, 1 - swing).bilin(0, swing.neg, 1 - swing, 0.5, 0, 1);
	swingIndex + swingPhaseShaped / swingCount;
};

{
	var measurePhase, stepPhase, stepTrigger;

	var plotScale = 100;
	var stepsPerMeasure = 16;

	// measure phase
	measurePhase = rampFromBPM.(\bpm.kr(120) * 100, \beatsPerMeasure.kr(4), \reset.tr(0));
	measurePhase = rampToSwing.(measurePhase, stepsPerMeasure, \swing.ar(0.7), \div.kr(2));

	// step phase & trigger
	stepPhase = (measurePhase * stepsPerMeasure).wrap(0, 1);
	stepTrigger = rampToTrig.(stepPhase);

	[measurePhase, stepPhase, stepTrigger];
}.plot(0.021);
)

Important to note though that “always run the FX first” is because the default “addAction” is \addToHead. Adding FX synth 1000, and then source synth 1001, results in node order 1001, 1000 and the FX can receive the source :+1:

This default addAction was chosen because this is a very common use case.

I usually prefer to use Groups to handle node order, e.g.:

~srcGroup = Group.new;
~fxGroup = Group(target: ~srcGroup, addAction: \addAfter);

… and the precise desired relationship is expressed explicitly in the code. Then ~fxGroup is the target of fx synths, and ~srcGroup is the target of source synths.

(Though really, in production, I use the ddwMixerChannel quark, and basically never worry about node ordering and bus routing at all: you’d have ~kikMc = MixerChannel(\kick, s, 2, 2, level: -6.dbamp, outbus: ~mainMc) and this gives you a synthgroup and effectgroup just for the kick, and it places the kick earlier than the main output channel, and you can do pre/post-fader sends – think of signal routing basically the same way you do in your DAW.)

hjh

Thanks for the hint with the ddw.MixerChannel. There isn’t really a documentation with it. Anywhere a good manual?

Ah… I forgot that I hadn’t rewritten the help file. Maybe I can do it over the weekend.

In the meantime, the best resource is dewdrop world > supercollider 3 > tutorials (except the comment at the end about SwingOSC – obsolete bc of QtGUI).

The class has a lot of methods, but basic usage is quite simple.

MixerChannel

(
s.waitForBoot {
	// default outbus 0
	~main = MixerChannel(\main, s, 2, 2, 1);
	
	~rvbmc = MixerChannel(\rvb, s, 2, 2, 1,
		outbus: ~main,
		completionFunc: { |chan|
			~rvb = chan.playfx { |outbus|
				var sig = In.ar(outbus, 2);
				FreeVerb2.ar(sig[0], sig[1], 1, 0.9, 0.3)
			}
		}
	);
	
	~src = MixerChannel(\src, s, 2, 2, 0.5, outbus: ~main,
		completionFunc: { |chan|
			chan.newPostSend(~rvbmc, 0.8)
		}
	);
}
)

MixingBoard(mixers: [~src, ~rvbmc, ~main]);

n = ~src.play(\default, [freq: 880, gate: 1, amp: 0.4]);
n.release;

p = ~src.play(Pbind(
	\degree, Pwhite(-7, 14, inf),
	\amp, 0.5,
	\sustain, 0.08,
	\dur, Pwrand([1, 2, 3, 4], [0.4, 0.3, 0.2, 0.1], inf) * 0.25
), (quant: 1));

~src.level = 0.15;

~src.levelTo(0.5, 10);

// autopan is audible, though not shown in GUI
~src.controls[\pan].automate { SinOsc.kr(0.1) * 0.7 };

~src.postSends[0].levelTo(0, 12);  // fade out reverb

~src.postSends[0].levelTo(0.6, 12);  // fade in reverb

~src.mute(true);
~src.mute(false);

p.stop;

[~src, ~rvbmc, ~main].do(_.free);

hjh