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