1 #ifndef STK_MODAL_H
2 #define STK_MODAL_H
3 
4 #include "Instrmnt.h"
5 #include "Envelope.h"
6 #include "FileLoop.h"
7 #include "SineWave.h"
8 #include "BiQuad.h"
9 #include "OnePole.h"
10 
11 namespace stk {
12 
13 /***************************************************/
14 /*! \class Modal
15     \brief STK resonance model abstract base class.
16 
17     This class contains an excitation wavetable,
18     an envelope, an oscillator, and N resonances
19     (non-sweeping BiQuad filters), where N is set
20     during instantiation.
21 
22     by Perry R. Cook and Gary P. Scavone, 1995--2021.
23 */
24 /***************************************************/
25 
26 class Modal : public Instrmnt
27 {
28 public:
29   //! Class constructor, taking the desired number of modes to create.
30   /*!
31     An StkError will be thrown if the rawwave path is incorrectly set.
32   */
33   Modal( unsigned int modes = 4 );
34 
35   //! Class destructor.
36   virtual ~Modal( void );
37 
38   //! Reset and clear all internal state.
39   void clear( void );
40 
41   //! Set instrument parameters for a particular frequency.
42   virtual void setFrequency( StkFloat frequency );
43 
44   //! Set the ratio and radius for a specified mode filter.
45   void setRatioAndRadius( unsigned int modeIndex, StkFloat ratio, StkFloat radius );
46 
47   //! Set the master gain.
48   void setMasterGain( StkFloat aGain ) { masterGain_ = aGain; };
49 
50   //! Set the direct gain.
51   void setDirectGain( StkFloat aGain ) { directGain_ = aGain; };
52 
53   //! Set the gain for a specified mode filter.
54   void setModeGain( unsigned int modeIndex, StkFloat gain );
55 
56   //! Initiate a strike with the given amplitude (0.0 - 1.0).
57   virtual void strike( StkFloat amplitude );
58 
59   //! Damp modes with a given decay factor (0.0 - 1.0).
60   void damp( StkFloat amplitude );
61 
62   //! Start a note with the given frequency and amplitude.
63   void noteOn( StkFloat frequency, StkFloat amplitude );
64 
65   //! Stop a note with the given amplitude (speed of decay).
66   void noteOff( StkFloat amplitude );
67 
68   //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
69   virtual void controlChange( int number, StkFloat value ) = 0;
70 
71   //! Compute and return one output sample.
72   StkFloat tick( unsigned int channel = 0 );
73 
74   //! Fill a channel of the StkFrames object with computed outputs.
75   /*!
76     The \c channel argument must be less than the number of
77     channels in the StkFrames argument (the first channel is specified
78     by 0).  However, range checking is only performed if _STK_DEBUG_
79     is defined during compilation, in which case an out-of-range value
80     will trigger an StkError exception.
81   */
82   StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
83 
84 protected:
85 
86   Envelope envelope_;
87   FileWvIn *wave_;
88   BiQuad **filters_;
89   OnePole  onepole_;
90   SineWave vibrato_;
91 
92   unsigned int nModes_;
93   std::vector<StkFloat> ratios_;
94   std::vector<StkFloat> radii_;
95 
96   StkFloat vibratoGain_;
97   StkFloat masterGain_;
98   StkFloat directGain_;
99   StkFloat stickHardness_;
100   StkFloat strikePosition_;
101   StkFloat baseFrequency_;
102 };
103 
104 inline StkFloat Modal :: tick( unsigned int )
105 {
106   StkFloat temp = masterGain_ * onepole_.tick( wave_->tick() * envelope_.tick() );
107 
108   StkFloat temp2 = 0.0;
109   for ( unsigned int i=0; i<nModes_; i++ )
110     temp2 += filters_[i]->tick(temp);
111 
112   temp2  -= temp2 * directGain_;
113   temp2 += directGain_ * temp;
114 
115   if ( vibratoGain_ != 0.0 ) {
116     // Calculate AM and apply to master out
117     temp = 1.0 + ( vibrato_.tick() * vibratoGain_ );
118     temp2 = temp * temp2;
119   }
120 
121   lastFrame_[0] = temp2;
122   return lastFrame_[0];
123 }
124 
125 inline StkFrames& Modal :: tick( StkFrames& frames, unsigned int channel )
126 {
127   unsigned int nChannels = lastFrame_.channels();
128 #if defined(_STK_DEBUG_)
129   if ( channel > frames.channels() - nChannels ) {
130     oStream_ << "Modal::tick(): channel and StkFrames arguments are incompatible!";
131     handleError( StkError::FUNCTION_ARGUMENT );
132   }
133 #endif
134 
135   StkFloat *samples = &frames[channel];
136   unsigned int j, hop = frames.channels() - nChannels;
137   if ( nChannels == 1 ) {
138     for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
139       *samples++ = tick();
140   }
141   else {
142     for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
143       *samples++ = tick();
144       for ( j=1; j<nChannels; j++ )
145         *samples++ = lastFrame_[j];
146     }
147   }
148 
149   return frames;
150 }
151 
152 } // stk namespace
153 
154 #endif
155