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