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.

127 lines
3.5KB

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