Skip to content

Instantly share code, notes, and snippets.

@catfact
Created April 23, 2020 06:04
Show Gist options
  • Select an option

  • Save catfact/0a95fe4890cc27130cd973f18fce15cf to your computer and use it in GitHub Desktop.

Select an option

Save catfact/0a95fe4890cc27130cd973f18fce15cf to your computer and use it in GitHub Desktop.
supercollider level control for polyphonic synths
// execute these lines first
p = PolyLevelTest.new;
p.init(s);
/// execute this line repeatedly to spawn voices
p.randomNote(s);
// use a Limiter instead of manual gain changes
// note that Limiter and Normalizer impose latency equal to attack time
p.estimatedGainPerVoiceDb = 0;
p.outputSynth.set(\limiterMode, 1);
// Normalizer
p.outputSynth.set(\limiterMode, 2);
PolyLevelTest {
// homework: experiment with this value
var <>estimatedGainPerVoiceDb = 3;
var <activeVoiceCount = 0;
var outputBus;
var <outputSynth;
init { arg server;
SynthDef.new(\fm_noise_1shot, {
arg out=0, amp=0.5, pan=0.0,
hz = 440,
mod_freq_ratio = 1.5,
mod_depth = 0.5,
noise_level = 0,
noise_flavor = 0.0,
bpf_fc = 1760,
bpf_rq = 0.5,
saw_level = 0.5,
sine_level = 0.5,
attack=0.1, sustain=0.2, release=1.0;
var mod, mod_hz, snd, noise, aenv;
mod = SinOsc.ar(mod_freq_ratio * hz, mul:mod_depth);
mod_hz = hz * (2 ** (mod * mod_depth));
snd = SinOsc.ar(mod_hz) * sine_level + VarSaw.ar(mod_hz) * saw_level;
noise = SelectX.ar(noise_flavor, [WhiteNoise.ar, PinkNoise.ar, BrownNoise.ar]);
snd = snd + noise * noise_level;
snd = BPF.ar(snd, bpf_fc, bpf_rq);
aenv = EnvGen.ar(Env.new([0, 1, 1, 0], [attack, sustain, release]), doneAction:2);
snd = snd * aenv * amp;
Out.ar(out, Pan2.ar(snd, pan));
}).send(server);
outputBus =Bus.audio(server, 2);
// a stereo patch synth with smoothed level control and a final limiting stage
outputSynth = SynthDef.new(\smooth_stereo_patch, {
arg in, out,
amp=1.0, amp_lag = 0.1,
limiter_mode = 0; // 0 == no limiting, 1== limiter, 2 == normalizer
// homework: break out and play with smoothing parameters, algos
var snd = In.ar(in, 2) * Lag.ar(K2A.ar(amp), amp_lag);
// homework: b reak out and play with limiter / normalizer parameters
snd = Select.ar(limiter_mode, [Limiter.ar(snd), Normalizer.ar(snd)]);
Out.ar(out, snd);
}).play(server, [\in, outputBus.index, \out, 0]);
}
randomNote { arg server;
var params;
var hz = 55 * (2 ** 4.0.rand);
var bpf_hz = hz * (2 ** 3.0.rand);
var bpf_rq = 0.01.rrand(0.9);
var mod_freq_ratio = 2 ** (2.0.rand);
var mod_depth = 4.0.rand;
var pan = 1.0.rand2;
var noise_level = 1.0.rand;
var sine_level = 1.0.rand;
var saw_level = 1.0.rand;
var noise_flavor = 2.0.rand;
var attack = 1.0.rand;
var sustain = 1.0.rand;
var release = 4.0.rand;
// normalize saw, sine, and noise level together
var amp_sum = noise_level + sine_level + saw_level;
noise_level = noise_level / amp_sum;
sine_level = sine_level / amp_sum;
saw_level = saw_level / amp_sum;
params = [
\out, outputBus.index,
\hz, hz,
\bpf_hz, bpf_hz,
\bpf_rq, bpf_rq,
\mod_freq_ratio, mod_freq_ratio,
\mod_depth, mod_depth,
\pan, pan,
\noise_level, noise_level,
\sine_level, sine_level,
\saw_level, saw_level,
\noise_flavor, noise_flavor,
\attack, attack,
\sustain, sustain,
\release, release,
];
postln(params);
this.newNote(params, server);
}
newNote { arg params, server;
var synth = Synth.new(\fm_noise_1shot, params, addAction:\addToHead);
synth.onFree({
this.handleVoiceFreed;
});
this.handleVoiceAdded;
}
handleVoiceAdded {
activeVoiceCount = activeVoiceCount + 1;
this.computeBusLevel;
}
handleVoiceFreed {
activeVoiceCount = activeVoiceCount - 1;
this.computeBusLevel;
}
computeBusLevel {
var voiceGainDb =estimatedGainPerVoiceDb * activeVoiceCount;
outputSynth.set(\amp, voiceGainDb.dbamp);
}
}
@catfact
Copy link
Author

catfact commented Apr 23, 2020

this is a class and script for investigating strategies for automatic gain control of polyphonic synths.

two basic approaches are included:

  1. keep track of active voice count and attempt to manually control bus level.
  2. use Limiter or Normalizer UGens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment