|
- /***************************************************/
- /*! \class BandedWG
- \brief Banded waveguide modeling class.
-
- This class uses banded waveguide techniques to
- model a variety of sounds, including bowed
- bars, glasses, and bowls. For more
- information, see Essl, G. and Cook, P. "Banded
- Waveguides: Towards Physical Modelling of Bar
- Percussion Instruments", Proceedings of the
- 1999 International Computer Music Conference.
-
- Control Change Numbers:
- - Bow Pressure = 2
- - Bow Motion = 4
- - Strike Position = 8 (not implemented)
- - Vibrato Frequency = 11
- - Gain = 1
- - Bow Velocity = 128
- - Set Striking = 64
- - Instrument Presets = 16
- - Uniform Bar = 0
- - Tuned Bar = 1
- - Glass Harmonica = 2
- - Tibetan Bowl = 3
-
- by Georg Essl, 1999 - 2004.
- Modified for STK 4.0 by Gary Scavone.
- */
- /***************************************************/
-
- #include "BandedWG.h"
- #include "SKINImsg.h"
- #include <cmath>
-
- namespace stk {
-
- BandedWG :: BandedWG( void )
- {
- doPluck_ = true;
-
- bowTable_.setSlope( 3.0 );
- adsr_.setAllTimes( 0.02, 0.005, 0.9, 0.01 );
-
- frequency_ = 220.0;
- this->setPreset(0);
-
- bowPosition_ = 0;
- baseGain_ = 0.999;
-
- integrationConstant_ = 0.0;
- trackVelocity_ = false;
-
- bowVelocity_ = 0.0;
- bowTarget_ = 0.0;
-
- strikeAmp_ = 0.0;
- }
-
- BandedWG :: ~BandedWG( void )
- {
- }
-
- void BandedWG :: clear( void )
- {
- for ( int i=0; i<nModes_; i++ ) {
- delay_[i].clear();
- bandpass_[i].clear();
- }
- }
-
- void BandedWG :: setPreset( int preset )
- {
- int i;
- switch ( preset ) {
-
- case 1: // Tuned Bar
- presetModes_ = 4;
- modes_[0] = (StkFloat) 1.0;
- modes_[1] = (StkFloat) 4.0198391420;
- modes_[2] = (StkFloat) 10.7184986595;
- modes_[3] = (StkFloat) 18.0697050938;
-
- for (i=0; i<presetModes_; i++) {
- basegains_[i] = (StkFloat) pow(0.999,(double) i+1);
- excitation_[i] = 1.0;
- }
-
- break;
-
- case 2: // Glass Harmonica
- presetModes_ = 5;
- modes_[0] = (StkFloat) 1.0;
- modes_[1] = (StkFloat) 2.32;
- modes_[2] = (StkFloat) 4.25;
- modes_[3] = (StkFloat) 6.63;
- modes_[4] = (StkFloat) 9.38;
- // modes_[5] = (StkFloat) 12.22;
-
- for (i=0; i<presetModes_; i++) {
- basegains_[i] = (StkFloat) pow(0.999,(double) i+1);
- excitation_[i] = 1.0;
- }
- /*
- baseGain_ = (StkFloat) 0.99999;
- for (i=0; i<presetModes_; i++)
- gains_[i]= (StkFloat) pow(baseGain_, delay_[i].getDelay()+i);
- */
-
- break;
-
- case 3: // Tibetan Prayer Bowl (ICMC'02)
- presetModes_ = 12;
- modes_[0]=0.996108344;
- basegains_[0]=0.999925960128219;
- excitation_[0]=11.900357/10.0;
- modes_[1]=1.0038916562;
- basegains_[1]=0.999925960128219;
- excitation_[1]=11.900357/10.;
- modes_[2]=2.979178;
- basegains_[2]=0.999982774366897;
- excitation_[2]=10.914886/10.;
- modes_[3]=2.99329767;
- basegains_[3]=0.999982774366897;
- excitation_[3]=10.914886/10.;
- modes_[4]=5.704452;
- basegains_[4]=1.0; //0.999999999999999999987356406352;
- excitation_[4]=42.995041/10.;
- modes_[5]=5.704452;
- basegains_[5]=1.0; //0.999999999999999999987356406352;
- excitation_[5]=42.995041/10.;
- modes_[6]=8.9982;
- basegains_[6]=1.0; //0.999999999999999999996995497558225;
- excitation_[6]=40.063034/10.;
- modes_[7]=9.01549726;
- basegains_[7]=1.0; //0.999999999999999999996995497558225;
- excitation_[7]=40.063034/10.;
- modes_[8]=12.83303;
- basegains_[8]=0.999965497558225;
- excitation_[8]=7.063034/10.;
- modes_[9]=12.807382;
- basegains_[9]=0.999965497558225;
- excitation_[9]=7.063034/10.;
- modes_[10]=17.2808219;
- basegains_[10]=0.9999999999999999999965497558225;
- excitation_[10]=57.063034/10.;
- modes_[11]=21.97602739726;
- basegains_[11]=0.999999999999999965497558225;
- excitation_[11]=57.063034/10.;
-
- break;
-
- default: // Uniform Bar
- presetModes_ = 4;
- modes_[0] = (StkFloat) 1.0;
- modes_[1] = (StkFloat) 2.756;
- modes_[2] = (StkFloat) 5.404;
- modes_[3] = (StkFloat) 8.933;
-
- for (i=0; i<presetModes_; i++) {
- basegains_[i] = (StkFloat) pow(0.9,(double) i+1);
- excitation_[i] = 1.0;
- }
-
- break;
- }
-
- nModes_ = presetModes_;
- setFrequency( frequency_ );
- }
-
- void BandedWG :: setFrequency( StkFloat frequency )
- {
- #if defined(_STK_DEBUG_)
- if ( frequency <= 0.0 ) {
- oStream_ << "BandedWG::setFrequency: parameter is less than or equal to zero!";
- handleError( StkError::WARNING ); return;
- }
- #endif
-
- if (frequency > 1568.0) frequency = 1568.0;
-
- StkFloat radius;
- StkFloat base = Stk::sampleRate() / frequency;
- StkFloat length;
- for (int i=0; i<presetModes_; i++) {
- // Calculate the delay line lengths for each mode.
- length = (int)(base / modes_[i]);
- if ( length > 2.0) {
- delay_[i].setDelay( length );
- gains_[i]=basegains_[i];
- // gains_[i]=(StkFloat) pow(basegains_[i], 1/((StkFloat)delay_[i].getDelay()));
- // std::cerr << gains_[i];
- }
- else {
- nModes_ = i;
- break;
- }
- // std::cerr << std::endl;
-
- // Set the bandpass filter resonances
- radius = 1.0 - PI * 32 / Stk::sampleRate(); //frequency_ * modes_[i] / Stk::sampleRate()/32;
- if ( radius < 0.0 ) radius = 0.0;
- bandpass_[i].setResonance(frequency * modes_[i], radius, true);
-
- delay_[i].clear();
- bandpass_[i].clear();
- }
-
- //int olen = (int)(delay_[0].getDelay());
- //strikePosition_ = (int)(strikePosition_*(length/modes_[0])/olen);
- }
-
- void BandedWG :: setStrikePosition( StkFloat position )
- {
- strikePosition_ = (int)(delay_[0].getDelay() * position / 2.0);
- }
-
- void BandedWG :: startBowing( StkFloat amplitude, StkFloat rate )
- {
- adsr_.setAttackRate(rate);
- adsr_.keyOn();
- maxVelocity_ = 0.03 + (0.1 * amplitude);
- }
-
- void BandedWG :: stopBowing( StkFloat rate )
- {
- adsr_.setReleaseRate(rate);
- adsr_.keyOff();
- }
-
- void BandedWG :: pluck( StkFloat amplitude )
- {
- int j;
- StkFloat min_len = delay_[nModes_-1].getDelay();
- for (int i=0; i<nModes_; i++)
- for(j=0; j<(int)(delay_[i].getDelay()/min_len); j++)
- delay_[i].tick( excitation_[i]*amplitude / nModes_ );
-
- // strikeAmp_ += amplitude;
- }
-
- void BandedWG :: noteOn( StkFloat frequency, StkFloat amplitude )
- {
- this->setFrequency( frequency );
-
- if ( doPluck_ )
- this->pluck( amplitude );
- else
- this->startBowing( amplitude, amplitude * 0.001 );
- }
-
- void BandedWG :: noteOff( StkFloat amplitude )
- {
- if ( !doPluck_ )
- this->stopBowing( (1.0 - amplitude) * 0.005 );
- }
-
- StkFloat BandedWG :: tick( unsigned int )
- {
- int k;
-
- StkFloat input = 0.0;
- if ( doPluck_ ) {
- input = 0.0;
- // input = strikeAmp_/nModes_;
- // strikeAmp_ = 0.0;
- }
- else {
- if ( integrationConstant_ == 0.0 )
- velocityInput_ = 0.0;
- else
- velocityInput_ = integrationConstant_ * velocityInput_;
-
- for ( k=0; k<nModes_; k++ )
- velocityInput_ += baseGain_ * delay_[k].lastOut();
-
- if ( trackVelocity_ ) {
- bowVelocity_ *= 0.9995;
- bowVelocity_ += bowTarget_;
- bowTarget_ *= 0.995;
- }
- else
- bowVelocity_ = adsr_.tick() * maxVelocity_;
-
- input = bowVelocity_ - velocityInput_;
- input = input * bowTable_.tick(input);
- input = input/(StkFloat)nModes_;
- }
-
- StkFloat data = 0.0;
- for ( k=0; k<nModes_; k++ ) {
- bandpass_[k].tick(input + gains_[k] * delay_[k].lastOut());
- delay_[k].tick(bandpass_[k].lastOut());
- data += bandpass_[k].lastOut();
- }
-
- //lastFrame_[0] = data * nModes_;
- lastFrame_[0] = data * 4;
- return lastFrame_[0];
- }
-
- void BandedWG :: controlChange( int number, StkFloat value )
- {
- #if defined(_STK_DEBUG_)
- if ( value < 0 || ( number != 101 && value > 128.0 ) ) {
- oStream_ << "BandedWG::controlChange: value (" << value << ") is out of range!";
- handleError( StkError::WARNING ); return;
- }
- #endif
-
- StkFloat normalizedValue = value * ONE_OVER_128;
- if (number == __SK_BowPressure_) { // 2
- if ( normalizedValue == 0.0 )
- doPluck_ = true;
- else {
- doPluck_ = false;
- bowTable_.setSlope( 10.0 - (9.0 * normalizedValue));
- }
- }
- else if (number == 4) { // 4
- if ( !trackVelocity_ ) trackVelocity_ = true;
- bowTarget_ += 0.005 * (normalizedValue - bowPosition_);
- bowPosition_ = normalizedValue;
- //adsr_.setTarget(bowPosition_);
- }
- else if (number == 8) // 8
- this->setStrikePosition( normalizedValue );
- else if (number == __SK_AfterTouch_Cont_) { // 128
- //bowTarget_ += 0.02 * (normalizedValue - bowPosition_);
- //bowPosition_ = normalizedValue;
- if ( trackVelocity_ ) trackVelocity_ = false;
- maxVelocity_ = 0.13 * normalizedValue;
- adsr_.setTarget(normalizedValue);
- }
- else if (number == __SK_ModWheel_) { // 1
- // baseGain_ = 0.9989999999 + (0.001 * normalizedValue );
- baseGain_ = 0.8999999999999999 + (0.1 * normalizedValue);
- // std::cerr << "Yuck!" << std::endl;
- for (int i=0; i<nModes_; i++)
- gains_[i]=(StkFloat) basegains_[i]*baseGain_;
- // gains_[i]=(StkFloat) pow(baseGain_, (int)((StkFloat)delay_[i].getDelay()+i));
- }
- else if (number == __SK_ModFrequency_) // 11
- integrationConstant_ = normalizedValue;
- else if (number == __SK_Sustain_) { // 64
- if (value < 65) doPluck_ = true;
- else doPluck_ = false;
- }
- else if (number == __SK_Portamento_) { // 65
- if (value < 65) trackVelocity_ = false;
- else trackVelocity_ = true;
- }
- else if (number == __SK_ProphesyRibbon_) // 16
- this->setPreset((int) value);
- #if defined(_STK_DEBUG_)
- else {
- oStream_ << "BandedWG::controlChange: undefined control number (" << number << ")!";
- handleError( StkError::WARNING );
- }
- #endif
- }
-
- } // stk namespace
|