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.

136 lines
3.8KB

  1. #ifndef STK_FMVOICES_H
  2. #define STK_FMVOICES_H
  3. #include "FM.h"
  4. namespace stk {
  5. /***************************************************/
  6. /*! \class FMVoices
  7. \brief STK singing FM synthesis instrument.
  8. This class implements 3 carriers and a common
  9. modulator, also referred to as algorithm 6 of
  10. the TX81Z.
  11. \code
  12. Algorithm 6 is :
  13. /->1 -\
  14. 4-|-->2 - +-> Out
  15. \->3 -/
  16. \endcode
  17. Control Change Numbers:
  18. - Vowel = 2
  19. - Spectral Tilt = 4
  20. - LFO Speed = 11
  21. - LFO Depth = 1
  22. - ADSR 2 & 4 Target = 128
  23. The basic Chowning/Stanford FM patent expired
  24. in 1995, but there exist follow-on patents,
  25. mostly assigned to Yamaha. If you are of the
  26. type who should worry about this (making
  27. money) worry away.
  28. by Perry R. Cook and Gary P. Scavone, 1995--2017.
  29. */
  30. /***************************************************/
  31. class FMVoices : public FM
  32. {
  33. public:
  34. //! Class constructor.
  35. /*!
  36. An StkError will be thrown if the rawwave path is incorrectly set.
  37. */
  38. FMVoices( void );
  39. //! Class destructor.
  40. ~FMVoices( void );
  41. //! Set instrument parameters for a particular frequency.
  42. void setFrequency( StkFloat frequency );
  43. //! Start a note with the given frequency and amplitude.
  44. void noteOn( StkFloat frequency, StkFloat amplitude );
  45. //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
  46. void controlChange( int number, StkFloat value );
  47. //! Compute and return one output sample.
  48. StkFloat tick( unsigned int channel = 0 );
  49. //! Fill a channel of the StkFrames object with computed outputs.
  50. /*!
  51. The \c channel argument must be less than the number of
  52. channels in the StkFrames argument (the first channel is specified
  53. by 0). However, range checking is only performed if _STK_DEBUG_
  54. is defined during compilation, in which case an out-of-range value
  55. will trigger an StkError exception.
  56. */
  57. StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
  58. protected:
  59. int currentVowel_;
  60. StkFloat tilt_[3];
  61. StkFloat mods_[3];
  62. };
  63. inline StkFloat FMVoices :: tick( unsigned int )
  64. {
  65. StkFloat temp, temp2;
  66. temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
  67. temp2 = vibrato_.tick() * modDepth_ * 0.1;
  68. waves_[0]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[0]);
  69. waves_[1]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[1]);
  70. waves_[2]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[2]);
  71. waves_[3]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[3]);
  72. waves_[0]->addPhaseOffset(temp * mods_[0]);
  73. waves_[1]->addPhaseOffset(temp * mods_[1]);
  74. waves_[2]->addPhaseOffset(temp * mods_[2]);
  75. waves_[3]->addPhaseOffset( twozero_.lastOut() );
  76. twozero_.tick( temp );
  77. temp = gains_[0] * tilt_[0] * adsr_[0]->tick() * waves_[0]->tick();
  78. temp += gains_[1] * tilt_[1] * adsr_[1]->tick() * waves_[1]->tick();
  79. temp += gains_[2] * tilt_[2] * adsr_[2]->tick() * waves_[2]->tick();
  80. lastFrame_[0] = temp * 0.33;
  81. return lastFrame_[0];
  82. }
  83. inline StkFrames& FMVoices :: tick( StkFrames& frames, unsigned int channel )
  84. {
  85. unsigned int nChannels = lastFrame_.channels();
  86. #if defined(_STK_DEBUG_)
  87. if ( channel > frames.channels() - nChannels ) {
  88. oStream_ << "FMVoices::tick(): channel and StkFrames arguments are incompatible!";
  89. handleError( StkError::FUNCTION_ARGUMENT );
  90. }
  91. #endif
  92. StkFloat *samples = &frames[channel];
  93. unsigned int j, hop = frames.channels() - nChannels;
  94. if ( nChannels == 1 ) {
  95. for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
  96. *samples++ = tick();
  97. }
  98. else {
  99. for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
  100. *samples++ = tick();
  101. for ( j=1; j<nChannels; j++ )
  102. *samples++ = lastFrame_[j];
  103. }
  104. }
  105. return frames;
  106. }
  107. } // stk namespace
  108. #endif