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