
/*
  rakarrack - a guitar effects software

 Expander.C  -  Noise Gate Effect

  Copyright (C) 2010 Ryan Billing & Josep Andreu
  Author: Ryan Billing & Josep Andreu
  Adapted from swh-plugins Noise Gate by Steve Harris

 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
 (version2)  along with this program; if not, write to the Free Software
 Foundation,
 Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

*/

#include "Expander.h"

#ifdef SHR3D_SFX_CORE_RAKARRACK

Expander::Expander()
  : lpfl(2, 22000, 1, 0)
  , lpfr(2, 22000, 1, 0)
  , hpfl(3, 20, 1, 0)
  , hpfr(3, 20, 1, 0)
{
  fs = fSAMPLE_RATE;

  setpreset(0);
}

void Expander::cleanup()
{
  lpfl.cleanup();
  hpfl.cleanup();
  lpfr.cleanup();
  hpfr.cleanup();
  oldgain = 0.0f;
}

void Expander::setlpf(i32 value)
{
  Plpf = value;
  f32 fr = (f32)Plpf;
  lpfl.setfreq(fr);
  lpfr.setfreq(fr);
}

void Expander::sethpf(i32 value)
{
  Phpf = value;
  f32 fr = (f32)Phpf;
  hpfl.setfreq(fr);
  hpfr.setfreq(fr);
}

void Expander::changepar(i32 np, i32 value)
{
  switch (np)
  {
  case 0:
    Pthreshold = value;
    tfactor = dB2rap(-((f32)Pthreshold));
    tlevel = 1.0f / tfactor;
    return;
  case 1:
    Pshape = value;
    sfactor = dB2rap((f32)Pshape / 2);
    sgain = expf(-sfactor);
    return;
  case 2:
    Pattack = value;
    a_rate = 1000.0f / ((f32)Pattack * fs);
    return;
  case 3:
    Pdecay = value;
    d_rate = 1000.0f / ((f32)Pdecay * fs);
    return;
  case 4:
    setlpf(value);
    return;
  case 5:
    sethpf(value);
    return;
  case 6:
    Plevel = value;
    level = dB2rap((f32)value / 6.0f);
    return;
  }
  ASSERT(false);
}

i32 Expander::getpar(i32 np)
{
  switch (np)
  {
  case 0:
    return Pthreshold;
  case 1:
    return Pshape;
  case 2:
    return Pattack;
  case 3:
    return Pdecay;
  case 4:
    return Plpf;
  case 5:
    return Phpf;
  case 6:
    return Plevel;
  }
  ASSERT(false);
  return 0;
}

void Expander::setpreset(i32 npreset)
{
  const i32 PRESET_SIZE = 7;
  i32 presets[][PRESET_SIZE] = {

    //Noise Gate
    {-50, 20, 50, 50, 3134, 76, 0},
    //Boost Gate
    {-55, 30, 50, 50, 1441, 157, 50},
    //Treble swell
    {-30, 9, 950, 25, 6703, 526, 90}
  };

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

void Expander::processBlock(f32** inOutBlock, const i32 blockSize)
{
  lpfl.filterout(inOutBlock[0], blockSize);
  hpfl.filterout(inOutBlock[0], blockSize);
  lpfr.filterout(inOutBlock[1], blockSize);
  hpfr.filterout(inOutBlock[1], blockSize);

  for (i32 i = 0; i < blockSize; i++)
  {
    const f32 delta = 0.5f * (fabsf(inOutBlock[0][i]) + fabsf(inOutBlock[1][i])) - env;    //envelope follower from Compressor.C
    if (delta > 0.0)
      env += a_rate * delta;
    else
      env += d_rate * delta;

    //End envelope power detection

    if (env > tlevel)
      env = tlevel;

    const f32 expenv = sgain * (expf(env * sfactor * tfactor) - 1.0f); //Envelope waveshaping

    gain = (1.0f - d_rate) * oldgain + d_rate * expenv;
    oldgain = gain;				//smooth it out a little bit

    if (efollower)
    {
      inOutBlock[0][i] = gain;
      inOutBlock[1][i] += gain;
    }
    else
    {
      inOutBlock[0][i] *= gain * level;
      inOutBlock[1][i] *= gain * level;
    }
  }
}

#endif // SHR3D_SFX_CORE_RAKARRACK
