// Based in gate_1410.c LADSPA Swh-plugins


/*
  rakarrack - a guitar effects software

 Gate.C  -  Noise Gate Effect
 Based on Steve Harris LADSPA gate.

  Copyright (C) 2008 Josep Andreu
  Author: 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
 (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 "NoiseGate_.h"

#ifdef SHR3D_SFX_CORE_RAKARRACK

#define CLOSED 1
#define OPENING 2
#define OPEN 3
#define CLOSING 4

NoiseGate::NoiseGate()
  : lpfl(2, 22000, 1, 0)
  , lpfr(2, 22000, 1, 0)
  , hpfl(3, 20, 1, 0)
  , hpfr(3, 20, 1, 0)
{
  fs = fSAMPLE_RATE;
  state = CLOSED;
  hold_count = 0;

  setpreset(0);
}

void NoiseGate::cleanup()
{
  lpfl.cleanup();
  hpfl.cleanup();
  lpfr.cleanup();
  hpfr.cleanup();
}

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

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

void NoiseGate::changepar(i32 np, i32 value)
{
  switch (np)
  {
  case 1:
    Pthreshold = value;
    t_level = dB2rap((f32)Pthreshold);
    return;
  case 2:
    Prange = value;
    cut = dB2rap((f32)Prange);
    return;
  case 3:
    Pattack = value;
    a_rate = 1000.0f / ((f32)Pattack * fs);
    return;
  case 4:
    Pdecay = value;
    d_rate = 1000.0f / ((f32)Pdecay * fs);
    return;
  case 5:
    setlpf(value);
    return;
  case 6:
    sethpf(value);
    return;
  case 7:
    Phold = value;
    hold = (f32)Phold;
    return;
  }
  ASSERT(false);
}

i32 NoiseGate::getpar(i32 np)
{
  switch (np)
  {
  case 1:
    return Pthreshold;
  case 2:
    return Prange;
  case 3:
    return Pattack;
  case 4:
    return Pdecay;
  case 5:
    return Plpf;
  case 6:
    return Phpf;
  case 7:
    return Phold;
  }
  ASSERT(false);
  return (0);
}

void NoiseGate::setpreset(i32 npreset)
{
  const i32 PRESET_SIZE = 7;
  i32 presets[][PRESET_SIZE] = {
    //0
    {0, 0, 1, 2, 6703, 76, 2},
    //-10
    {0, -10, 1, 2, 6703, 76, 2},
    //-20
    {0, -20, 1, 2, 6703, 76, 2}
  };

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

void NoiseGate::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 sum = fabsf(inOutBlock[0][i]) + fabsf(inOutBlock[1][i]);

    if (sum > env)
      env = sum;
    else
      env = sum * ENV_TR + env * (1.0f - ENV_TR);

    if (state == CLOSED)
    {
      if (env >= t_level)
        state = OPENING;
    }
    else if (state == OPENING)
    {
      gate += a_rate;
      if (gate >= 1.0)
      {
        gate = 1.0f;
        state = OPEN;
        hold_count = lrintf(hold * fs * 0.001f);
      }
    }
    else if (state == OPEN)
    {
      if (hold_count <= 0)
      {
        if (env < t_level)
          state = CLOSING;
      }
      else
      {
        hold_count--;
      }
    }
    else if (state == CLOSING)
    {
      gate -= d_rate;
      if (env >= t_level)
      {
        state = OPENING;
      }
      else if (gate <= 0.0)
      {
        gate = 0.0;
        state = CLOSED;
      }
    }

    inOutBlock[0][i] *= (cut * (1.0f - gate) + gate);
    inOutBlock[1][i] *= (cut * (1.0f - gate) + gate);
  }
}

#endif // SHR3D_SFX_CORE_RAKARRACK
