f@0: #ifndef STK_ENVELOPE_H f@0: #define STK_ENVELOPE_H f@0: f@0: #include "Generator.h" f@0: f@0: namespace stk { f@0: f@0: /***************************************************/ f@0: /*! \class Envelope f@0: \brief STK linear line envelope class. f@0: f@0: This class implements a simple linear line envelope generator f@0: which is capable of ramping to an arbitrary target value by a f@0: specified \e rate. It also responds to simple \e keyOn and \e f@0: keyOff messages, ramping to 1.0 on keyOn and to 0.0 on keyOff. f@0: f@0: by Perry R. Cook and Gary P. Scavone, 1995--2014. f@0: */ f@0: /***************************************************/ f@0: f@0: class Envelope : public Generator f@0: { f@0: public: f@0: f@0: //! Default constructor. f@0: Envelope( void ); f@0: f@0: //! Class destructor. f@0: ~Envelope( void ); f@0: f@0: //! Assignment operator. f@0: Envelope& operator= ( const Envelope& e ); f@0: f@0: //! Set target = 1. f@0: void keyOn( void ) { this->setTarget( 1.0 ); }; f@0: f@0: //! Set target = 0. f@0: void keyOff( void ) { this->setTarget( 0.0 ); }; f@0: f@0: //! Set the \e rate. f@0: /*! f@0: The \e rate must be positive (though a value of 0.0 is allowed). f@0: */ f@0: void setRate( StkFloat rate ); f@0: f@0: //! Set the \e rate based on a positive time duration (seconds). f@0: /*! f@0: The \e rate is calculated such that the envelope will ramp from f@0: a value of 0.0 to 1.0 in the specified time duration. f@0: */ f@0: void setTime( StkFloat time ); f@0: f@0: //! Set the target value. f@0: void setTarget( StkFloat target ); f@0: f@0: //! Set current and target values to \e value. f@0: void setValue( StkFloat value ); f@0: f@0: //! Return the current envelope \e state (0 = at target, 1 otherwise). f@0: int getState( void ) const { return state_; }; f@0: f@0: //! Return the last computed output value. f@0: StkFloat lastOut( void ) const { return lastFrame_[0]; }; f@0: f@0: //! Compute and return one output sample. f@0: StkFloat tick( void ); f@0: f@0: //! Fill a channel of the StkFrames object with computed outputs. f@0: /*! f@0: The \c channel argument must be less than the number of f@0: channels in the StkFrames argument (the first channel is specified f@0: by 0). However, range checking is only performed if _STK_DEBUG_ f@0: is defined during compilation, in which case an out-of-range value f@0: will trigger an StkError exception. f@0: */ f@0: StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); f@0: f@0: protected: f@0: f@0: void sampleRateChanged( StkFloat newRate, StkFloat oldRate ); f@0: f@0: StkFloat value_; f@0: StkFloat target_; f@0: StkFloat rate_; f@0: int state_; f@0: }; f@0: f@0: inline StkFloat Envelope :: tick( void ) f@0: { f@0: if ( state_ ) { f@0: if ( target_ > value_ ) { f@0: value_ += rate_; f@0: if ( value_ >= target_ ) { f@0: value_ = target_; f@0: state_ = 0; f@0: } f@0: } f@0: else { f@0: value_ -= rate_; f@0: if ( value_ <= target_ ) { f@0: value_ = target_; f@0: state_ = 0; f@0: } f@0: } f@0: lastFrame_[0] = value_; f@0: } f@0: f@0: return value_; f@0: } f@0: f@0: inline StkFrames& Envelope :: tick( StkFrames& frames, unsigned int channel ) f@0: { f@0: #if defined(_STK_DEBUG_) f@0: if ( channel >= frames.channels() ) { f@0: oStream_ << "Envelope::tick(): channel and StkFrames arguments are incompatible!"; f@0: handleError( StkError::FUNCTION_ARGUMENT ); f@0: } f@0: #endif f@0: f@0: StkFloat *samples = &frames[channel]; f@0: unsigned int hop = frames.channels(); f@0: for ( unsigned int i=0; i