// Coded by astrobuf.
//
// An additive type stereo pan.
// 
//
//  use 3dB law (sin/cos taper) constant power across the pan
//      6dB law for equal volume across the pan in mono
//      4.5dB law is a compromise
//
//
// Because as of Reaper 3.75 its pan is wonky.
// 
//  Reaper 3.x pan tapers feature request
//  - discussion:  http://forum.cockos.com/showthread.php?p=434029
//  - feature request:  http://forum.cockos.com/project.php?issueid=1860
//
//  - Reaper 4 prerelease discussion: 
//    http://forum.cockos.com/showthread.php?t=77296
//    http://forum.cockos.com/showthread.php?t=71905
//     http://forum.cockos.com/showthread.php?t=69730
//
//
// This pan works on both mono and stereo sources. It works by mixing channels
// so that on a hard pan the channels are equally mixed. 
//
// This will crush the stereo image at the pan extremes. If that is to be avoided,
// use a stereo field rotation plugin.
//
// Good for stereo or mono mixdowns.
//
//
// If we pan left, we mix an amount (given by the mix curve) of the right channel
// into the left, and vice versa.


desc:Mixing Type Pan 

slider1:0<-90,90,1>Pan
slider2:3.52183<3,6,0.1>Pan Law
slider3:1<0,1,1{sin,linear,1-cos}>Base Mix Curve
slider4:1.4<0.5,2,0.01>Mix Curve Power

@init
pi_2 = 0.5 * $pi;
pi_4 = 0.25 * $pi;
gain3dB = sqrt(2);

G11 = G22 = 1;
G12 = G21 = 0;
dG11 = dG12 = dG21 = dG22 = 0;


@slider
pan = slider1/45;                // map pan in [-1, 1]
pan_rads = slider1 * $pi / 180;  // the pan angle in radians

exponent = slider4;

//////////// Mixing ////////////////////


// LL is the amount of left channel mixed from the left channel.
// LR is the amount of left channel mixed from the right.
// RR is the amout of right channel mixed from the right.
// RL is the amount of right channel mixed from the left.

slider3 == 0 ? ( // sin base curve
    risingmix = abs(sin(2*pan_rads));
);

slider3 == 1 ? ( // linear base curve.
    risingmix = abs(pan);
 );

slider3 == 2 ? ( // 1 - cos base curve
    risingmix = 1 - cos(2*pan_rads);
);

risingmix = risingmix^exponent;

pan < 0 ? (
  LL = 1;
  LR = risingmix;
  RL = 0;
  RR = 1;
  ) : (
  LL = 1;
  LR = 0;
  RL = risingmix;
  RR = 1;
);
  

normL = 1/(LL + LR);
normR = 1/(RR + RL);


////////// Pan Law  ///////////

// constant power (3dB)  pan law.
// we know this is constant power because  sin^2 + cos^2 = 1
panL = cos( (pan+1) * pi_4);
panR = sin( (pan+1) * pi_4);

// constant boost by 3 dB to compensate middle
panL *= gain3dB;
panR *= gain3dB;

// pan law gain
dBgain = 10^((slider2-3)/20);
alpha = (dBgain-1)/(sqrt(2)-1); // Alpha in [0,1]
gain = 1 + alpha*(1/cos(pan*pi_4)-1);

panL *= gain*normL;
panR *= gain*normR;


///////// Transformation Matrix  /////////

T11 = panR*RR;     T12 = panR*RL;
T21 = panL*LR;     T22 = panL*LL;


@block

// This awkwardness to smooth pans and avoid zipper noise.
dG11 = (T11 - G11)/samplesblock;
dG12 = (T12 - G12)/samplesblock;
dG21 = (T21 - G21)/samplesblock;
dG22 = (T22 - G22)/samplesblock;

@sample
G11 += dG11;
G12 += dG12;
G21 += dG21;
G22 += dG22;

rchan = G11*spl1 + G12*spl0;
lchan = G21*spl1 + G22*spl0;

spl1 = rchan;
spl0 = lchan;

