// Coded by astrobuf.
//
// Rotation based panning.
//
//  use 3dB law (sin/cos taper) constant power across the pan
//      6dB law (linear taper) 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 is compatible with both stereo and mono sources. On 
// stereo sources, it rotates and smoothly crushes the stereo field till
// on a hard pan the signal is equally mixed on one channel. 
// 
// Because it proportionally crushes the stereo field, it maintains good mono 
// compatibilty. This makes it a good panner for most mono or stereo source 
// material with a mono or stereo mixdown.
//



desc: Rotation based Pan

slider1:0<-180,180,1>Pan
slider2:4.5<3,6,0.1>Pan Law

@init

G11 = 1.0; G12 = 0.0;
G21 = 0.0; G22 = 1.0;
W = 1.0;

@slider

// map pan to radians
pan = -slider1 * $pi/180;

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

width = 1 - abs(sin(pan)/sin($pi/4));


// Rotation matrix.
R11 = gain*cos(pan);  R12 = -gain*sin(pan);
R21 = gain*sin(pan);  R22 = gain*cos(pan);

@block
// Smooth coefficients to avoid zipper noise during a sweep.
d11 = (R11 - G11) / samplesblock;
d12 = (R12 - G12) / samplesblock;
d21 = (R21 - G21) / samplesblock;
d22 = (R22 - G22) / samplesblock;
dW = (width - W) / samplesblock;

@sample

// Smooth the coefficients.
G11 += d11;
G12 += d12;
G21 += d21;
G22 += d22;
W += dW;

// M/S Conversion.
M = (spl0 + spl1) / 2;
S = (spl0 - spl1) / 2;

// Crush stereo;
S *= W;

// Convert back to L/R.
L = M + S;
R = M - S;

// Rotate.
spl1 = R*G11 + L*G12;
spl0 = R*G21 + L*G22;

