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