/***************************************************/
/*! \class Brass
    \brief STK simple brass instrument class.

    This class implements a simple brass instrument
    waveguide model, a la Cook (TBone, HosePlayer).

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

    Control Change Numbers: 
       - Lip Tension = 2
       - Slide Length = 4
       - Vibrato Frequency = 11
       - Vibrato Gain = 1
       - Volume = 128

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

#include "Brass.h"
#include "SKINI.msg"
#include <math.h>

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

  lipFilter_.setGain( 0.03 );
  dcBlock_.setBlockZero();

  adsr_.setAllTimes( 0.005, 0.001, 1.0, 0.010);

  // Concatenate the STK rawwave path to the rawwave file
  vibrato_ = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
  vibrato_->setFrequency( 6.137 );
  vibratoGain_ = 0.0;

  this->clear();
	maxPressure_ = 0.0;
  lipTarget_ = 0.0;

  // This is necessary to initialize variables.
  this->setFrequency( 220.0 );
}

Brass :: ~Brass()
{
  delete vibrato_;
}

void Brass :: clear()
{
  delayLine_.clear();
  lipFilter_.clear();
  dcBlock_.clear();
}

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

  // Fudge correction for filter delays.
  slideTarget_ = (Stk::sampleRate() / freakency * 2.0) + 3.0;
  delayLine_.setDelay( slideTarget_ ); // play a harmonic

  lipTarget_ = freakency;
  lipFilter_.setResonance( freakency, 0.997 );
}

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

  lipFilter_.setResonance( freakency, 0.997 );
}

void Brass :: startBlowing(StkFloat amplitude, StkFloat rate)
{
  adsr_.setAttackRate( rate );
  maxPressure_ = amplitude;
  adsr_.keyOn();
}

void Brass :: stopBlowing(StkFloat rate)
{
  adsr_.setReleaseRate( rate );
  adsr_.keyOff();
}

void Brass :: noteOn(StkFloat frequency, StkFloat amplitude)
{
  this->setFrequency( frequency );
  this->startBlowing( amplitude, amplitude * 0.001 );

#if defined(_STK_DEBUG_)
  errorString_ << "Brass::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
  handleError( StkError::DEBUG_WARNING );
#endif
}

void Brass :: noteOff(StkFloat amplitude)
{
  this->stopBlowing( amplitude * 0.005 );

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

StkFloat Brass :: tick()
{
  StkFloat breathPressure = maxPressure_ * adsr_.tick();
  breathPressure += vibratoGain_ * vibrato_->tick();

  StkFloat mouthPressure = 0.3 * breathPressure;
  StkFloat borePressure = 0.85 * delayLine_.lastOut();
  StkFloat deltaPressure = mouthPressure - borePressure; // Differential pressure.
  deltaPressure = lipFilter_.tick( deltaPressure );      // Force - > position.
  deltaPressure *= deltaPressure;                        // Basic position to area mapping.
  if ( deltaPressure > 1.0 ) deltaPressure = 1.0;        // Non-linear saturation.

  // The following input scattering assumes the mouthPressure = area.
  lastOutput_ = deltaPressure * mouthPressure + ( 1.0 - deltaPressure) * borePressure;
  lastOutput_ = delayLine_.tick( dcBlock_.tick( lastOutput_ ) );

  return lastOutput_;
}

StkFloat *Brass :: tick(StkFloat *vector, unsigned int vectorSize)
{
  return Instrmnt::tick( vector, vectorSize );
}

StkFrames& Brass :: tick( StkFrames& frames, unsigned int channel )
{
  return Instrmnt::tick( frames, channel );
}

void Brass :: controlChange(int number, StkFloat value)
{
  StkFloat norm = value * ONE_OVER_128;
  if ( norm < 0 ) {
    norm = 0.0;
    errorString_ << "Brass::controlChange: control value less than zero ... setting to zero!";
    handleError( StkError::WARNING );
  }
  else if ( norm > 1.0 ) {
    norm = 1.0;
    errorString_ << "Brass::controlChange: control value greater than 128.0 ... setting to 128.0!";
    handleError( StkError::WARNING );
  }

  if (number == __SK_LipTension_)	{ // 2
    StkFloat temp = lipTarget_ * pow( 4.0, (2.0 * norm) - 1.0 );
    this->setLip(temp);
  }
  else if (number == __SK_SlideLength_) // 4
    delayLine_.setDelay( slideTarget_ * (0.5 + norm) );
  else if (number == __SK_ModFrequency_) // 11
    vibrato_->setFrequency( norm * 12.0 );
  else if (number == __SK_ModWheel_ ) // 1
    vibratoGain_ = norm * 0.4;
  else if (number == __SK_AfterTouch_Cont_) // 128
    adsr_.setTarget( norm );
  else {
    errorString_ << "Brass::controlChange: undefined control number (" << number << ")!";
    handleError( StkError::WARNING );
  }

#if defined(_STK_DEBUG_)
    errorString_ << "Brass::controlChange: number = " << number << ", value = " << value << ".";
    handleError( StkError::DEBUG_WARNING );
#endif
}
