// written by Till
// filter written by SStillwell based on RBJ's filter cookbook
// SStillwell's copyright notice can be found at the bottom

desc: Auto-Wideness
//tags: processing stereo
//author: Till

slider1:-18<-60,0,1>0% Wideness @ (dB)
slider2:-6<-30,24,1>100% Wideness @ (dB)
slider3:1<0,50,1>Attack (ms)
slider4:250<20,2000,10>Release (ms)
slider5:0<0,50,1>Min Width (%)
slider6:100<50,500,10>Max Width (%)
slider7:0<0,2,1{Left+Right,Left,Right}>0% Signal
slider8:0<0,1,1{No,Yes}>Reverse Mode
slider14:0<0,100,1>Current Wideness (%)
slider9:0<0,5,1{Left+Right,Left,Right,Sidechain Left+Right,Sidechain Left,Sidechain Right}>Director
slider10:20<20,20000,10>Director HP (Hz)
slider11:20000<20,20000,10>Director LP (Hz)
slider12:0<0,1,1{No,Yes}>Preview Director

in_pin:left input
in_pin:right input
in_pin:sidechain left input
in_pin:sidechain right input
out_pin:left output
out_pin:right output

/////////////////
///           ///
///  I N I T  ///
///           ///
/////////////////

@init

  curwideness = 0; // factor

/////////////////
///           ///
///  SLIDER   ///
///           ///
/////////////////

@slider

  // SLIDER VALUES

  bottomdb = slider1; // dB
  bottom = 2 ^ (bottomdb / 6); // Amplitude

  topdb = slider2; // dB
  top = 2 ^ (topdb / 6); // factor

  attack = max(1, ceil(slider3 / 1000 * srate)); // samples

  release = max(1, ceil(slider4 / 1000 * srate)); // samples

  minwidth = slider5;

  maxwidth = slider6;

  zerowidth = slider7;

  reverse = slider8;

  director = slider9;

  hipass = slider10;
  lopass = slider11;

  preview = slider12;

  // filtering values

  a0 = 1;
  s0 = 1;
  q0 = 1 / (sqrt((a0 + 1/a0)*(1/s0 - 1) + 2));
  w00 = 2 * $pi * hipass/srate;
  cosw00 = cos(w00);
  sinw00 = sin(w00);
  alpha0 = sinw00 / (2 * q0);
  
  b00 = (1 + cosw00)/2;
  b10 = -(1 + cosw00);
  b20 = (1 + cosw00)/2;
  a00 = 1 + alpha0;
  a10 = -2 * cosw00;
  a20 = 1 - alpha0;
  b00 /= a00;
  b10 /= a00;
  b20 /= a00;
  a10 /= a00;
  a20 /= a00;
  
  a9 = 1;
  s9 = 2;
  q9 = 1 / (sqrt((a9 + 1/a9)*(1/s9 - 1) + 2));
  w09 = 2 * $pi * lopass/srate;
  cosw09 = cos(w09);
  sinw09 = sin(w09);
  alpha9 = sinw09 / (2 * q9);
  
  b09 = (1 - cosw09)/2;
  b19 = (1 - cosw09);
  b29 = (1 - cosw09)/2;
  a09 = 1 + alpha9;
  a19 = -2 * cosw09;
  a29 = 1 - alpha9;
  b09 /= a09;
  b19 /= a09;
  b29 /= a09;
  a19 /= a09;
  a29 /= a09;

/////////////////
///           ///
///  SAMPLE   ///
///           ///
/////////////////

@sample

  // choosing director

  director == 0 ? (
    dl = spl0;
    dr = spl1;
  ) : director == 1 ? (
    dl = spl0;
    dr = spl0;
  ) : director == 2 ? (
    dl = spl1;
    dr = spl1;
  ) : director == 3 ? (
    dl = spl2;
    dr = spl3;
  ) : director == 4 ? (
    dl = spl2;
    dr = spl2;
  ) : director == 5 ? (
    dl = spl3;
    dr = spl3;
  ) : 0;

  // filtering

  hipass > 20 ? (
    ospl0 = dl;
    dl = b00 * dl + b10 * xl10 + b20 * xl20 - a10 * yl10 - a20 * yl20;
    xl20 = xl10;
    xl10 = ospl0;
    yl20 = yl10;
    yl10 = dl;
  
    ospl1 = dr;
    dr = b00 * dr + b10 * xr10 + b20 * xr20 - a10 * yr10 - a20 * yr20;
    xr20 = xr10;
    xr10 = ospl1;
    yr20 = yr10;
    yr10 = dr;
  );
  
  lopass < 20000 ? (
    ospl0 = dl;
    dl = b09 * dl + b19 * xl19 + b29 * xl29 - a19 * yl19 - a29 * yl29;
    xl29 = xl19;
    xl19 = ospl0;
    yl29 = yl19;
    yl19 = dl;
    
    ospl1 = dr;
    dr = b09 * dr + b19 * xr19 + b29 * xr29 - a19 * yr19 - a29 * yr29;
    xr29 = xr19;
    xr19 = ospl1;
    yr29 = yr19;
    yr19 = dr;
  );

  // choosing 0% width signal

  zerowidth == 0 ? (
    z = (spl0 + spl1) / 2;
  ) : zerowidth == 1 ? (
    z = spl0;
  ) : zerowidth == 2 ? (
    z = spl1;
  ) : 0;

  cursample = (abs(dl) + abs(dr)) / 2;

  cursampledb = 6 * log(cursample) / log(2);
  destwideness = (cursampledb - bottomdb) / (topdb - bottomdb);

  widenesschange = destwideness - curwideness;

  widenesschange > 0 ? (widenesschange = widenesschange / attack) : (widenesschange = widenesschange / release);

  curwideness += widenesschange;

  curwideness = min(reverse ? (1 - minwidth / 100) : (maxwidth / 100), curwideness);
  curwideness = max(reverse ? (1 - maxwidth / 100) : (minwidth / 100), curwideness);

  actualwideness = curwideness;

  reverse ? (
    actualwideness = 1 - actualwideness;
  ) : 0;

  l = actualwideness * spl0 + (1 - actualwideness) * z;
  r = actualwideness * spl1 + (1 - actualwideness) * z;
  
  preview ? (
    spl0 = dl;
    spl1 = dr;
  ) : (
    spl0 = l;
    spl1 = r;
  );

  slider14 = ceil(actualwideness * 100);

// Copyright 2006, Thomas Scott Stillwell
// All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are permitted 
//provided that the following conditions are met:
//
//Redistributions of source code must retain the above copyright notice, this list of conditions 
//and the following disclaimer. 
//
//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. 
//
//The name of Thomas Scott Stillwell may not be used to endorse or 
//promote products derived from this software without specific prior written permission. 
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
//IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 
//BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
//STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
//THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
