desc:dyson-based advanced compressor

// This effect Copyright (C) 2004 and later Cockos Incorporated
// License: as below

// based on, but might be broken or something:

/* 
 * 
 * Copyright (c) 1996, John S. Dyson *  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * More info/comments: dyson@freebsd.org
 */

slider1:-32<-100,0,1>limit (dB)
slider2:10<1,1000,1>release time (ms)
slider3:0.5<0,1,0.01>compression ratio (fast)
slider4:1<0,1,0.01>compression ratio overall
slider5:0<-120,120,1>preamp (dB)

@init
rlevelsq0filter = .001;
rlevelsq1filter = .010;
rlevelsq0ffilter = .001;
rlevelsqefilter = .001;
maxfastgain = 3;
maxslowgain = 9;
floorlevel = 0.06;
rmastergain0filter = .000003;
rpeakgainfilter = .001;
rpeaklimitdelay = 2500;
rgain = rmastergain0 = 1.0;
rlevelsq0 = levelsq1 = 0;
rlevelsq1 = 0;
compress = 1;
ndelay = (1.0 / rlevelsq0ffilter)|0;

rpeakgain0 = 1.0;
rpeakgain1 = 1.0;
rpeaklimitdelay = 0;
ndelayptr = 0;
lastrgain = 1.0;

NFILT = 12-1;
NEFILT = 17-1;

delaybuf=0;
ndelayptr=0;
rlevelsqn=delaybuf+ndelay*2;
rlevelsqe=rlevelsqn+NFILT+1;


@slider

// target level
maxlevel = 0.9;
targetlevel = maxlevel * (2^(slider1/6));

// linear gain filters
releasetime=slider2*0.001;
rgainfilter=1.0 / (releasetime * srate);

// compression ratio (fast gain)
fratio = slider3;
fastgaincompressionratio=fratio;
// compression ratio
ratio=slider4;
compressionratio=ratio;

preamp = 2^(slider5/6);

@sample
  delaybuf[ndelayptr] = spl0*preamp;
  delaybuf[ndelayptr+1] = spl1*preamp;
  ndelayptr += 2;
  ndelayptr >= ndelay ? ndelayptr=0;

  compress ? (
    levelsq0 = sqr(spl0) + sqr(spl1);
    rlevelsq0 = (levelsq0 * (levelsq0 > rlevelsq0 ? rlevelsq0ffilter : rlevelsq0filter)) + rlevelsq0 * (1 - rlevelsq0ffilter);

    rlevelsq0 > sqr(floorlevel) ? 
    (
      rlevelsq1 = rlevelsq0 > rlevelsq1 ? rlevelsq0 : rlevelsq0 * rlevelsq1filter + rlevelsq1 * (1 - rlevelsq1filter);

      rlevelsqn[0] = rlevelsq1;
      i=0;
      loop(NFILT,
           rlevelsqn[i+1] = rlevelsqn[i] > rlevelsqn[i+1] ? rlevelsqn[i] : rlevelsqn[i] * rlevelsq1filter +  rlevelsqn[i+1] * (1 - rlevelsq1filter);
           i+=1;
      );
      efilt = rlevelsqefilter;
      levelsqe = rlevelsqe[0] = rlevelsqn[NFILT];

      i=0;
      loop(NEFILT,
        i+=1;
        rlevelsqe[i] = rlevelsqe[i-1] * efilt + rlevelsqe[i] * (1.0 - efilt);
        rlevelsqe[i] > levelsqe ? levelsqe = rlevelsqe[i];
        efilt *= 0.66666666667;
       );

       gain = targetlevel * invsqrt(levelsqe);
       compressionratio < 0.99 ?
       (
         gain = compressionratio == 0.50 ? sqrt(gain) : exp(log(gain) * compressionratio);
       );
       
      rgain = gain < rgain ? 
        gain * rlevelsqefilter/2 + rgain * (1 - rlevelsqefilter*0.5)
        :
        gain * rgainfilter + rgain * (1 - rgainfilter);

      lastrgain = min(rgain,gain);
    );
    skipmode=1;
  ) 
  : skipmode=0;

  tgain = lastrgain;
  
  leftd = delaybuf[ndelayptr];
  rightd = delaybuf[ndelayptr+1];
  fastgain = max(min(tgain,maxfastgain),0.0001);

  fastgaincompressionratio == 0.25 ? qgain = sqrt(sqrt(fastgain)) :
    fastgaincompressionratio == 0.5 ? qgain = sqrt(fastgain) :
      fastgaincompressionratio == 1.0 ? qgain = fastgain : 
        qgain = exp(log(fastgain) * fastgaincompressionratio);

   tslowgain = min(tgain / qgain,maxslowgain);    

   rmastergain0 = tslowgain < rmastergain0 ? tslowgain : tslowgain * rmastergain0filter + (1 - rmastergain0filter) * rmastergain0;
   slowgain = rmastergain0;
   skipmode ? npeakgain = slowgain * qgain;

   newright = rightd * npeakgain;
   nrgain = abs(newright) >= maxlevel ? maxlevel / abs(newright) : 1.0;
   newleft = leftd * npeakgain;
   nlgain = abs(newleft) >= maxlevel ? maxlevel / abs(newleft) : 1.0;

   ngain=min(nrgain,nlgain);

   ngsq = ngain * ngain;
   ngsq <= rpeakgain0 ?
   (
      rpeakgain0 = ngsq;
      rpeaklimitdelay = peaklimitdelay;
   ) : rpeaklimitdelay == 0 ? 
   (
      nrgain > 1.0 ? tnrgain = 1.0 : tnrgain = nrgain;
      rpeakgain0 = tnrgain * rpeakgainfilter + (1.0 - rpeakgainfilter) * rpeakgain0;
   );

   rpeakgain0 <= rpeakgain1 ? 
   (
     rpeakgain1 = rpeakgain0;
     rpeaklimitdelay = peaklimitdelay;
   ) : rpeaklimitdelay == 0 ? 
   (
     rpeakgain1 = rpeakgainfilter * rpeakgain0 + (1.0 - rpeakgainfilter) * rpeakgain1;
   ) : (
     rpeaklimitdelay-=1;
   );

    sqrtrpeakgain = sqrt(rpeakgain1);
    totalgain = npeakgain * sqrtrpeakgain;
    
    spl1 = newright * sqrtrpeakgain;
    spl0 = newleft * sqrtrpeakgain;
