You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
5.1KB

  1. /***************************************************/
  2. /*! \class Saxofony
  3. \brief STK faux conical bore reed instrument class.
  4. This class implements a "hybrid" digital
  5. waveguide instrument that can generate a
  6. variety of wind-like sounds. It has also been
  7. referred to as the "blowed string" model. The
  8. waveguide section is essentially that of a
  9. string, with one rigid and one lossy
  10. termination. The non-linear function is a
  11. reed table. The string can be "blown" at any
  12. point between the terminations, though just as
  13. with strings, it is impossible to excite the
  14. system at either end. If the excitation is
  15. placed at the string mid-point, the sound is
  16. that of a clarinet. At points closer to the
  17. "bridge", the sound is closer to that of a
  18. saxophone. See Scavone (2002) for more details.
  19. This is a digital waveguide model, making its
  20. use possibly subject to patents held by Stanford
  21. University, Yamaha, and others.
  22. Control Change Numbers:
  23. - Reed Stiffness = 2
  24. - Reed Aperture = 26
  25. - Noise Gain = 4
  26. - Blow Position = 11
  27. - Vibrato Frequency = 29
  28. - Vibrato Gain = 1
  29. - Breath Pressure = 128
  30. by Perry R. Cook and Gary P. Scavone, 1995--2017.
  31. */
  32. /***************************************************/
  33. #include "Saxofony.h"
  34. #include "SKINImsg.h"
  35. namespace stk {
  36. Saxofony :: Saxofony( StkFloat lowestFrequency )
  37. {
  38. if ( lowestFrequency <= 0.0 ) {
  39. oStream_ << "Saxofony::Saxofony: argument is less than or equal to zero!";
  40. handleError( StkError::FUNCTION_ARGUMENT );
  41. }
  42. unsigned long nDelays = (unsigned long) ( Stk::sampleRate() / lowestFrequency );
  43. delays_[0].setMaximumDelay( nDelays + 1 );
  44. delays_[1].setMaximumDelay( nDelays + 1 );
  45. // Initialize blowing position to 0.2 of length.
  46. position_ = 0.2;
  47. reedTable_.setOffset( 0.7 );
  48. reedTable_.setSlope( 0.3 );
  49. vibrato_.setFrequency( 5.735 );
  50. outputGain_ = 0.3;
  51. noiseGain_ = 0.2;
  52. vibratoGain_ = 0.1;
  53. this->setFrequency( 220.0 );
  54. this->clear();
  55. }
  56. Saxofony :: ~Saxofony( void )
  57. {
  58. }
  59. void Saxofony :: clear( void )
  60. {
  61. delays_[0].clear();
  62. delays_[1].clear();
  63. filter_.clear();
  64. }
  65. void Saxofony :: setFrequency( StkFloat frequency )
  66. {
  67. #if defined(_STK_DEBUG_)
  68. if ( frequency <= 0.0 ) {
  69. oStream_ << "Saxofony::setFrequency: argument is less than or equal to zero!";
  70. handleError( StkError::WARNING ); return;
  71. }
  72. #endif
  73. // Account for filter delay and one sample "lastOut" delay.
  74. StkFloat delay = ( Stk::sampleRate() / frequency ) - filter_.phaseDelay( frequency ) - 1.0;
  75. delays_[0].setDelay( (1.0-position_) * delay );
  76. delays_[1].setDelay( position_ * delay );
  77. }
  78. void Saxofony :: setBlowPosition( StkFloat position )
  79. {
  80. if ( position_ == position ) return;
  81. if ( position < 0.0 ) position_ = 0.0;
  82. else if ( position > 1.0 ) position_ = 1.0;
  83. else position_ = position;
  84. StkFloat totalDelay = delays_[0].getDelay();
  85. totalDelay += delays_[1].getDelay();
  86. delays_[0].setDelay( (1.0-position_) * totalDelay );
  87. delays_[1].setDelay( position_ * totalDelay );
  88. }
  89. void Saxofony :: startBlowing( StkFloat amplitude, StkFloat rate )
  90. {
  91. if ( amplitude <= 0.0 || rate <= 0.0 ) {
  92. oStream_ << "Saxofony::startBlowing: one or more arguments is less than or equal to zero!";
  93. handleError( StkError::WARNING ); return;
  94. }
  95. envelope_.setRate( rate );
  96. envelope_.setTarget( amplitude );
  97. }
  98. void Saxofony :: stopBlowing( StkFloat rate )
  99. {
  100. if ( rate <= 0.0 ) {
  101. oStream_ << "Saxofony::stopBlowing: argument is less than or equal to zero!";
  102. handleError( StkError::WARNING ); return;
  103. }
  104. envelope_.setRate( rate );
  105. envelope_.setTarget( 0.0 );
  106. }
  107. void Saxofony :: noteOn( StkFloat frequency, StkFloat amplitude )
  108. {
  109. this->setFrequency( frequency );
  110. this->startBlowing( 0.55 + (amplitude * 0.30), amplitude * 0.005 );
  111. outputGain_ = amplitude + 0.001;
  112. }
  113. void Saxofony :: noteOff( StkFloat amplitude )
  114. {
  115. this->stopBlowing( amplitude * 0.01 );
  116. }
  117. void Saxofony :: controlChange( int number, StkFloat value )
  118. {
  119. #if defined(_STK_DEBUG_)
  120. if ( Stk::inRange( value, 0.0, 128.0 ) == false ) {
  121. oStream_ << "Saxofony::controlChange: value (" << value << ") is out of range!";
  122. handleError( StkError::WARNING ); return;
  123. }
  124. #endif
  125. StkFloat normalizedValue = value * ONE_OVER_128;
  126. if (number == __SK_ReedStiffness_) // 2
  127. reedTable_.setSlope( 0.1 + (0.4 * normalizedValue) );
  128. else if (number == __SK_NoiseLevel_) // 4
  129. noiseGain_ = ( normalizedValue * 0.4 );
  130. else if (number == 29) // 29
  131. vibrato_.setFrequency( normalizedValue * 12.0 );
  132. else if (number == __SK_ModWheel_) // 1
  133. vibratoGain_ = ( normalizedValue * 0.5 );
  134. else if (number == __SK_AfterTouch_Cont_) // 128
  135. envelope_.setValue( normalizedValue );
  136. else if (number == 11) // 11
  137. this->setBlowPosition( normalizedValue );
  138. else if (number == 26) // reed table offset
  139. reedTable_.setOffset(0.4 + ( normalizedValue * 0.6));
  140. #if defined(_STK_DEBUG_)
  141. else {
  142. oStream_ << "Saxofony::controlChange: undefined control number (" << number << ")!";
  143. handleError( StkError::WARNING );
  144. }
  145. #endif
  146. }
  147. } // stk namespace