View Full Version : Simple compressor Problem
junioreq
12-10-2009, 01:55 AM
I'm trying to port this compressor :
desc:Compressor
slider1:-10<-120,6,1>Threshold [dB]
slider2:3<1,10,1>Ratio
@init
gain=1;
@slider
thresh = 2 ^ (slider1 / 6) ;
ratio = slider2 ;
attack = 2 ^ ( (2000 / srate) / 6 );
release = 2 ^ ( (60 / srate) / 6 );
@sample
maxsamples = max(abs(spl0),abs(spl1));
maxsamples > thresh ?
(
seekgain = thresh + (maxsamples - thresh) / ratio;
) : (
seekgain = 1
);
gain > seekgain ? (gain /= attack; ):(gain *= release; );
spl0 *= gain;
spl1 *= gain;
To iplug:
double gain=1;
double seekgain = 0 ;
double thresh = 2 ^ (-8 / 6) ;
double ratio = 5 ;
double attack = 2 ^ ( (2000 / 44100) / 6 );
double release = 2 ^ ( (60 / 44100) / 6 );
double maxsamples = max(abs(*in1),abs(*in2));
if (maxsamples > thresh)
seekgain = thresh + (maxsamples - thresh) / ratio;
else seekgain = 1;
if (gain > seekgain)
gain /= attack;
else gain*=release;
*out1 = *in1 * gain;
*out2 = *in2 * gain;
And it just isn't working. Any ideas? or sample code for a very simple compressor? Honestly, I'm having ahard time understanding how the attack and release are working.... like.. attack is time....and release is time... but its all ending up as "gain"... ??
I'm trying to port this compressor :
desc:Compressor
slider1:-10<-120,6,1>Threshold [dB]
slider2:3<1,10,1>Ratio
@init
gain=1;
@slider
thresh = 2 ^ (slider1 / 6) ;
ratio = slider2 ;
attack = 2 ^ ( (2000 / srate) / 6 );
release = 2 ^ ( (60 / srate) / 6 );
@sample
maxsamples = max(abs(spl0),abs(spl1));
maxsamples > thresh ?
(
seekgain = thresh + (maxsamples - thresh) / ratio;
) : (
seekgain = 1
);
gain > seekgain ? (gain /= attack; ):(gain *= release; );
spl0 *= gain;
spl1 *= gain;
To iplug:
double gain=1;
double seekgain = 0 ;
double thresh = 2 ^ (-8 / 6) ;
double ratio = 5 ;
double attack = 2 ^ ( (2000 / 44100) / 6 );
double release = 2 ^ ( (60 / 44100) / 6 );
double maxsamples = max(abs(*in1),abs(*in2));
if (maxsamples > thresh)
seekgain = thresh + (maxsamples - thresh) / ratio;
else seekgain = 1;
if (gain > seekgain)
gain /= attack;
else gain*=release;
*out1 = *in1 * gain;
*out2 = *in2 * gain;
And it just isn't working. Any ideas? or sample code for a very simple compressor? Honestly, I'm having ahard time understanding how the attack and release are working.... like.. attack is time....and release is time... but its all ending up as "gain"... ??
JesuSonic and C/C++ have different syntax, so a^b has different semantics. In JS it is power while in C/C++ it is a bitwise exclusive OR. So you want a pow(a,b) in C/C++. Also 2000 is interpreted as an integer in C/C++, so you should make it 2000.0. Also activating a compiler warnings for implicit conversions will warn you about those issues.
Next abs() is/can/mostly is the absoulte value of an integer, so you might want to call fabs() and also keep in mind that not all functions in JS e.g. max(a,b) are defined in C/C++.
As for learning what a compressor does you might find this useful: http://www.kvraudio.com/forum/viewtopic.php?p=3750226 (C++ code is also in that thread).
Regarding why it all ends up in 'gain' that is just how digital audio volume scaling works, simply by multiplying the sample value by a gain factor and 'gain' is itself calculated based on the input sample value the threshold, attack/release coefficient, etc ... I recommend some reading up on DSP and digital audio in general before jumping into cold water.
Hope that helps.
junioreq
12-10-2009, 11:28 AM
Unfortunately I can't find anything on the net about the Logic of how this is working.
And quite honestly, i know this is simple code lol, just having a mental block - well actually, never really looked into how in DSP a comp was working.
~Rob.
cturner
12-11-2009, 05:25 AM
Hi-
I've found these texts to be useful while trying to understand how a limiter works:
The compression tutorial from Max/MSP:
http://vze26m98.net/reaper/OctiMaxCompressionTutorial.pdf
Screenshot of the basic compressor mentioned:
http://vze26m98.net/reaper/basic_compression.png
(I'll put up others if you're interested.)
And Christian Budde's compressor algorithm:
http://www.musicdsp.org/archive.php?classid=4#274
(There's other good stuff on <musicdsp.org>)
HTH, Charles
junioreq
12-11-2009, 09:56 AM
Thank you! That cleared a lot of things up, just the one stumbling block i'm having now. Doing dsp compression, it doesnt seem like the attack is actually moving ahead or backwards in time is it? Looks like its just getting added to the signal. ? It looks like to me that attack time will just ADD signal, and release will just subtract. I think where i'm getting lost is the Per sample thing, visually I just cant picture it. lol racking my brain here.
~Rob.
junioreq
12-11-2009, 07:36 PM
Now kinda picking this apart I see this line:
double maxsamples = max(abs(*in1),abs(*in2));
This looks like full wave rectification - which would be the envelope follower/detector.
http://upload.wikimedia.org/wikipedia/en/b/bc/Envelope_follower.jpg
Is this block also part of the follower?
maxsamples > thresh ?
(
seekgain = thresh + (maxsamples - thresh) / ratio;
) : (
seekgain = 1
);
Not really sure why its called "max samples". But lets say that max samples is 10 and the threshold is 5 and ratio is 5:
seekgain = 5 + 5 / 5 which gives seekgain a value of 2. gain = 1 so seekgain is greater so we use "decay" which is like .0015. so that means
gain * release so 1 * .0015
So all we are doing is for this sample just multiplying the input signal by .0015 ..... ????
How does that equate to a "release" ? Time.
I think the thing you're missing is that the variable called 'release' is not the release time, it is the value the gain should increase by each sample when the signal is under the threshold. In the example above release works out to be 1.00015.
So in the release phase the gain is increased by 1.00015 time each sample time, just what you want for a compressor: gain = gain * release.
junioreq
12-12-2009, 03:13 AM
ok, making more sense, now that i know it isnt time. Still gotta visualize how this is working in my head. I cannot use code unless I 80% understand it.
~Rob.
junioreq
12-12-2009, 06:32 PM
Well, this is what I came up with:
double gain=1;
double seekgain = 0 ;
double threshnum = -15/6;
double thresh = pow(2,threshnum) ;
double ratio = 5 ;
double attack = pow(2, .036751 );
double release = pow(2, 122.5);
double maxsamples = abs(*in1),abs(*in2);
if (maxsamples > thresh)
seekgain = thresh + (maxsamples - thresh) / ratio;
else seekgain = 1;
if (gain > seekgain)
gain = gain / attack;
else gain = gain * release;
*out1 = *in1 * gain;
*out2 = *in2 * gain;
and it does nothing but distort with a constant like +235db redline lol.. Uhhh!!
~Rob.
junioreq
12-12-2009, 06:42 PM
So, if there are 10 samples that are over the threshold, it will apply GR and as soon as it goes under the threshold? what?
So it looks like the compressor is either on or off correct? It looks like the there will always be the same amount of gain reduction. which is set by the attack/release/thresh. if 1 > seekgain then add the attack value, no matter how many db it is over threshold... is this correct?
~Rob.
junioreq
12-13-2009, 02:10 AM
Is "gain" cumulative? might be my big hangup.
~Rob.
Yes, it is initialised to 1 when the plug is loaded, then each sample it just goes up or down a little bit.
junioreq
12-14-2009, 02:04 AM
Still no luck getting this to run in iplug:
band1gain = -10;
double thresh = pow(2.0, (band1gain/44100.0)/6.0);
double ratio = 6 ;
double attack = pow(2.0, (200.0/44100.0)/6.0);
double release = pow(2.0,((60.0)/44100.0)/6.0);
double seekgain;
double maxsamples = max(fabs(*in1),abs(*in2));
if (maxsamples > thresh)
seekgain = thresh + (maxsamples - thresh) / ratio;
else
seekgain = 1;
if(gain > seekgain)
gain /= attack;
else;
gain *= release;
*out1 = *in1 *gain;
*out2 = *in2 * gain;
BTW: I finally understand how the gain is being reduced etc. But this line has me confused. Is there a REASON that this formula was created, or is it just thrown together to get a value? I guess what i'm saying is, what is the logic of this code. seekgain seems that its the target gain u are after, but WHY is ratio in there?? and why is it devided?:
seekgain = thresh + (maxsamples - thresh) / ratio;
~Rob.
Fergo
12-14-2009, 12:36 PM
I've edited a picture originally taken from Wikipedia to try to make the code more clear:
http://img.photobucket.com/albums/v385/Fergo/compression.png
By subtracting the threshold from the maxsamples, you'll have only the part the needs to be compressed (everything above the threshold). Dividing this difference by the ratio (let's suppose it's 2), you'll have the exceeding signal cut in half (the gain reduction in the pic), that added with the threshold will result in the final amplitude of you compressed sample.
The release/attack stuff made that code a little bit hard to "visualize". Most compression codes you find out there compress the signal to the given ration directly, in one single step (no attack time).
Regards,
Fergo
junioreq
12-14-2009, 11:48 PM
Wow! Thank you so much! Actually, the workings of this NOW finally are understood, I thank you so much for your time and effort :)
Here's the resulting audio though :(
http://dl.dropbox.com/u/1933049/CompressorFail.mp3
//double thresh = pow(2.0, (threshold/44100.0)/6.0);
double thresh = .08875;
double attack = 1.005;
double release = 1.0015;
double ratio = 8 ;
//double attack = pow(2.0, (2000.0/44100.0)/6.0);
//double release = pow(2.0,(600.0/44100.0)/6.0);
double maxsamples = max(fabs(*in1),fabs(*in2));
maxsamples += 10e-30f;
if (maxsamples > thresh) {seekgain = thresh + (maxsamples - thresh) / ratio;}
else {seekgain = 1;}
if(gain > seekgain) {gain /= attack;}
else {gain *= release;}
*out1 = *in1 * gain;
*out2 = *in2 * gain;
And just for testing, I am using 441 as my sample rate in reaper. Honestly, this SHOULD work, i don't see any reason for it not too???!!???
~Rob.
Andrew J
12-15-2009, 05:49 PM
Are you still initialising gain to 1?
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.