Limiter class or another solution

hi everyone, i am back today with a question about Limiter class. Used to the ableton version where the gain is pushed until compression reach the right volume control to delete peaks and set average limit.

SuperCollider Limiter.ar(gain*input, vol, du(delay)); hasnt worked yet for me . simply wont stay at one level while my sound keep having odd peaks of volume.

i havent found a clear example but the sound I use has a reverb that occasionally moves volume which i thought could be control with the limiter.

Thanks community , everyone for your help

Maybe you’re looking for Normalizer.ar ?
Note that Limiter as well as Normalizer can fail under extreme conditions:

2 Likes

ok its hard to see the difference between both but i tried and since volume went very high I did input -20dbamp for level agr which brought it back to -30 when i was aiming for -20 but anyway seems pretty stable at -20 when input -10 so i might go with whats working…

thanks a lot dkmayer !!!

1 Like

hey Normalizer really helped to reduce big gaps of volume but i cannot get all my signals to stop at one volume given although I tried putting a limiter after the normalizer that doesnt seem to do anything to limit volume. is there a way to do it please ? i dont see why this is so hard to do

thanks a lot

It isn’t clear what you want. “wont stay at one level”… so, a -3 dB signal should be amplified by 3 dB to be full scale… what happens when the note decays so that it’s -20 dB? Or -60 dB, or -150 dB?

It happens many times with computers that the solution seems mysterious, but when the problem is stated clearly, then the solution starts to appear.

Can you explain what you’re after, but in specific detail?

hjh

yes jamshark7, i have a synth playing different sounds usign pbing all routed to a reverb, a compresser, a normalizer once this is done all sounds are bus routed to a compressor ,sidechained to a snare, and routed to another limiter for trying to limit lvls.

The main jumps of volume come from my synth that randomly apply different filters that sometimes are slightly low frequency (which lower the volume) and sometimes high.

i got less big changes in volume and it went quiet stable after using Normalizer but I still get a few dbs difference in between sounds

I hope this describre better the problem, I can make a simplified version of the codes and send to demonstrate the problem if needed

thank you “thumb up”

for example i d like all the sounds to not go over -23db

all right one step further it nearly works when having Normaliser right after synth (before reverb) and one limiter for each sound haha what a nightmare

The problem with normalizer is: if the signal is quiet, it can be amplified by a factor of up to 100000:

            if (maxval2 <= 0.00001f)
                next_level = 100000.f * amp;
            else
                next_level = amp / maxval2;

100000.ampdb = +100 dB.

This means Normalizer, with a short time, will completely destroy envelope characteristics of individual notes. Usually this is a bad thing.

(
a = {
	var trig = Impulse.kr(0.5);
	var decay = Decay2.kr(trig, 0.01, 1.5);
	var sig = LPF.ar(PinkNoise.ar, 1200) * decay;
	var norm = Normalizer.ar(sig, 0.1);
	var index = ToggleFF.kr(trig);
	Poll.kr(trig, index, "0 = normalized, 1 = plain");
	Select.ar(index, [norm, sig]).dup
}.play;
)

I would simply not use Normalizer.

Probably you need a Compander with a quick attack (clampTime) and a long release (relaxTime) – this should respond immediately to attacks, while the long release time should do less damage to envelope shapes. Set the threshold fairly low.

// notes of many volumes
(
a = {
	var trig = Impulse.kr(2);
	var decay = Decay2.kr(trig * TRand.kr(0.05, 0.8, trig), 0.01, 0.7);
	var sig = LPF.ar(PinkNoise.ar, 1200) * decay;
	sig.dup
}.play;
)

// now add an extreme compander
(
a = {
	var trig = Impulse.kr(2);
	var decay = Decay2.kr(trig * TRand.kr(0.05, 0.8, trig), 0.01, 0.7);
	var sig = LPF.ar(PinkNoise.ar, 1200) * decay;
	sig = Compander.ar(sig, sig, 0.001, 1, 0.05, 0.01, 0.8) * 50;
	sig.dup
}.play;
)

But it will never be a perfectly flat level – if you did the same thing in a DAW with a commercial compressor plug-in, you still wouldn’t get a totally flat level.

hjh

2 Likes

ok i ll look at it closer but my synth wont create very low volume sounds , very concerned by envelopes though, thanks for mentioning

well thanks for the help, it isn’t working I get a huge spike at first when I play your code onto mine, curious this question hasn’t been solved before

thanks a lot I’ll update if I figure

crazy the spike only happen at the first play and not on the following notes…

allright I replaced the Normalizer with your codes and it gets better. cant be totally sure it is all working yet but I’ll confirm thanks for your help jamshark70

hey after a first 2 weeks of practise doing mixing on supercollider (adjusting volumes) I am finding very challenging to reach any satisfying output.

Is there tips I can get from experimented users please? for example i only found the meter to visualize my volumes haha isnt there another way to see actual amounts (beside using .dbamp)

thanks a lot <3

writing psytrance lmao

hey jamshark70, following your last very helpful answer i though i d come back to you about that first spike when using the compander to limit volume, I cannot get a rid of it mmm, have you encountered the same problem ?

thank you

You might try CompanderD (check the input list carefully! I think the control signal input is removed). This delays the output slightly so that it can react better to attacks.

If you’re doing sidechained pads, you could also detect the drum attack and use it to trigger an envelope. Then the size of the dip in volume would be independent of the drum’s volume. That is, in DAWs you have to use a sidechain compressor because it’s the only way – but in SC, you can build exactly the processing chain you want (instead of trying to force a hammer to turn screws).

hjh

thank you there is no more spike ! i think i am just too used to the design of ableton limiter that really set a roof/ceiling limit volume that wont go over while adding gain to the source.

thanks a lot hopefully i can manage something that will stay close to the flat levels

CompanderD was the best to get each sounds to a close volume to what i want (remove bumps) and then everything through one limiter to draw the line.

that s the closest so far ^^

In fact, you don’t need a classical compander at all for this.

This way, you have total control over the “pumping” level of the sidechain. This completely eliminates the need to be sure every input stroke is at the same level.

(
s.waitForBoot {
	SynthDef(\fader, { |in, out, level = 1, pan = 0|
		var sig = In.ar(in, 2) * level;
		Out.ar(out, Balance2.ar(sig[0], sig[1], pan))
	}).add;
	SynthDef(\kick, { |out, freq = 55, aFreq = 300, aTime = 0.08,
		dec = 0.3, sus = 0.7, rel = 0.08, amp = 0.1, preamp = 3|
		var eg = EnvGen.ar(Env([0, 1, sus, 0], [0.005, dec, rel], -4), doneAction: 2);
		var feg = EnvGen.ar(Env([aFreq, freq], [aTime], \exp));
		var sig = amp * tanh(SinOsc.ar(feg) * preamp);
		Out.ar(out, (sig * eg).dup);
	}).add;
	SynthDef(\pad, { |out, gate = 1, freq = 440, detun = 1.008, amp = 0.1,
		ffreq = 8000,
		atk = 0.1, dec = 0.3, sus = 0.5, rel = 0.3|
		var n = 7;
		var freqs = freq * Array.fill(n, { detun ** Rand(-1, 1) });
		var sig = Splay.ar(Saw.ar(freqs));
		var eg = EnvGen.ar(Env.adsr(atk, dec, sus, rel), gate, doneAction: 2);
		sig = LPF.ar(LPF.ar(sig, ffreq), ffreq);
		Out.ar(out, sig * (amp * eg));
	}).add;
	SynthDef(\fakeSidechain, { |out, sideBus, thresh = 0.05,
		clamp = 0.05, clampLevel = 0.2, relax = 0.08|
		var sig = In.ar(out, 2);
		var side = In.ar(sideBus, 2).sum;
		var level = Amplitude.ar(side, 0.01, 0.1);
		var gate = level > thresh;
		var eg = EnvGen.ar(Env([1, clampLevel, 1], [clamp, relax], releaseNode: 1), gate);
		ReplaceOut.ar(out, sig * eg);
	}).add;

	s.sync;

	TempoClock.tempo = 128/60;

	~kickbus = Bus.audio(s, 2);
	~kickgroup1 = Group.new;
	~kickgroup = Group(~kickgroup1);
	~kickfader = Synth(\fader, [in: ~kickbus, out: 0], ~kickgroup1, \addToTail);

	~padbus = Bus.audio(s, 2);
	~padgroup1 = Group.after(~kickgroup1);
	~padgroup = Group(~padgroup1);
	~padfader = Synth(\fader, [in: ~padbus, out: 0], ~padgroup1, \addToTail);
	~fakeSidechain = Synth(\fakeSidechain, [
		out: ~padbus, sideBus: ~kickbus,
		relax: 0.1
	], ~padfader, \addBefore);

	~pad = (
		type: \on, instrument: \pad,
		out: ~padbus, group: ~padgroup,
		midinote: [52, 59, 62, 69, 73, 78],
		amp: 0.1
	).play;

	Pdef(\kick, Pbind(
		\instrument, \kick,
		\dur, 1,
		\amp, 0.2,
		\freq, 55,
		\aFreq, 200,
		\aTime, 0.05,
		\dec, 0.1,
		\out, ~kickbus,
		\group, ~kickgroup
	)).play;
};
)

// stop:
~pad.type_(\off).play;
Pdef(\kick).stop;

// clean up:
~kickgroup1.free; ~padgroup1.free;

hjh

2 Likes

oow I save your codes preciously, haven’t had any issue with sidechaining so far. been using ghost" channels to store an extra pbind running of kick and one with snare, both sent to independent compressors as sidechains

thanks heaps

the bumps I mentioned referred to the spikes of volume in the sound my bad

hey =D I realise I am insisting a bit much but CompanderD has been giving me heaps of crashes , all my synths run and work but fail as soon as I play them all with the companderD and I get no error message just a plop noise haha sounds can run infinitely on their own, same for kickbass + percussion but as soon as I Ppar([]) them all in one it crashes and synths keep running says plotTree just no sound

my cpu goes around 20% nothing crazy , does this have happened for someone else ?

thanks !!