Super Cool SuperCollider Synthesis Challenge (Prize)?

HAHAAA! Oh man, you nailed it :rofl:

It’s amazing how concise that is really, just multiplying and folding over itself a few times with RLPF in between…

Ok, you win, so what’s next? @nathan you got any ideas?

Thanks. Typically this is done with a wavetable synth, but I found a way to get the rich, metallic spectrum entirely using wavefolding. The other half of the trick is to alternate nonlinearities and EQ filters, which gives you really dirty and intense distortion.

Another fun option is to use Au5’s HyperGrowl method. I have old some code for that in Python/NumPy that generates a variable wavetables which I then use in VOsc.

As for what to do next, how about synthesizing an entire drum kit? At least kick+snare+hat, other sounds welcome.

1 Like

Right! I’ve done it in Serum with wavetables a dozen times, but never like that.

I’d be interested in that Python code if it’s something you’d share? Understand if not.

And yes, I think a drum kit is a good idea. Again I’m pretty new so it won’t be great, but I’m going to try to do something different than just a typical 808-ish thing. It’ll take me a week or so probably since I’m studying for this stupid IT cert…

any attempts on this one? :slight_smile:

Interesting. @nathan Can you export the Wavetable directly from serum into SuperCollider? Why do you need the Python /NumPy?

Oh… Here is some kind of WT converter by a SC forum member. Maybe something like this could do it…

1 Like

@Scott_Lawrence_Simon I’ve played with that, not bad.

I use Alik’s method of using wavetables from this video:

@dietcv is that song made with SC? I’m taking a while on this one. I have been working on a snare loosely based on a SOS article, but with my own flavor, and it’s taken up a lot of time. I should have a basic kit in a week.

1 Like

i think he is using lazorbass for synthesis and max for sequencing, tried out some chords with formant shift windowed sync or phase distortion but it sounds way more sharp.

(
SynthDef(\phase, {
	arg out=0, pan=0, amp=0.25, freq=110, 
	mRatio=1.5, cRatio=1, widthMod=0.5;
	
	var sig, saw, sine;
	var width = SinOsc.ar(widthMod!2).range(\widthMin.kr(0.15), \widthMax.kr(0.50).clip(0.001,0.999));
	
	saw = LFSaw.ar(mRatio * freq, 1).linlin(-1,1, width.neg, 1-width);
	saw = saw.bilin(0, width.neg, 1-width, 0, -0.5, 1);
	sine = (Select.ar(saw>0, [0.5+saw, saw]) * 2pi).sin;

	sig = SinOsc.ar(
		cRatio * freq * [1.001, 1],
		phase: sine * MouseY.kr(0, 7)
	);

	sig = Pan2.ar(sig, pan, amp);
	Out.ar(out, sig);
}).add;
)

(instrument: \phase, midinote: [57,60,64,65,70]).play;
2 Likes

I didn’t use Serum at all, the idea was to generate and re-sample the detuned oscillators entirely in Python.

1 Like

Recently I came across this Chariots of Fire with the \default Synth :

http://sccode.org/1-1QI

I would be amazing to have the full synthesized version made on SC! I would be our athem :rofl:!

Haha! Fortunately there’s a guy that attempted this on YouTube, I wrote it down and have a copy:

// Vangelis from studioTTTguTTT on YouTube: https://www.youtube.com/watch?v=zLJ1gcw0xbc-poison0ak

(
SynthDef(\vangelis, {
	var freq, osc1, osc2, freq1, freq2, env, pitch, amp, sig, lfo1, pitch2, fenv;
	amp = \amp.kr(0.85, 0.017);
	env = EnvGen.ar(Env.asr(\atk.kr(0.41), 1, \rel.kr(4.1), \crv.kr(0)), \trig.kr(1));
	fenv = EnvGen.ar(Env.asr(\fatk.kr(1.6), 1, \frel.kr(4.7), \fcrv.kr(0)), \trig.kr(1));
	lfo1 = SinOsc.kr(\lffreq.kr(0.06));
	freq = \freq.kr(440, 0.017);
	freq2 = freq + (lfo1*(\detune.kr(0.06)));
	osc1 = Saw.ar(freq);
	osc2 = Saw.ar(freq2);
	sig = Mix.ar( [osc1, osc2] );
	sig = RLPF.ar(sig, (\lpfreq.kr(6000)*env)+10);
	sig = JPverb.ar(sig, \revtime.kr(4), \damp.kr(0), \size.kr(4));
	Out.ar(\out.kr(0), sig*env*amp);
}).add;
)

a = Synth(\vangelis, [\freq, 261])
a.set(\trig, 0)

It needs some tweaking to be usable though.

Source:

3 Likes

This SynthDef is a masterpiece, I love it. It would be great if you could explain to the newbies some of the code you are using: laguad, fold2, dbamp…

Thank you. I’ve responded in a new thread: Video: Making dubstep bass sounds without wavetables

2 Likes

Great. I really appreciate it. I’m eager to watch it.

This is Razor. The synthesis isn’t particularly wild, just a bank of sines - but obviously the magic is in how it’s warping them around. You can do this in SC pretty easily, but because you’ll basically be controlling 256 separate SinOsc's the efficiency is trash - I wasn’t able to easily get anything close to Razor because of this… Still this synth is a big inspiration, and - if you can read Reaktor patches at least - it’s basically open source.

Lol, if Massive (and later Serum) are the synths that more or less created dubstep - Razor is the synth that created… whatever clubby computer music it is that Gabor Lazar, Rian Treanor, Cam Deas, and Errorsmith etc etc make. (Errorsmith made the synth, so I guess it’s no surprise that he uses it…)

2 Likes

hey, @nathan helped me out with creating the spectrum and the initial idea of the quasi bandpass filter sweep trough the partials and ive added some envelopes.

(
SynthDef(\gabor, {

	var trig = \trig.tr;
	
	var freqEnv = EnvGen.kr(Env([1,2,1], [0.5, 0.01], \lin), trig, doneAction: Done.none);
	var fltEnv = EnvGen.kr(Env([0.0125,1,0.0125], [\fAtk.kr(0.3), \fRel.kr(0.01)], \exp), trig, doneAction: Done.none);
	var gainEnv = EnvGen.kr(Env([0,1,0], [\atk.kr(0.01), \rel.kr(0.3)], \lin), trig, doneAction: Done.none);

	var numPartials = 50;
	var n = (1..numPartials);
	var freqs = \freq.kr(150) * (n + (n * n * 0.05));
	var cutoff, amps, sig;

	cutoff = fltEnv * \fltRange.kr(8000);

	amps = (
		(freqs.log2 - cutoff.log2).squared
		* \slope.kr(-5)
	).dbamp;

	sig = SinOsc.ar(freqs * freqEnv.midiratio, 0, amps).sum * -25.dbamp;

	sig = sig * gainEnv;

	sig = Pan2.ar(sig, \pan.kr(0), \amp.kr(0.25));
	Out.ar(\out.kr(0), sig);
}).add;
)

(
Pdef(\gabor,
	Pbind(
		\instrument, \gabor,
		
		\atk, 0.01,
		\rel, 0.5,
		
		// Bandpass Filter sweep
		\slope, -5,
		\fltRange, 8000,
		
		\fAtk, 0.3,
		\fRel, 0.01,
		
		\freq, 68,
		
		\amp, 0.30,
		\pan, 0,
		\out, 0,
	)
).play;
)

Pdef(\gabor).stop;


ive also played around with this BufWr approach to control the amplitudes of the partials and modulating the phase of the LFGauss for a similiar bandpassfilter like sweep. I also tried to use control busses to map different LFOs / looping envelopes to the phase argument of LFGauss for multichannel expansion and split the signal into different audio busses, to have two seperate modulated signals. but without the additional phase modulation you dont really have any possibility to shape the spectrum, when the synth is running. any further ideas?

(
~numPartials = 50;
~bufAmps = Buffer.alloc(s, ~numPartials, 1);

SynthDef(\additive, {
	arg index=1, iScale=3, gate=1, time=1;
	
	var numPartials = ~numPartials;
	var bufAmps = ~bufAmps;
	var f0 = \freq.kr(68);
	var sig, mod;
	
	var iEnv = EnvGen.kr(Env([index, index * iScale, index], [\iAtk.kr(0.2), \iRel.kr(0.5)], \lin), gate, timeScale: time, doneAction: Done.none);
	var gainEnv = EnvGen.kr(Env.linen(\atk.kr(0.1), \sus.kr(0.5), \rel.kr(1), curve: \sine), gate, doneAction: Done.freeSelf);
	
	BufWr.ar(
		LFGauss.ar(
			duration: SampleDur.ir * numPartials * \factor.kr(1, 0.5).reciprocal,
			width: \width.kr(0.2, 0.5),
			iphase: LFTri.ar(\phaseModFreq.kr(0.5)).linexp(-1, 1, 1, 2),
		),
		bufnum: bufAmps,
		phase: Phasor.ar(end: numPartials)
	);
	
	mod = SinOsc.ar(f0 * \mRatio.kr(1), mul: iEnv);
	
	sig = Array.fill(numPartials, {|i|
		var freqs, partials;
		freqs = f0 * (i + (i * i * 0.05));
		partials = SinOsc.ar(
			freq: freqs * \cRatio.kr(1),
			phase: mod.wrap(0, 4pi),
			mul: Index.ar(bufAmps, i)
		) / numPartials;
	}).sum;
	
	sig = LeakDC.ar(sig);
	
	sig = sig * gainEnv;
	
	sig = Pan2.ar(sig, \pan.kr(0), \amp.kr(0.25));
	Out.ar(\out.kr(0), sig);
}).add;
)

(
Pdef(\additive,
	Pbind(
		\instrument, \additive,
		
		\dur, 4,
		
		\width, 0.20,
		\phaseModFreq, 0.5,
		
		\atk, 1.5,
		\sus, 4,
		\rel, 2.5,
		
		\time, Pfunc { |ev| ev.use { ~sustain.value } / thisThread.clock.tempo },
		
		//Phase Modulation
		\iAtk, 1.5,
		\iRel, 2.5,
		\mRatio, 1.96417,
		\cRatio, 2.28158,
		\index, 1,
		\iScale, 1,
	
		\amp, 0.30,
		\out, 0,
	)
).play;
)

4 Likes

This is great.

I’ve been considering building an efficient “Sine Bank” ugen specifically for this purpose (e.g. to read freq/amp/phase data from a buffer and render a bank all at once). I think the additional piece to make things usable is to mass-manipulate values in those buffers, which requires a handful of new UGens for this purpose. For example, I would expect that I could do something like this (…imaging a Bank class encapsulating these buffer ops):

var numPartials = 256;
var fundamental = \freq.kr(440);
var warpPhase, freqBank, ampBank;

warpPhase = SinOsc.kr(4).range(-4, 4);

freqBank = Bank.fillSeries(0, 1, numPartials); // [0,1,2...]
freqBank = fundamental * buf;
freqBank = freqBank + Bank.fillSine(freq: 0.1, phase:warpPhase, amp: 4); // offset each freq

ampBank = 1 - Bank.fillSeries(0, 1/numPartials, numPartials).pow(0.25); // amp falloff... 

sig = SineBank.ar(freqBank, amp: ampBank);

Implementing this isn’t so challenging … I think the challenge is figuring out the minimal set of Bank operations you need in order to do anything interesting.

(I guess it’s worth noting that you can already do this with existing SC ugens, it’s just too slow to scale to 256+ partials for things as complex as Razor is doing)

3 Likes

this would be really great :slight_smile: lately there have been a lot of requests on the forum about synthesis related to razor (myself included). its really interesting that one of the first things i picked up about sc is the strength to do iteration for additive synthesis pretty easily. but to control all the partials with exisiting ugens isnt so trivial / possible.

do you have a good way to deal with additive synthesis in a universal way until we have the sine bank ;)?
imagine for example i want to have only the fundamental Ab2 and the 7th partial F#5 (-31 dev. from 12TET) of the harmonic series with specific amplitudes for example sig = SinOsc.ar([103.826, 726.783 * 2], 0, [0.5, 0.6]).sum;
and another time more partials with a specific amplitude conture for example all even partials up to a specific overtone. i would like to control everything with patterns and not write a new SynthDef every single time for only one specific case. any ideas ? :slight_smile:

(
(1..50).do({|partials|
	SynthDef(\additive ++ partials, {

		var sig, freqs, gainEnv;

		gainEnv = EnvGen.ar(Env.adsr(
			\atk.kr(0.07),
			\dec.kr(0.5),
			\sus.kr(1),
			\rel.kr(2),
			curve: \curve.kr(-4)
		), \gate.kr(1), doneAction:2);

		freqs = Array.fill(partials, {|i|
			\freq.kr(20) * (i+1); // even partials
		});

		sig = freqs.collect({|freq, i|
			var amps = \decay.kr(0.5) / (i+1); // even partials
			SinOsc.ar(freq) * amps;
		});

		sig = Mix(sig);

		sig = sig * gainEnv * \amp.kr(0.3) * \vel.kr(1);
		sig = Splay.ar(sig);
		Out.ar(\out.kr(0), sig)
	}).add;
});
)

x = Synth(\additive10, [\freq, 110, \decay, 0.5]);

x.set(\gate, 0);