/***************************************************/ /*! \class Guitar \brief STK guitar model class. This class implements a guitar model with an arbitrary number of strings (specified during instantiation). Each string is represented by an stk::Twang object. The model supports commuted synthesis, as discussed by Smith and Karjalainen. It also includes a basic body coupling model and supports feedback. This class does not attempt voice management. Rather, most functions support a parameter to specify a particular string number and string (voice) management is assumed to occur externally. Note that this class does not inherit from stk::Instrmnt because of API inconsistencies. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. Control Change Numbers: - Bridge Coupling Gain = 2 - Pluck Position = 4 - Loop Gain = 11 - Coupling Filter Pole = 1 - Pick Filter Pole = 128 by Gary P. Scavone, 2012. */ /***************************************************/ #include "Guitar.h" #include "FileWvIn.h" #include "Noise.h" #include "SKINImsg.h" #include namespace stk { #define BASE_COUPLING_GAIN 0.01 Guitar :: Guitar( unsigned int nStrings, std::string bodyfile ) { strings_.resize( nStrings ); stringState_.resize( nStrings, 0 ); decayCounter_.resize( nStrings, 0 ); filePointer_.resize( nStrings, 0 ); pluckGains_.resize( nStrings, 0 ); setBodyFile( bodyfile ); couplingGain_ = BASE_COUPLING_GAIN; couplingFilter_.setPole( 0.9 ); pickFilter_.setPole( 0.95 ); lastFrame_.resize(1, 1, 0.0); } void Guitar :: clear( void ) { for ( unsigned int i=0; i 1.0 ) { std::cerr << "Guitar::setPluckPosition: position parameter out of range!"; handleError( StkError::WARNING ); return; } if ( string >= (int) strings_.size() ) { oStream_ << "Guitar::setPluckPosition: string parameter is greater than number of strings!"; handleError( StkError::WARNING ); return; } if ( string < 0 ) // set all strings for ( unsigned int i=0; i 1.0 ) { std::cerr << "Guitar::setLoopGain: gain parameter out of range!"; handleError( StkError::WARNING ); return; } if ( string >= (int) strings_.size() ) { oStream_ << "Guitar::setLoopGain: string parameter is greater than number of strings!"; handleError( StkError::WARNING ); return; } if ( string < 0 ) // set all strings for ( unsigned int i=0; i= strings_.size() ) { oStream_ << "Guitar::setFrequency: string parameter is greater than number of strings!"; handleError( StkError::WARNING ); return; } #endif strings_[string].setFrequency( frequency ); } void Guitar :: noteOn( StkFloat frequency, StkFloat amplitude, unsigned int string ) { #if defined(_STK_DEBUG_) if ( string >= strings_.size() ) { oStream_ << "Guitar::noteOn: string parameter is greater than number of strings!"; handleError( StkError::WARNING ); return; } if ( Stk::inRange( amplitude, 0.0, 1.0 ) == false ) { oStream_ << "Guitar::noteOn: amplitude parameter is outside range 0.0 - 1.0!"; handleError( StkError::WARNING ); return; } #endif this->setFrequency( frequency, string ); stringState_[string] = 2; filePointer_[string] = 0; strings_[string].setLoopGain( 0.995 ); pluckGains_[string] = amplitude; } void Guitar :: noteOff( StkFloat amplitude, unsigned int string ) { #if defined(_STK_DEBUG_) if ( string >= strings_.size() ) { oStream_ << "Guitar::noteOff: string parameter is greater than number of strings!"; handleError( StkError::WARNING ); return; } if ( Stk::inRange( amplitude, 0.0, 1.0 ) == false ) { oStream_ << "Guitar::noteOff: amplitude parameter is outside range 0.0 - 1.0!"; handleError( StkError::WARNING ); return; } #endif strings_[string].setLoopGain( (1.0 - amplitude) * 0.9 ); stringState_[string] = 1; } void Guitar :: controlChange( int number, StkFloat value, int string ) { #if defined(_STK_DEBUG_) if ( Stk::inRange( value, 0.0, 128.0 ) == false ) { oStream_ << "Guitar::controlChange: value (" << value << ") is out of range!"; handleError( StkError::WARNING ); return; } if ( string > 0 && string >= (int) strings_.size() ) { oStream_ << "Guitar::controlChange: string parameter is greater than number of strings!"; handleError( StkError::WARNING ); return; } #endif StkFloat normalizedValue = value * ONE_OVER_128; if ( number == 2 ) couplingGain_ = 1.5 * BASE_COUPLING_GAIN * normalizedValue; else if ( number == __SK_PickPosition_ ) // 4 this->setPluckPosition( normalizedValue, string ); else if ( number == __SK_StringDamping_ ) // 11 this->setLoopGain( 0.97 + (normalizedValue * 0.03), string ); else if ( number == __SK_ModWheel_ ) // 1 couplingFilter_.setPole( 0.98 * normalizedValue ); else if (number == __SK_AfterTouch_Cont_) // 128 pickFilter_.setPole( 0.95 * normalizedValue ); #if defined(_STK_DEBUG_) else { oStream_ << "Guitar::controlChange: undefined control number (" << number << ")!"; handleError( StkError::WARNING ); } #endif } } // stk namespace