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