/*
  Rakarrack   Audio FX software
  Stompbox.C - stompbox modeler
  Modified for rakarrack by Ryan Billing

  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License
  as published by the Free Software Foundation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License (version 2) for more details.

  You should have received a copy of the GNU General Public License (version 2)
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

*/

#include "StompBox.h"

#ifdef SHR3D_SFX_CORE_RAKARRACK

#ifdef SHR3D_SFX_CORE_RAKARRACK_LIBSAMPLERATE

StompBox::StompBox()
//left channel filters
  : linput(1, 80.0f, 1.0f, 0)  //  AnalogFilter (unsigned char Ftype, f32 Ffreq, f32 Fq,unsigned char Fstages)
  , lpre1(1, 630.0f, 1.0f, 0)   // LPF = 0, HPF = 1
  , lpre2(1, 220.0f, 1.0f, 0)
  , lpost(0, 720.0f, 1.0f, 0)
  , ltonehg(1, 1500.0f, 1.0f, 0)
  , ltonemd(4, 1000.0f, 1.0f, 0)
  , ltonelw(0, 500.0f, 1.0, 0)
  //Right channel filters
  , rinput(1, 80.0f, 1.0f, 0)  //  AnalogFilter (unsigned char Ftype, f32 Ffreq, f32 Fq,unsigned char Fstages)
  , rpre1(1, 630.0f, 1.0f, 0)   // LPF = 0, HPF = 1
  , rpre2(1, 220.0f, 1.0f, 0)
  , rpost(0, 720.0f, 1.0f, 0)
  , rtonehg(1, 1500.0f, 1.0f, 0)
  , rtonemd(4, 1000.0f, 1.0f, 0)
  , rtonelw(0, 500.0f, 1.0f, 0)
  //Anti-aliasing for between stages
  , ranti(0, 6000.0f, 0.707f, 1)
  , lanti(0, 6000.0f, 0.707f, 1)
{
  //default values
  cleanup();

  setpreset(0);
}

void StompBox::cleanup()
{
  linput.cleanup();
  lpre1.cleanup();
  lpre2.cleanup();
  lpost.cleanup();
  ltonehg.cleanup();
  ltonemd.cleanup();
  ltonelw.cleanup();

  //right channel filters  
  rinput.cleanup();
  rpre1.cleanup();
  rpre2.cleanup();
  rpost.cleanup();
  rtonehg.cleanup();
  rtonemd.cleanup();
  rtonelw.cleanup();

  ranti.cleanup();
  lanti.cleanup();

  rwshape.cleanup();
  lwshape.cleanup();
  rwshape2.cleanup();
  lwshape2.cleanup();
}

void StompBox::processBlock(f32** inBlock, f32** outBlock, const i32 blockSize)
{
  f32 hfilter;  //temporary variables
  f32 mfilter;
  f32 lfilter;
  f32 tempr;
  f32 templ;

  switch (Pmode)
  {
  case 0:          //Odie
    lpre2.filterout(inBlock[0], blockSize);
    rpre2.filterout(inBlock[1], blockSize);
    rwshape.waveshapesmps(blockSize, inBlock[0], 28, 20, 1);  //Valve2
    lwshape.waveshapesmps(blockSize, inBlock[1], 28, 20, 1);
    ranti.filterout(inBlock[1], blockSize);
    lanti.filterout(inBlock[0], blockSize);
    lpre1.filterout(inBlock[0], blockSize);
    rpre1.filterout(inBlock[1], blockSize);
    rwshape2.waveshapesmps(blockSize, inBlock[0], 28, Pgain, 1);  //Valve2
    lwshape2.waveshapesmps(blockSize, inBlock[1], 28, Pgain, 1);

    lpost.filterout(inBlock[0], blockSize);
    rpost.filterout(inBlock[1], blockSize);

    for (i32 i = 0; i < blockSize; i++)
    {
      //left channel
      lfilter = ltonelw.filterout_s(inBlock[0][i]);
      mfilter = ltonemd.filterout_s(inBlock[0][i]);
      hfilter = ltonehg.filterout_s(inBlock[0][i]);

      outBlock[0][i] = 0.5f * volume * (inBlock[0][i] + lowb * lfilter + midb * mfilter + highb * hfilter);

      //Right channel
      lfilter = rtonelw.filterout_s(inBlock[1][i]);
      mfilter = rtonemd.filterout_s(inBlock[1][i]);
      hfilter = rtonehg.filterout_s(inBlock[1][i]);

      outBlock[1][i] = 0.5f * volume * (inBlock[1][i] + lowb * lfilter + midb * mfilter + highb * hfilter);
    }
    return;
  case 1:  //Grunge
  case 5:  //Death Metal
  case 6:  //Metal Zone
    linput.filterout(inBlock[0], blockSize);
    rinput.filterout(inBlock[1], blockSize);

    for (i32 i = 0; i < blockSize; i++)
    {
      templ = inBlock[0][i] * (gain * pgain + 0.01f);
      tempr = inBlock[1][i] * (gain * pgain + 0.01f);
      inBlock[0][i] += lpre1.filterout_s(templ);
      inBlock[1][i] += rpre1.filterout_s(tempr);
    }
    rwshape.waveshapesmps(blockSize, inBlock[0], 24, 1, 1);  // Op amp limiting
    lwshape.waveshapesmps(blockSize, inBlock[1], 24, 1, 1);

    ranti.filterout(inBlock[1], blockSize);
    lanti.filterout(inBlock[0], blockSize);

    rwshape2.waveshapesmps(blockSize, inBlock[0], 23, Pgain, 1);  // hard comp
    lwshape2.waveshapesmps(blockSize, inBlock[1], 23, Pgain, 1);

    for (i32 i = 0; i < blockSize; i++)
    {
      inBlock[0][i] = inBlock[0][i] + RGP2 * lpre2.filterout_s(inBlock[0][i]);
      inBlock[1][i] = inBlock[1][i] + RGP2 * rpre2.filterout_s(inBlock[1][i]);
      inBlock[0][i] = inBlock[0][i] + RGPST * lpost.filterout_s(inBlock[0][i]);
      inBlock[1][i] = inBlock[1][i] + RGPST * rpost.filterout_s(inBlock[1][i]);

      //left channel
      lfilter = ltonelw.filterout_s(inBlock[0][i]);
      mfilter = ltonemd.filterout_s(inBlock[0][i]);
      hfilter = ltonehg.filterout_s(inBlock[0][i]);

      outBlock[0][i] = 0.1f * volume * (inBlock[0][i] + lowb * lfilter + midb * mfilter + highb * hfilter);

      //Right channel
      lfilter = rtonelw.filterout_s(inBlock[1][i]);
      mfilter = rtonemd.filterout_s(inBlock[1][i]);
      hfilter = rtonehg.filterout_s(inBlock[1][i]);

      outBlock[1][i] = 0.1f * volume * (inBlock[1][i] + lowb * lfilter + midb * mfilter + highb * hfilter);
    }
    return;
  case 2:  //Rat
  case 3:  //Fat Cat  //Pre gain & filter freqs the only difference

    linput.filterout(inBlock[0], blockSize);
    rinput.filterout(inBlock[1], blockSize);

    for (i32 i = 0; i < blockSize; i++)
    {
      templ = inBlock[0][i];
      tempr = inBlock[1][i];
      inBlock[0][i] += lpre1.filterout_s(pre1gain * gain * templ);
      inBlock[1][i] += rpre1.filterout_s(pre1gain * gain * tempr);  //Low freq gain stage
      inBlock[0][i] += lpre2.filterout_s(pre2gain * gain * templ);
      inBlock[1][i] += rpre2.filterout_s(pre2gain * gain * tempr); //High freq gain stage
    }

    rwshape.waveshapesmps(blockSize, inBlock[0], 24, 1, 1);  // Op amp limiting
    lwshape.waveshapesmps(blockSize, inBlock[1], 24, 1, 1);

    ranti.filterout(inBlock[1], blockSize);
    lanti.filterout(inBlock[0], blockSize);

    rwshape2.waveshapesmps(blockSize, inBlock[0], 23, 1, 0);  // hard comp
    lwshape2.waveshapesmps(blockSize, inBlock[1], 23, 1, 0);

    for (i32 i = 0; i < blockSize; i++)
    {
      //left channel
      lfilter = ltonelw.filterout_s(inBlock[0][i]);
      mfilter = ltonemd.filterout_s(inBlock[0][i]);

      outBlock[0][i] = 0.5f * ltonehg.filterout_s(volume * (inBlock[0][i] + lowb * lfilter + midb * mfilter));

      //Right channel
      lfilter = rtonelw.filterout_s(inBlock[1][i]);
      mfilter = rtonemd.filterout_s(inBlock[1][i]);

      outBlock[1][i] = 0.5f * rtonehg.filterout_s(volume * (inBlock[1][i] + lowb * lfilter + midb * mfilter));
    }
    return;
  case 4:  //Dist+

    linput.filterout(inBlock[0], blockSize);
    rinput.filterout(inBlock[1], blockSize);

    for (i32 i = 0; i < blockSize; i++)
    {
      templ = inBlock[0][i];
      tempr = inBlock[1][i];
      inBlock[0][i] += lpre1.filterout_s(pre1gain * gain * templ);
      inBlock[1][i] += rpre1.filterout_s(pre1gain * gain * tempr);  //Low freq gain stage    
    }

    rwshape.waveshapesmps(blockSize, inBlock[0], 24, 1, 1);  // Op amp limiting
    lwshape.waveshapesmps(blockSize, inBlock[1], 24, 1, 1);

    ranti.filterout(inBlock[1], blockSize);
    lanti.filterout(inBlock[0], blockSize);

    rwshape2.waveshapesmps(blockSize, inBlock[0], 29, 1, 0);  // diode limit
    lwshape2.waveshapesmps(blockSize, inBlock[1], 29, 1, 0);

    for (i32 i = 0; i < blockSize; i++)
    {
      //left channel
      lfilter = ltonelw.filterout_s(inBlock[0][i]);
      mfilter = ltonemd.filterout_s(inBlock[0][i]);

      outBlock[0][i] = 0.5f * ltonehg.filterout_s(volume * (inBlock[0][i] + lowb * lfilter + midb * mfilter));

      //Right channel
      lfilter = rtonelw.filterout_s(inBlock[1][i]);
      mfilter = rtonemd.filterout_s(inBlock[1][i]);

      outBlock[1][i] = 0.5f * rtonehg.filterout_s(volume * (inBlock[1][i] + lowb * lfilter + midb * mfilter));
    }
    return;
  case 7:          //Classic Fuzz
    lpre1.filterout(inBlock[0], blockSize);
    rpre1.filterout(inBlock[1], blockSize);
    linput.filterout(inBlock[0], blockSize);
    rinput.filterout(inBlock[1], blockSize);
    rwshape.waveshapesmps(blockSize, inBlock[1], 19, 25, 1);  //compress
    lwshape.waveshapesmps(blockSize, inBlock[0], 19, 25, 1);

    for (i32 i = 0; i < blockSize; i++)
    {
      //left channel
      mfilter = ltonemd.filterout_s(inBlock[0][i]);

      templ = lpost.filterout_s(fabs(inBlock[0][i]));
      tempr = rpost.filterout_s(fabs(inBlock[1][i]));   //dynamic symmetry   

      inBlock[0][i] += lowb * templ + midb * mfilter;      //In this case, lowb control tweaks symmetry

      //Right channel
      mfilter = rtonemd.filterout_s(inBlock[1][i]);
      inBlock[1][i] += lowb * tempr + midb * mfilter;
    }

    ranti.filterout(inBlock[1], blockSize);
    lanti.filterout(inBlock[0], blockSize);
    rwshape2.waveshapesmps(blockSize, inBlock[1], 25, Pgain, 1);  //JFET
    lwshape2.waveshapesmps(blockSize, inBlock[0], 25, Pgain, 1);
    lpre2.filterout(inBlock[0], blockSize);
    rpre2.filterout(inBlock[1], blockSize);

    for (i32 i = 0; i < blockSize; i++)
    {
      //left channel
      lfilter = ltonelw.filterout_s(inBlock[0][i]);
      hfilter = ltonehg.filterout_s(inBlock[0][i]);

      outBlock[0][i] = volume * ((1.0f - highb) * lfilter + highb * hfilter);  //classic BMP tone stack

      //Right channel
      lfilter = rtonelw.filterout_s(inBlock[1][i]);
      hfilter = rtonehg.filterout_s(inBlock[1][i]);

      outBlock[1][i] = volume * ((1.0f - highb) * lfilter + highb * hfilter);
    }
    return;
  }
  ASSERT(false);
}

void StompBox::init_mode(i32 value)
{
  i32 tinput = 1;
  f32 finput = 80.0f;
  f32 qinput = 1.0f;
  i32 sinput = 0;

  i32 tpre1 = 1;
  f32 fpre1 = 708.0f;
  f32 qpre1 = 1.0f;
  i32 spre1 = 0;

  i32 tpre2 = 1;
  f32 fpre2 = 30.0f;
  f32 qpre2 = 1.0f;
  i32 spre2 = 0;

  i32 tpost = 0;
  f32 fpost = 720.0f;
  f32 qpost = 1.0f;
  i32 spost = 0;

  i32 ttonehg = 1;
  f32 ftonehg = 1500.0f;
  f32 qtonehg = 1.0f;
  i32 stonehg = 0;

  i32 ttonemd = 4;
  f32 ftonemd = 720.0f;
  f32 qtonemd = 1.0f;
  i32 stonemd = 0;

  i32 ttonelw = 0;
  f32 ftonelw = 500.0f;
  f32 qtonelw = 1.0f;
  i32 stonelw = 0;

  switch (value)
  {
  case 0:
    tinput = 1;
    finput = 80.0f;
    qinput = 1.0f;
    sinput = 0;

    tpre1 = 1;
    fpre1 = 630.0f;
    qpre1 = 1.0f;
    spre1 = 0;

    tpre2 = 1;
    fpre2 = 220.0f;
    qpre2 = 1.0f;
    spre2 = 0;

    tpost = 0;
    fpost = 720.0f;
    qpost = 1.0f;
    spost = 0;

    ttonehg = 1;
    ftonehg = 1500.0f;
    qtonehg = 1.0f;
    stonehg = 0;

    ttonemd = 4;
    ftonemd = 720.0f;
    qtonemd = 1.0f;
    stonemd = 0;

    ttonelw = 0;
    ftonelw = 500.0f;
    qtonelw = 1.0f;
    stonelw = 0;
    break;
  case 1: //Grunge
    // Some key filter stages based upon a schematic for a grunge pedal 
    // Total gain up to 25,740/2 (91dB)
    // Fc1 =  999.02  Gain = 110 = 40.8dB
    // Q1 =  2.9502
    // gain stage 1rst order HP @ 340 Hz, Gain = 21.3 ... 234 (26dB ... 47dB)
    // Fc2 =  324.50
    // Q2 =  4.5039
    // Fc3 =  5994.1
    // Q3 =  1.7701
    // Fc4 =  127.80
    // Q4 =  3.7739

    tinput = 4;         //Pre-Emphasis filter
    finput = 1000.0f;
    qinput = 2.95f;
    sinput = 0;
    pgain = 110.0f;

    tpre1 = 0;         //Gain stage reduce aliasing
    fpre1 = 6000.0f;
    qpre1 = 0.707f;
    spre1 = 2;

    tpre2 = 4;        //being used as a recovery filter, gain = 10
    fpre2 = 324.5f;
    qpre2 = 4.5f;
    spre2 = 0;
    RGP2 = 10.0f;

    tpost = 4;       //The other recovery filter, gain = 3
    fpost = 6000.0f;
    qpost = 1.77f;
    spost = 0;
    RGPST = 3.0f;

    ttonehg = 1;       //high shelf ranging 880 to 9700 Hz, gain 10
    ftonehg = 4000.0f;
    qtonehg = 1.0f;
    stonehg = 0;

    ttonemd = 4;       // Pedal has no mid filter so I'll make up my own
    ftonemd = 1000.0f;
    qtonemd = 2.0f;
    stonemd = 0;

    ttonelw = 4;       //Low Eq band, peaking type, gain = up to 22.
    ftonelw = 128.0f;
    qtonelw = 3.8f;
    stonelw = 0;
    break;
  case 2: //ProCo Rat Distortion emulation
    // Some key filter stages based upon a schematic for a grunge pedal 

    tinput = 0;         //Reduce some noise aliasing
    finput = 5000.0f;
    qinput = 1.0f;
    sinput = 3;

    tpre1 = 1;         //Gain stage high boost, gain = 1 ... 268 (max)
    fpre1 = 60.0f;
    qpre1 = 1.0f;
    spre1 = 0;
    pre1gain = 268.0f;

    tpre2 = 1;        //being used as a recovery filter, gain = 1 ... 3000
    fpre2 = 1539.0f;
    qpre2 = 1.0f;
    spre2 = 0;
    pre2gain = 3000.0f;

    tpost = 0;       //Not used...initialized to "something"
    fpost = 6000.0f;
    qpost = 1.77f;
    spost = 0;

    ttonehg = 0;       //frequency sweeping LPF
    ftonehg = 1000.0f;
    qtonehg = 1.0f;
    stonehg = 0;

    ttonemd = 4;       // Pedal has no mid filter so I'll make up my own
    ftonemd = 700.0f;
    qtonemd = 2.0f;
    stonemd = 0;

    ttonelw = 0;       //Pedal has no Low filter, so make up my own...Low Eq band, peaking type
    ftonelw = 328.0f;  //Mild low boost
    qtonelw = 0.50f;
    stonelw = 1;
    break;
  case 3: //Fat Cat Distortion emulation
  case 4: //MXR Dist+ emulation (many below filters unuse)
    // Some key filter stages based upon a schematic for a grunge pedal 
    tinput = 0;         //Reduce some noise aliasing
    finput = 5000.0f;
    qinput = 1.0f;
    sinput = 3;

    tpre1 = 1;         //Gain stage high boost, gain = 1 ... 100 (max)
    fpre1 = 33.0f;
    qpre1 = 1.0f;
    spre1 = 0;
    pre1gain = 100.0f;

    tpre2 = 1;        //being used as a recovery filter, gain = 1 ... 1700
    fpre2 = 861.0f;
    qpre2 = 1.0f;
    spre2 = 0;
    pre2gain = 1700.0f;

    tpost = 0;       //Not used...initialized to "something"
    fpost = 6000.0f;
    qpost = 1.77f;
    spost = 0;

    ttonehg = 0;       //frequency sweeping LPF
    ftonehg = 1000.0f;
    qtonehg = 1.0f;
    stonehg = 0;

    ttonemd = 4;       // Pedal has no mid filter so I'll make up my own
    ftonemd = 700.0f;
    qtonemd = 2.0f;
    stonemd = 0;

    ttonelw = 0;       //Pedal has no Low filter, so make up my own...Low Eq band, peaking type
    ftonelw = 328.0f;  //Mild low boost
    qtonelw = 0.50f;
    stonelw = 1;
    break;
  case 5: //Death Metal
    // Some key filter stages based upon a schematic for a grunge pedal 
    tinput = 4;         //Pre-Emphasis filter
    finput = 6735.4f;
    qinput = 0.43f;
    sinput = 0;
    pgain = 110.0f;

    tpre1 = 0;         //Gain stage reduce aliasing
    fpre1 = 6000.0f;
    qpre1 = 0.707f;
    spre1 = 2;

    tpre2 = 4;        //being used as a recovery filter, gain = 10
    fpre2 = 517.0f;
    qpre2 = 7.17f;
    spre2 = 0;
    RGP2 = 1.0f;

    tpost = 4;       //The other recovery filter, gain = 10
    fpost = 48.0f;
    qpost = 6.68f;
    spost = 0;
    RGPST = 10.0f;

    ttonehg = 1;       //high shelf ranging 880 to 9700 Hz, gain 11
    ftonehg = 4000.0f;
    qtonehg = 1.0f;
    stonehg = 0;
    HG = 11.0f;

    ttonemd = 4;       // Mid band EQ gain 11
    ftonemd = 1017.0f;
    qtonemd = 1.15f;
    stonemd = 0;
    MG = 11.0f;

    ttonelw = 4;       //Low Eq band, peaking type, gain = up to 22.
    ftonelw = 107.0f;
    qtonelw = 3.16f;
    stonelw = 0;
    LG = 22.0f;
    break;
  case 6: //Metal Zone
    // Some key filter stages based upon a schematic for a grunge pedal 
    tinput = 4;         //Pre-Emphasis filter
    finput = 952.53f;
    qinput = 2.8f;
    sinput = 0;
    pgain = 100.0f;

    tpre1 = 0;         //Gain stage reduce aliasing
    fpre1 = 6000.0f;
    qpre1 = 0.707f;
    spre1 = 2;

    tpre2 = 4;        //being used as a recovery filter, gain = 10
    fpre2 = 4894.0f;
    qpre2 = 2.16f;
    spre2 = 0;
    RGP2 = 3.3f;

    tpost = 4;       //The other recovery filter, gain = 10
    fpost = 105.0f;
    qpost = 14.62f;
    spost = 0;
    RGPST = 7.0f;

    ttonehg = 1;       //high shelf ranging 880 to 9700 Hz, gain 11
    ftonehg = 4000.0f;
    qtonehg = 1.0f;
    stonehg = 0;
    HG = 10.0f;

    ttonemd = 4;       // Mid band EQ gain 11
    ftonemd = 1017.0f;
    qtonemd = 1.15f;
    stonemd = 0;
    MG = 11.0f;

    ttonelw = 4;       //Low Eq band, peaking type, gain = up to 22.
    ftonelw = 105.50f;
    qtonelw = 3.11f;
    stonelw = 0;
    LG = 3.33f;
    break;
  case 7:  //Classic Fuzz
    tinput = 1;
    finput = 80.0f;
    qinput = 1.0f;
    sinput = 0;

    tpre1 = 0;
    fpre1 = 4500.0f;
    qpre1 = 1.0f;
    spre1 = 1;

    tpre2 = 1;
    fpre2 = 40.0f;
    qpre2 = 1.0f;
    spre2 = 0;

    tpost = 0;
    fpost = 2.0f;
    qpost = 1.0f;
    spost = 0;

    ttonehg = 1;
    ftonehg = 397.0f;
    qtonehg = 1.0f;
    stonehg = 0;

    ttonemd = 4;
    ftonemd = 515.0f;  //sort of like a stuck wahwah
    qtonemd = 4.0f;
    stonemd = 0;

    ttonelw = 0;
    ftonelw = 295.0f;
    qtonelw = 1.0f;
    stonelw = 0;
    break;
  }

  //left channel filters
  //  AnalogFilter (unsigned char Ftype, f32 Ffreq, f32 Fq,unsigned char Fstages);
  // LPF = 0, HPF = 1
  linput.settype(tinput);
  linput.setfreq_and_q(finput, qinput);
  linput.setstages(sinput);

  lpre1.settype(tpre1);
  lpre1.setfreq_and_q(fpre1, qpre1);
  lpre1.setstages(spre1);

  lpre2.settype(tpre2);
  lpre2.setfreq_and_q(fpre2, qpre2);
  lpre2.setstages(spre2);

  lpost.settype(tpost);
  lpost.setfreq_and_q(fpost, qpost);
  lpost.setstages(spost);

  ltonehg.settype(ttonehg);
  ltonehg.setfreq_and_q(ftonehg, qtonehg);
  ltonehg.setstages(stonehg);

  ltonemd.settype(ttonemd);
  ltonemd.setfreq_and_q(ftonemd, qtonemd);
  ltonemd.setstages(stonemd);

  ltonelw.settype(ttonelw);
  ltonelw.setfreq_and_q(ftonelw, qtonelw);
  ltonelw.setstages(stonelw);

  //right channel filters  

  rinput.settype(tinput);
  rinput.setfreq_and_q(finput, qinput);
  rinput.setstages(sinput);

  rpre1.settype(tpre1);
  rpre1.setfreq_and_q(fpre1, qpre1);
  rpre1.setstages(spre1);

  rpre2.settype(tpre2);
  rpre2.setfreq_and_q(fpre2, qpre2);
  rpre2.setstages(spre2);

  rpost.settype(tpost);
  rpost.setfreq_and_q(fpost, qpost);
  rpost.setstages(spost);

  rtonehg.settype(ttonehg);
  rtonehg.setfreq_and_q(ftonehg, qtonehg);
  rtonehg.setstages(stonehg);

  rtonemd.settype(ttonemd);
  rtonemd.setfreq_and_q(ftonemd, qtonemd);
  rtonemd.setstages(stonemd);

  rtonelw.settype(ttonelw);
  rtonelw.setfreq_and_q(ftonelw, qtonelw);
  rtonelw.setstages(stonelw);
}

void StompBox::init_tone()
{
  f32 varf;
  switch (Pmode)
  {
  case 0:
    varf = 2533.0f + highb * 1733.0f;  //High tone ranges from 800 to 6000Hz
    rtonehg.setfreq(varf);
    ltonehg.setfreq(varf);
    if (highb > 0.0f) highb = ((f32)Phigh) / 8.0f;
    break;
  case 1:
    varf = 3333.0f + highb * 2500.0f;  //High tone ranges from 833 to 8333Hz
    rtonehg.setfreq(varf);
    ltonehg.setfreq(varf);

    if (highb > 0.0f)
      highb = ((f32)Phigh) / 16.0f;
    if (lowb > 0.0f)
      lowb = ((f32)Plow) / 18.0f;
    break;
  case 2:
  case 3:
    varf = 3653.0f + highb * 3173.0f;  //High tone ranges from ~480 to 10k
    rtonehg.setfreq(varf);
    ltonehg.setfreq(varf);
    break;
  case 4:
    varf = gain * 700.0f + 20.0f;
    rpre1.setfreq(varf);
    lpre1.setfreq(varf);
    pre1gain = 212.0f;
    varf = 3653.0f + highb * 3173.0f;  //High tone ranges from ~480 to 10k
    rtonehg.setfreq(varf);
    ltonehg.setfreq(varf);
    break;
  case 5: //Death Metal
  case 6: //Mid Elves Own
    varf = 3653.0f + highb * 3173.0f;  //High tone ranges from ~480 to 10k
    rtonehg.setfreq(varf);
    ltonehg.setfreq(varf);

    if (highb > 0.0f)
      highb = HG * ((f32)Phigh) / 64.0f;
    if (lowb > 0.0f)
      lowb = LG * ((f32)Plow) / 64.0f;
    if (midb > 0.0f)
      midb = MG * ((f32)Pmid) / 64.0f;
    break;
  case 7:
    highb = ((f32)Phigh + 64) / 127.0f;
    varf = 40.0f + gain * 200.0f;
    linput.setfreq(varf);
    rinput.setfreq(varf);
    if (midb > 0.0f)
      midb = ((f32)Pmid) / 8.0f;
    lowb = ((f32)Plow) / 64.0f;

    varf = 1085.0f - lowb * 1000.0f;
    lpre1.setfreq(varf);
    rpre1.setfreq(varf);
    break;
  }
}

void StompBox::setvolume(i32 value)
{
  Pvolume = value;
  volume = (f32)Pvolume / 127.0f;
}

void StompBox::setpreset(i32 npreset)
{
  const i32 PRESET_SIZE = 6;
  i32 presets[][PRESET_SIZE] = {
    //Odie
    {80, 32, 0, 32, 10, 0},
    //Grunger
    {48, 10, -6, 55, 85, 1},
    //Hard Dist.
    {48, -22, -6, 38, 12, 1},
    //Ratty
    {48, -20, 0, 0, 70, 2},
    //Classic Dist
    {50, 64, 0, 0, 110, 4},
    //Morbid Impalement
    {38, 6, 6, 6, 105, 5},
    //Mid Elve
    {48, 0, -12, 0, 127, 6},
    //Fuzz
    {48, 0, 0, 0, 127, 7}
  };

  for (i32 n = 0; n < PRESET_SIZE; n++)
    changepar(n, presets[npreset][n]);

  cleanup();
}

void StompBox::changepar(i32 npar, i32 value)
{
  switch (npar)
  {
  case 0:
    setvolume(value);
    break;
  case 1:
    Phigh = value;
    if (value < 0)
      highb = ((f32)value) / 64.0f;
    if (value > 0)
      highb = ((f32)value) / 32.0f;
    break;
  case 2:
    Pmid = value;
    if (value < 0)
      midb = ((f32)value) / 64.0f;
    if (value > 0)
      midb = ((f32)value) / 32.0f;
    break;
  case 3:
    Plow = value;
    if (value < 0)
      lowb = ((f32)value) / 64.0f;
    if (value > 0)
      lowb = ((f32)value) / 32.0f;
    break;
  case 4:
    Pgain = value;
    gain = dB2rap(50.0f * ((f32)value) / 127.0f - 50.0f);
    break;
  case 5:
    Pmode = value;
    init_mode(Pmode);
    break;
  default:
    unreachable();
  }
  init_tone();
}

i32 StompBox::getpar(i32 npar)
{
  switch (npar)
  {
  case 0:
    return Pvolume;
  case 1:
    return Phigh;
  case 2:
    return Pmid;
  case 3:
    return Plow;
  case 4:
    return Pgain;
  case 5:
    return Pmode;
  }
  ASSERT(false);
  return 0;
}

#endif // SHR3D_SFX_CORE_RAKARRACK_LIBSAMPLERATE

#endif // SHR3D_SFX_CORE_RAKARRACK
