1 #ifndef STK_SINEWAVE_H
2 #define STK_SINEWAVE_H
3 
4 const unsigned long TABLE_SIZE = 2048;
5 
6 #include "Generator.h"
7 
8 namespace stk {
9 
10 /***************************************************/
11 /*! \class SineWave
12     \brief STK sinusoid oscillator class.
13 
14     This class computes and saves a static sine "table" that can be
15     shared by multiple instances.  It has an interface similar to the
16     WaveLoop class but inherits from the Generator class.  Output
17     values are computed using linear interpolation.
18 
19     The "table" length, set in SineWave.h, is 2048 samples by default.
20 
21     by Perry R. Cook and Gary P. Scavone, 1995--2021.
22 */
23 /***************************************************/
24 
25 class SineWave : public Generator
26 {
27 public:
28   //! Default constructor.
29   SineWave( void );
30 
31   //! Class destructor.
32   ~SineWave( void );
33 
34   //! Clear output and reset time pointer to zero.
35   void reset( void );
36 
37   //! Set the data read rate in samples.  The rate can be negative.
38   /*!
39     If the rate value is negative, the data is read in reverse order.
40   */
setRate(StkFloat rate)41   void setRate( StkFloat rate ) { rate_ = rate; };
42 
43   //! Set the data interpolation rate based on a looping frequency.
44   /*!
45     This function determines the interpolation rate based on the file
46     size and the current Stk::sampleRate.  The \e frequency value
47     corresponds to file cycles per second.  The frequency can be
48     negative, in which case the loop is read in reverse order.
49    */
50   void setFrequency( StkFloat frequency );
51 
52   //! Increment the read pointer by \e time in samples, modulo the table size.
53   void addTime( StkFloat time );
54 
55   //! Increment the read pointer by a normalized \e phase value.
56   /*!
57     This function increments the read pointer by a normalized phase
58     value, such that \e phase = 1.0 corresponds to a 360 degree phase
59     shift.  Positive or negative values are possible.
60    */
61   void addPhase( StkFloat phase );
62 
63   //! Add a normalized phase offset to the read pointer.
64   /*!
65     A \e phaseOffset = 1.0 corresponds to a 360 degree phase
66     offset.  Positive or negative values are possible.
67    */
68   void addPhaseOffset( StkFloat phaseOffset );
69 
70   //! Return the last computed output value.
lastOut(void)71   StkFloat lastOut( void ) const { return lastFrame_[0]; };
72 
73   //! Compute and return one output sample.
74   StkFloat tick( void );
75 
76   //! Fill a channel of the StkFrames object with computed outputs.
77   /*!
78     The \c channel argument must be less than the number of
79     channels in the StkFrames argument (the first channel is specified
80     by 0).  However, range checking is only performed if _STK_DEBUG_
81     is defined during compilation, in which case an out-of-range value
82     will trigger an StkError exception.
83   */
84   StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
85 
86 protected:
87 
88   void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
89 
90   static StkFrames table_;
91   StkFloat time_;
92   StkFloat rate_;
93   StkFloat phaseOffset_;
94   unsigned int iIndex_;
95   StkFloat alpha_;
96 
97 };
98 
tick(void)99 inline StkFloat SineWave :: tick( void )
100 {
101   // Check limits of time address ... if necessary, recalculate modulo
102   // TABLE_SIZE.
103   while ( time_ < 0.0 )
104     time_ += TABLE_SIZE;
105   while ( time_ >= TABLE_SIZE )
106     time_ -= TABLE_SIZE;
107 
108   iIndex_ = (unsigned int) time_;
109   alpha_ = time_ - iIndex_;
110   StkFloat tmp = table_[ iIndex_ ];
111   tmp += ( alpha_ * ( table_[ iIndex_ + 1 ] - tmp ) );
112 
113   // Increment time, which can be negative.
114   time_ += rate_;
115 
116   lastFrame_[0] = tmp;
117   return lastFrame_[0];
118 }
119 
tick(StkFrames & frames,unsigned int channel)120 inline StkFrames& SineWave :: tick( StkFrames& frames, unsigned int channel )
121 {
122 #if defined(_STK_DEBUG_)
123   if ( channel >= frames.channels() ) {
124     oStream_ << "SineWave::tick(): channel and StkFrames arguments are incompatible!";
125     handleError( StkError::FUNCTION_ARGUMENT );
126   }
127 #endif
128 
129   StkFloat *samples = &frames[channel];
130   StkFloat tmp = 0.0;
131 
132   unsigned int hop = frames.channels();
133   for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
134 
135     // Check limits of time address ... if necessary, recalculate modulo
136     // TABLE_SIZE.
137     while ( time_ < 0.0 )
138       time_ += TABLE_SIZE;
139     while ( time_ >= TABLE_SIZE )
140       time_ -= TABLE_SIZE;
141 
142     iIndex_ = (unsigned int) time_;
143     alpha_ = time_ - iIndex_;
144     tmp = table_[ iIndex_ ];
145     tmp += ( alpha_ * ( table_[ iIndex_ + 1 ] - tmp ) );
146     *samples = tmp;
147 
148     // Increment time, which can be negative.
149     time_ += rate_;
150   }
151 
152   lastFrame_[0] = tmp;
153   return frames;
154 }
155 
156 } // stk namespace
157 
158 #endif
159 
160