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