Implementing filters with additive synthesis

Hi and welcome,

@semiquaver and @hemiketal have pointed to the issue in your first approach. There’s an ‘if’ in the language and ‘if’ in the server. See this help file:

https://supercollider.github.io/tutorials/If-statements-in-a-SynthDef.html

To apply boolean logic server-side you have to think about signals returning 0 an 1. However, you’ve been very close. Your example works if the Functions within ‘if’ are dropped, making it to an ‘if’-UGen.

(
{
	var n = 30;
	var f0 = 200;
	var freqs = Array.fill(n, {arg i; f0*(i+1)});
	var amps = Array.fill(n, {arg i; 1/(i+1)});
	var filtered_amps = n.collect {arg i; if (DC.ar(freqs[i]) < MouseX.kr(1000, 2000), amps[i], 0)};
	var sig = Mix.ar(SinOsc.ar(freq:freqs, mul:filtered_amps));
	Pan2.ar(sig*0.5, 0.0);
}.play;
)

Some syntactic suggestions to save typing. ‘indicator’ is a multichannel signal providing 0s and 1s.

(
{
	var n = 30;
	var f0 = 200;
	var freqs = (1..n) * f0;
	var amps = 1 / (1..n);
	var indicator = freqs < MouseX.kr(1000, 2000);
	var sig = Mix.ar(SinOsc.ar(freq: freqs, mul: indicator * amps));
	Pan2.ar(sig * 0.5, 0.0);
}.play;
)

This approach is absolutely ok, can be extended to complex additive setups in multiple ways (using independant LFOs for amplitude and frequency, alternative frequency choices, array arguments, other UGens than SinOsc, feedback etc.).

Patterns are also a nice way to do additive synthesis. At the moment I’m working with some students doing additive synthesis projects. On this occasion I was remembered how well Patterns are suited for this. One big plus is that you can use the Event apparatus for defining harmonic relations. I wanted to collect some additive synthesis ideas in a tutorial, but didn’t have time to work it out yet. Here some Patterns examples:

Additive Synthesis with Patterns

// WARNING: note the low amp values (* 0.02)!
// needed as many single synths do overlap

// simple sine synthdef with spatial placement and trapezoidal envelope

(
SynthDef(\sine, { |out, freq = 400, att = 1, sus = 1, rel = 1,
	pan = 0, amp = 0.1|
	var env = EnvGen.ar(Env.linen(att, sus, rel, curve: \sine), 1, doneAction: 2);
	var sig = SinOsc.ar(freq, 0, amp) * env;
	OffsetOut.ar(out, Pan2.ar(sig, pan))
}).add
)

// moving clusters

(
p = Pbind(
	\instrument, \sine,
	\dur, 0.1,
	\att, 3,
	\sus, 3,
	\rel, 3,
	\amp, 0.02 * Pseg(Pwhite(0.0, 1), Pwhite(0.5, 1)),
	// Pseg generates env-like movement
	\midinote, Pseg(Pexprand(40.0, 110), Pwhite(0.2, 1.5), \sine),
	\pan, Pwhite(-1.0, 1)
).play
)

// needs some seconds to stop
p.stop



// microtonal clusters at random pitch, causing beats
(
p = Pbind(
	\instrument, \sine,
	\dur, 0.5,
	\att, 3,
	\sus, 3,
	\rel, 3,
	\amp, 0.02 * Pwhite(0.5, 1),
	\midinote, Pexprand(40.0, 110) + [0, 0.25, 0.5],
	\pan, Pwhite(-1.0, 1)
).play
)

// needs some seconds to stop
p.stop



// partial row glitter
(
p = Pbind(
	\instrument, \sine,
	\dur, 0.1,
	\att, 1,
	\sus, 2,
	\rel, 1,
	\amp, 0.02 * Pseg(Pwhite(0.0, 1), Pwhite(0.5, 1)),
	// fundamental walks with mediant steps, added quartertones
	\midinote, Pstutter(Pwhite(50, 100), Pseq([25, 29, 33], inf) + Pseq([0, 0.5], inf)),
	\harmonic, Pwhite(1, 30),
	\pan, Pwhite(-1.0, 1)
).play
)

// needs some seconds to stop
p.stop
6 Likes