/*
  Rakarrack   Audio FX software
  CoilCrafter.C - Harmonic Enhancer
  Based in Steve Harris LADSPA Plugin harmonic_gen
  Modified for rakarrack by Ryan Billing and Josep Andreu


  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 "CoilCrafter.h"

#ifdef SHR3D_SFX_CORE_RAKARRACK

CoilCrafter::CoilCrafter()
  : RB1l(2, 2000.0f, 1.0f, 0)
  , RB1r(2, 2000.0f, 1.0f, 0)
  , RB2l(2, 2000.0f, 1.0f, 0)
  , RB2r(2, 2000.0f, 1.0f, 0)
{
  //default values
  att = 16.0f * powf(PI_, fSAMPLE_RATE / 44100.0f);

  tfreqs[0] = 4000.0f;
  tfreqs[1] = 4400.0f;
  tfreqs[2] = 4200.0f;
  tfreqs[3] = 2900.0f;
  tfreqs[4] = 3000.0f;
  tfreqs[5] = 2700.0f;
  tfreqs[6] = 3300.0f;
  tfreqs[7] = 3300.0f;
  tfreqs[8] = 2800.0f;

  tqs[0] = 4.2f;
  tqs[1] = 4.2f;
  tqs[2] = 2.3f;
  tqs[3] = 1.8f;
  tqs[4] = 2.2f;
  tqs[5] = 2.1f;
  tqs[6] = 1.7f;
  tqs[7] = 1.7f;
  tqs[8] = 1.8f;

  for (i32 i = 0; i < 10; i++)
  {
    rm[i] = 0.0f;
  }
  rm[0] = 1.0; rm[2] = -1.0; rm[4] = 1.0; rm[6] = -1.0; rm[8] = 1.0;

  harm = new HarmEnhancer(rm, 2500.0f, 4400.0f, 1.0f);

  cleanup();

  setpreset(0);
}

/*
 * Cleanup the effect
 */
void CoilCrafter::cleanup()
{
  harm->cleanup();
  harm->calcula_mag(rm);
  harm->set_vol(1, 1.0f);

  RB1l.cleanup();
  RB1r.cleanup();
  RB2l.cleanup();
  RB2r.cleanup();
}


/*
 * Effect output
 */
void CoilCrafter::processBlock(f32** inOutBlock, const i32 blockSize)
{
  if (Ppo > 0)
  {
    RB1l.filterout(inOutBlock[0], blockSize);
    RB1r.filterout(inOutBlock[1], blockSize);

    for (i32 i = 0; i < blockSize; i++)
    {
      inOutBlock[0][i] *= att;
      inOutBlock[1][i] *= att;
    }

  }
  if (Ppd > 0)
  {
    RB2l.filterout(inOutBlock[0], blockSize);
    RB2r.filterout(inOutBlock[1], blockSize);
  }

  if (Pmode)
    harm->harm_out(inOutBlock, blockSize);

  for (i32 i = 0; i < blockSize; i++)
  {
    inOutBlock[0][i] *= outvolume;
    inOutBlock[1][i] *= outvolume;

    if (Pmode)
    {
      inOutBlock[0][i] *= .5f;
      inOutBlock[1][i] *= .5f;
    }
  }
}


/*
 * Parameter control
 */
void CoilCrafter::setvolume(i32 value)
{
  Pvolume = value;
  outvolume = (1.0f + (f32)Pvolume) / 127.0f;

};

void CoilCrafter::setfreq1()
{
  RB1l.setfreq(freq1);
  RB1l.reversecoeffs();
  RB1r.setfreq(freq1);
  RB1r.reversecoeffs();
}

void CoilCrafter::setq1()
{
  RB1l.setq(q1);
  RB1l.reversecoeffs();
  RB1r.setq(q1);
  RB1r.reversecoeffs();
}

void CoilCrafter::setfreq2()
{

  RB2l.setfreq(freq2);
  RB2r.setfreq(freq2);
}

void CoilCrafter::setq2()
{
  RB2l.setq(q2);
  RB2r.setq(q2);
}

void CoilCrafter::sethpf(i32 value)
{
  harm->set_freqh(0, f32(value));
}

void CoilCrafter::setpreset(i32 npreset)
{
  const i32 PRESET_SIZE = 9;
  i32 presets[][PRESET_SIZE] = {
    //H to S
    {32, 6, 1, 3300, 16,  4400, 42, 20, 0},
    //S to H
    {32, 1, 6, 4400, 42, 3300, 16, 20, 0}
  };

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

  cleanup();
}

void CoilCrafter::changepar(i32 npar, i32 value)
{
  switch (npar)
  {
  case 0:
    setvolume(value);
    return;
  case 1:
    Ppo = value;
    if (Ppo > 0)
    {
      freq1 = tfreqs[value];
      Pfreq1 = (i32)freq1;
      setfreq1();
      q1 = tqs[value];
      Pq1 = (i32)(q1 * 10.0f);
      setq1();
    }
    return;
  case 2:
    Ppd = value;
    if (Ppd > 0)
    {
      freq2 = tfreqs[value];
      Pfreq2 = (i32)freq2;
      setfreq2();
      q2 = tqs[value];
      Pq2 = (i32)(q2 * 10.0f);
      setq2();
    }
    return;
  case 3:
    Pfreq1 = value;
    freq1 = (f32)value;
    setfreq1();
    return;
  case 4:
    Pq1 = value;
    q1 = (f32)value / 10.0f;
    setq1();
    return;
  case 5:
    Pfreq2 = value;
    freq2 = (f32)value;
    setfreq2();
    return;
  case 6:
    Pq2 = value;
    q2 = (f32)value / 10.0f;
    setq2();
    return;
  case 7:
    Ptone = value;
    sethpf(value);
    return;
  case 8:
    Pmode = value;
    return;
  }
  ASSERT(false);
}

i32 CoilCrafter::getpar(i32 npar)
{
  switch (npar)
  {
  case 0:
    return Pvolume;
  case 1:
    return Ppo;
  case 2:
    return Ppd;
  case 3:
    return Pfreq1;
  case 4:
    return Pq1;
  case 5:
    return Pfreq2;
  case 6:
    return Pq2;
  case 7:
    return Ptone;
  case 8:
    return Pmode;
  }
  ASSERT(false);
  return 0;
}

#endif // SHR3D_SFX_CORE_RAKARRACK
