/***************************************************/
/*! \class PluckTwo
    \brief STK enhanced plucked string model class.

    This class implements an enhanced two-string,
    plucked physical model, a la Jaffe-Smith,
    Smith, and others.

    PluckTwo is an abstract class, with no excitation
    specified.  Therefore, it can't be directly
    instantiated.

    This is a digital waveguide model, making its
    use possibly subject to patents held by
    Stanford University, Yamaha, and others.

    by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
*/
/***************************************************/

#include "PluckTwo.h"

PluckTwo :: PluckTwo(StkFloat lowestFrequency)
{
  length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1);
  lastLength_ = length_ * 0.5;
  delayLine_.setMaximumDelay( length_ );
  delayLine_.setDelay( lastLength_ );
  delayLine2_.setMaximumDelay( length_ );
  delayLine2_.setDelay( lastLength_ );
  combDelay_.setMaximumDelay( length_ );
  combDelay_.setDelay( lastLength_ );

  baseLoopGain_ = 0.995;
  loopGain_ = 0.999;
  pluckAmplitude_ = 0.3;
  pluckPosition_ = 0.4;
  detuning_ = 0.995;
  lastFrequency_ = lowestFrequency * 2.0;

}

PluckTwo :: ~PluckTwo()
{
}

void PluckTwo :: clear()
{
  delayLine_.clear();
  delayLine2_.clear();
  combDelay_.clear();
  filter_.clear();
  filter2_.clear();
}

void PluckTwo :: setFrequency(StkFloat frequency)
{
  lastFrequency_ = frequency;
  if ( lastFrequency_ <= 0.0 ) {
    errorString_ << "Clarinet::setFrequency: parameter is less than or equal to zero!";
    handleError( StkError::WARNING );
    lastFrequency_ = 220.0;
  }

  // Delay = length - approximate filter delay.
  lastLength_ = Stk::sampleRate() / lastFrequency_;
  StkFloat delay = (lastLength_ / detuning_) - 0.5;
  if ( delay <= 0.0 ) delay = 0.3;
  else if ( delay > length_ ) delay = length_;
  delayLine_.setDelay( delay );

  delay = (lastLength_ * detuning_) - 0.5;
  if ( delay <= 0.0 ) delay = 0.3;
  else if ( delay > length_ ) delay = length_;
  delayLine2_.setDelay( delay );

  loopGain_ = baseLoopGain_ + (frequency * 0.000005);
  if ( loopGain_ > 1.0 ) loopGain_ = 0.99999;
}

void PluckTwo :: setDetune(StkFloat detune)
{
  detuning_ = detune;
  if ( detuning_ <= 0.0 ) {
    errorString_ << "Clarinet::setDeturn: parameter is less than or equal to zero!";
    handleError( StkError::WARNING );
    detuning_ = 0.1;
  }
  delayLine_.setDelay(( lastLength_ / detuning_) - 0.5);
  delayLine2_.setDelay( (lastLength_ * detuning_) - 0.5);
}

void PluckTwo :: setFreqAndDetune(StkFloat frequency, StkFloat detune)
{
  detuning_ = detune;
  this->setFrequency( frequency );
}

void PluckTwo :: setPluckPosition(StkFloat position)
{
  pluckPosition_ = position;
  if ( position < 0.0 ) {
    errorString_ << "PluckTwo::setPluckPosition: parameter is less than zero ... setting to 0.0!";
    handleError( StkError::WARNING );
    pluckPosition_ = 0.0;
  }
  else if ( position > 1.0 ) {
    errorString_ << "PluckTwo::setPluckPosition: parameter is greater than one ... setting to 1.0!";
    handleError( StkError::WARNING );
    pluckPosition_ = 1.0;
  }
}

void PluckTwo :: setBaseLoopGain(StkFloat aGain)
{
  baseLoopGain_ = aGain;
  loopGain_ = baseLoopGain_ + (lastFrequency_ * 0.000005);
  if ( loopGain_ > 0.99999 ) loopGain_ = 0.99999;
}

void PluckTwo :: noteOff(StkFloat amplitude)
{
  loopGain_ =  (1.0 - amplitude) * 0.5;

#if defined(_STK_DEBUG_)
  errorString_ << "PluckTwo::NoteOff: amplitude = " << amplitude << ".";
  handleError( StkError::DEBUG_WARNING );
#endif
}

