f@0
|
1 /***************************************************/
|
f@0
|
2 /*! \class Stk
|
f@0
|
3 \brief STK base class
|
f@0
|
4
|
f@0
|
5 Nearly all STK classes inherit from this class.
|
f@0
|
6 The global sample rate can be queried and
|
f@0
|
7 modified via Stk. In addition, this class
|
f@0
|
8 provides error handling and byte-swapping
|
f@0
|
9 functions.
|
f@0
|
10
|
f@0
|
11 The Synthesis ToolKit in C++ (STK) is a set of open source audio
|
f@0
|
12 signal processing and algorithmic synthesis classes written in the
|
f@0
|
13 C++ programming language. STK was designed to facilitate rapid
|
f@0
|
14 development of music synthesis and audio processing software, with
|
f@0
|
15 an emphasis on cross-platform functionality, realtime control,
|
f@0
|
16 ease of use, and educational example code. STK currently runs
|
f@0
|
17 with realtime support (audio and MIDI) on Linux, Macintosh OS X,
|
f@0
|
18 and Windows computer platforms. Generic, non-realtime support has
|
f@0
|
19 been tested under NeXTStep, Sun, and other platforms and should
|
f@0
|
20 work with any standard C++ compiler.
|
f@0
|
21
|
f@0
|
22 STK WWW site: http://ccrma.stanford.edu/software/stk/
|
f@0
|
23
|
f@0
|
24 The Synthesis ToolKit in C++ (STK)
|
f@0
|
25 Copyright (c) 1995--2014 Perry R. Cook and Gary P. Scavone
|
f@0
|
26
|
f@0
|
27 Permission is hereby granted, free of charge, to any person
|
f@0
|
28 obtaining a copy of this software and associated documentation files
|
f@0
|
29 (the "Software"), to deal in the Software without restriction,
|
f@0
|
30 including without limitation the rights to use, copy, modify, merge,
|
f@0
|
31 publish, distribute, sublicense, and/or sell copies of the Software,
|
f@0
|
32 and to permit persons to whom the Software is furnished to do so,
|
f@0
|
33 subject to the following conditions:
|
f@0
|
34
|
f@0
|
35 The above copyright notice and this permission notice shall be
|
f@0
|
36 included in all copies or substantial portions of the Software.
|
f@0
|
37
|
f@0
|
38 Any person wishing to distribute modifications to the Software is
|
f@0
|
39 asked to send the modifications to the original developer so that
|
f@0
|
40 they can be incorporated into the canonical version. This is,
|
f@0
|
41 however, not a binding provision of this license.
|
f@0
|
42
|
f@0
|
43 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
f@0
|
44 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
f@0
|
45 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
f@0
|
46 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
f@0
|
47 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
f@0
|
48 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
f@0
|
49 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
f@0
|
50 */
|
f@0
|
51 /***************************************************/
|
f@0
|
52
|
f@0
|
53 #include "../include/Stk.h"
|
f@0
|
54 #include <stdlib.h>
|
f@0
|
55
|
f@0
|
56 namespace stk {
|
f@0
|
57
|
f@0
|
58 StkFloat Stk :: srate_ = (StkFloat) SRATE;
|
f@0
|
59 std::string Stk :: rawwavepath_ = RAWWAVE_PATH;
|
f@0
|
60 const Stk::StkFormat Stk :: STK_SINT8 = 0x1;
|
f@0
|
61 const Stk::StkFormat Stk :: STK_SINT16 = 0x2;
|
f@0
|
62 const Stk::StkFormat Stk :: STK_SINT24 = 0x4;
|
f@0
|
63 const Stk::StkFormat Stk :: STK_SINT32 = 0x8;
|
f@0
|
64 const Stk::StkFormat Stk :: STK_FLOAT32 = 0x10;
|
f@0
|
65 const Stk::StkFormat Stk :: STK_FLOAT64 = 0x20;
|
f@0
|
66 bool Stk :: showWarnings_ = true;
|
f@0
|
67 bool Stk :: printErrors_ = true;
|
f@0
|
68 std::vector<Stk *> Stk :: alertList_;
|
f@0
|
69 std::ostringstream Stk :: oStream_;
|
f@0
|
70
|
f@0
|
71 Stk :: Stk( void )
|
f@0
|
72 : ignoreSampleRateChange_(false)
|
f@0
|
73 {
|
f@0
|
74 }
|
f@0
|
75
|
f@0
|
76 Stk :: ~Stk( void )
|
f@0
|
77 {
|
f@0
|
78 }
|
f@0
|
79
|
f@0
|
80 void Stk :: setSampleRate( StkFloat rate )
|
f@0
|
81 {
|
f@0
|
82 if ( rate > 0.0 && rate != srate_ ) {
|
f@0
|
83 StkFloat oldRate = srate_;
|
f@0
|
84 srate_ = rate;
|
f@0
|
85
|
f@0
|
86 for ( unsigned int i=0; i<alertList_.size(); i++ )
|
f@0
|
87 alertList_[i]->sampleRateChanged( srate_, oldRate );
|
f@0
|
88 }
|
f@0
|
89 }
|
f@0
|
90
|
f@0
|
91 void Stk :: sampleRateChanged( StkFloat /*newRate*/, StkFloat /*oldRate*/ )
|
f@0
|
92 {
|
f@0
|
93 // This function should be reimplemented in classes that need to
|
f@0
|
94 // make internal variable adjustments in response to a global sample
|
f@0
|
95 // rate change.
|
f@0
|
96 }
|
f@0
|
97
|
f@0
|
98 void Stk :: addSampleRateAlert( Stk *ptr )
|
f@0
|
99 {
|
f@0
|
100 for ( unsigned int i=0; i<alertList_.size(); i++ )
|
f@0
|
101 if ( alertList_[i] == ptr ) return;
|
f@0
|
102
|
f@0
|
103 alertList_.push_back( ptr );
|
f@0
|
104 }
|
f@0
|
105
|
f@0
|
106 void Stk :: removeSampleRateAlert( Stk *ptr )
|
f@0
|
107 {
|
f@0
|
108 for ( unsigned int i=0; i<alertList_.size(); i++ ) {
|
f@0
|
109 if ( alertList_[i] == ptr ) {
|
f@0
|
110 alertList_.erase( alertList_.begin() + i );
|
f@0
|
111 return;
|
f@0
|
112 }
|
f@0
|
113 }
|
f@0
|
114 }
|
f@0
|
115
|
f@0
|
116 void Stk :: setRawwavePath( std::string path )
|
f@0
|
117 {
|
f@0
|
118 if ( !path.empty() )
|
f@0
|
119 rawwavepath_ = path;
|
f@0
|
120
|
f@0
|
121 // Make sure the path includes a "/"
|
f@0
|
122 if ( rawwavepath_[rawwavepath_.length()-1] != '/' )
|
f@0
|
123 rawwavepath_ += "/";
|
f@0
|
124 }
|
f@0
|
125
|
f@0
|
126 void Stk :: swap16(unsigned char *ptr)
|
f@0
|
127 {
|
f@0
|
128 unsigned char val;
|
f@0
|
129
|
f@0
|
130 // Swap 1st and 2nd bytes
|
f@0
|
131 val = *(ptr);
|
f@0
|
132 *(ptr) = *(ptr+1);
|
f@0
|
133 *(ptr+1) = val;
|
f@0
|
134 }
|
f@0
|
135
|
f@0
|
136 void Stk :: swap32(unsigned char *ptr)
|
f@0
|
137 {
|
f@0
|
138 unsigned char val;
|
f@0
|
139
|
f@0
|
140 // Swap 1st and 4th bytes
|
f@0
|
141 val = *(ptr);
|
f@0
|
142 *(ptr) = *(ptr+3);
|
f@0
|
143 *(ptr+3) = val;
|
f@0
|
144
|
f@0
|
145 //Swap 2nd and 3rd bytes
|
f@0
|
146 ptr += 1;
|
f@0
|
147 val = *(ptr);
|
f@0
|
148 *(ptr) = *(ptr+1);
|
f@0
|
149 *(ptr+1) = val;
|
f@0
|
150 }
|
f@0
|
151
|
f@0
|
152 void Stk :: swap64(unsigned char *ptr)
|
f@0
|
153 {
|
f@0
|
154 unsigned char val;
|
f@0
|
155
|
f@0
|
156 // Swap 1st and 8th bytes
|
f@0
|
157 val = *(ptr);
|
f@0
|
158 *(ptr) = *(ptr+7);
|
f@0
|
159 *(ptr+7) = val;
|
f@0
|
160
|
f@0
|
161 // Swap 2nd and 7th bytes
|
f@0
|
162 ptr += 1;
|
f@0
|
163 val = *(ptr);
|
f@0
|
164 *(ptr) = *(ptr+5);
|
f@0
|
165 *(ptr+5) = val;
|
f@0
|
166
|
f@0
|
167 // Swap 3rd and 6th bytes
|
f@0
|
168 ptr += 1;
|
f@0
|
169 val = *(ptr);
|
f@0
|
170 *(ptr) = *(ptr+3);
|
f@0
|
171 *(ptr+3) = val;
|
f@0
|
172
|
f@0
|
173 // Swap 4th and 5th bytes
|
f@0
|
174 ptr += 1;
|
f@0
|
175 val = *(ptr);
|
f@0
|
176 *(ptr) = *(ptr+1);
|
f@0
|
177 *(ptr+1) = val;
|
f@0
|
178 }
|
f@0
|
179
|
f@0
|
180 #if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
f@0
|
181 #include <unistd.h>
|
f@0
|
182 #elif defined(__OS_WINDOWS__)
|
f@0
|
183 #include <windows.h>
|
f@0
|
184 #endif
|
f@0
|
185
|
f@0
|
186 void Stk :: sleep(unsigned long milliseconds)
|
f@0
|
187 {
|
f@0
|
188 #if defined(__OS_WINDOWS__)
|
f@0
|
189 Sleep((DWORD) milliseconds);
|
f@0
|
190 #elif (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
|
f@0
|
191 usleep( (unsigned long) (milliseconds * 1000.0) );
|
f@0
|
192 #endif
|
f@0
|
193 }
|
f@0
|
194
|
f@0
|
195 void Stk :: handleError( StkError::Type type ) const
|
f@0
|
196 {
|
f@0
|
197 handleError( oStream_.str(), type );
|
f@0
|
198 oStream_.str( std::string() ); // reset the ostringstream buffer
|
f@0
|
199 }
|
f@0
|
200
|
f@0
|
201 void Stk :: handleError( const char *message, StkError::Type type )
|
f@0
|
202 {
|
f@0
|
203 std::string msg( message );
|
f@0
|
204 handleError( msg, type );
|
f@0
|
205 }
|
f@0
|
206
|
f@0
|
207 void Stk :: handleError( std::string message, StkError::Type type )
|
f@0
|
208 {
|
f@0
|
209 if ( type == StkError::WARNING || type == StkError::STATUS ) {
|
f@0
|
210 if ( !showWarnings_ ) return;
|
f@0
|
211 std::cerr << '\n' << message << '\n' << std::endl;
|
f@0
|
212 }
|
f@0
|
213 else if (type == StkError::DEBUG_PRINT) {
|
f@0
|
214 #if defined(_STK_DEBUG_)
|
f@0
|
215 std::cerr << '\n' << message << '\n' << std::endl;
|
f@0
|
216 #endif
|
f@0
|
217 }
|
f@0
|
218 else {
|
f@0
|
219 if ( printErrors_ ) {
|
f@0
|
220 // Print error message before throwing.
|
f@0
|
221 std::cerr << '\n' << message << '\n' << std::endl;
|
f@0
|
222 }
|
f@0
|
223 throw StkError(message, type);
|
f@0
|
224 }
|
f@0
|
225 }
|
f@0
|
226
|
f@0
|
227 //
|
f@0
|
228 // StkFrames definitions
|
f@0
|
229 //
|
f@0
|
230
|
f@0
|
231 StkFrames :: StkFrames( unsigned int nFrames, unsigned int nChannels )
|
f@0
|
232 : data_( 0 ), nFrames_( nFrames ), nChannels_( nChannels )
|
f@0
|
233 {
|
f@0
|
234 size_ = nFrames_ * nChannels_;
|
f@0
|
235 bufferSize_ = size_;
|
f@0
|
236
|
f@0
|
237 if ( size_ > 0 ) {
|
f@0
|
238 data_ = (StkFloat *) calloc( size_, sizeof( StkFloat ) );
|
f@0
|
239 #if defined(_STK_DEBUG_)
|
f@0
|
240 if ( data_ == NULL ) {
|
f@0
|
241 std::string error = "StkFrames: memory allocation error in constructor!";
|
f@0
|
242 Stk::handleError( error, StkError::MEMORY_ALLOCATION );
|
f@0
|
243 }
|
f@0
|
244 #endif
|
f@0
|
245 }
|
f@0
|
246
|
f@0
|
247 dataRate_ = Stk::sampleRate();
|
f@0
|
248 }
|
f@0
|
249
|
f@0
|
250 StkFrames :: StkFrames( const StkFloat& value, unsigned int nFrames, unsigned int nChannels )
|
f@0
|
251 : data_( 0 ), nFrames_( nFrames ), nChannels_( nChannels )
|
f@0
|
252 {
|
f@0
|
253 size_ = nFrames_ * nChannels_;
|
f@0
|
254 bufferSize_ = size_;
|
f@0
|
255 if ( size_ > 0 ) {
|
f@0
|
256 data_ = (StkFloat *) malloc( size_ * sizeof( StkFloat ) );
|
f@0
|
257 #if defined(_STK_DEBUG_)
|
f@0
|
258 if ( data_ == NULL ) {
|
f@0
|
259 std::string error = "StkFrames: memory allocation error in constructor!";
|
f@0
|
260 Stk::handleError( error, StkError::MEMORY_ALLOCATION );
|
f@0
|
261 }
|
f@0
|
262 #endif
|
f@0
|
263 for ( long i=0; i<(long)size_; i++ ) data_[i] = value;
|
f@0
|
264 }
|
f@0
|
265
|
f@0
|
266 dataRate_ = Stk::sampleRate();
|
f@0
|
267 }
|
f@0
|
268
|
f@0
|
269 StkFrames :: ~StkFrames()
|
f@0
|
270 {
|
f@0
|
271 if ( data_ ) free( data_ );
|
f@0
|
272 }
|
f@0
|
273
|
f@0
|
274 StkFrames :: StkFrames( const StkFrames& f )
|
f@0
|
275 : data_(0), size_(0), bufferSize_(0)
|
f@0
|
276 {
|
f@0
|
277 resize( f.frames(), f.channels() );
|
f@0
|
278 dataRate_ = Stk::sampleRate();
|
f@0
|
279 for ( unsigned int i=0; i<size_; i++ ) data_[i] = f[i];
|
f@0
|
280 }
|
f@0
|
281
|
f@0
|
282 StkFrames& StkFrames :: operator= ( const StkFrames& f )
|
f@0
|
283 {
|
f@0
|
284 data_ = 0;
|
f@0
|
285 size_ = 0;
|
f@0
|
286 bufferSize_ = 0;
|
f@0
|
287 resize( f.frames(), f.channels() );
|
f@0
|
288 dataRate_ = Stk::sampleRate();
|
f@0
|
289 for ( unsigned int i=0; i<size_; i++ ) data_[i] = f[i];
|
f@0
|
290 return *this;
|
f@0
|
291 }
|
f@0
|
292
|
f@0
|
293 void StkFrames :: resize( size_t nFrames, unsigned int nChannels )
|
f@0
|
294 {
|
f@0
|
295 nFrames_ = nFrames;
|
f@0
|
296 nChannels_ = nChannels;
|
f@0
|
297
|
f@0
|
298 size_ = nFrames_ * nChannels_;
|
f@0
|
299 if ( size_ > bufferSize_ ) {
|
f@0
|
300 if ( data_ ) free( data_ );
|
f@0
|
301 data_ = (StkFloat *) malloc( size_ * sizeof( StkFloat ) );
|
f@0
|
302 #if defined(_STK_DEBUG_)
|
f@0
|
303 if ( data_ == NULL ) {
|
f@0
|
304 std::string error = "StkFrames::resize: memory allocation error!";
|
f@0
|
305 Stk::handleError( error, StkError::MEMORY_ALLOCATION );
|
f@0
|
306 }
|
f@0
|
307 #endif
|
f@0
|
308 bufferSize_ = size_;
|
f@0
|
309 }
|
f@0
|
310 }
|
f@0
|
311
|
f@0
|
312 void StkFrames :: resize( size_t nFrames, unsigned int nChannels, StkFloat value )
|
f@0
|
313 {
|
f@0
|
314 this->resize( nFrames, nChannels );
|
f@0
|
315
|
f@0
|
316 for ( size_t i=0; i<size_; i++ ) data_[i] = value;
|
f@0
|
317 }
|
f@0
|
318
|
f@0
|
319 StkFloat StkFrames :: interpolate( StkFloat frame, unsigned int channel ) const
|
f@0
|
320 {
|
f@0
|
321 #if defined(_STK_DEBUG_)
|
f@0
|
322 if ( frame < 0.0 || frame > (StkFloat) ( nFrames_ - 1 ) || channel >= nChannels_ ) {
|
f@0
|
323 std::ostringstream error;
|
f@0
|
324 error << "StkFrames::interpolate: invalid frame (" << frame << ") or channel (" << channel << ") value!";
|
f@0
|
325 Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
|
f@0
|
326 }
|
f@0
|
327 #endif
|
f@0
|
328
|
f@0
|
329 size_t iIndex = ( size_t ) frame; // integer part of index
|
f@0
|
330 StkFloat output, alpha = frame - (StkFloat) iIndex; // fractional part of index
|
f@0
|
331
|
f@0
|
332 iIndex = iIndex * nChannels_ + channel;
|
f@0
|
333 output = data_[ iIndex ];
|
f@0
|
334 if ( alpha > 0.0 )
|
f@0
|
335 output += ( alpha * ( data_[ iIndex + nChannels_ ] - output ) );
|
f@0
|
336
|
f@0
|
337 return output;
|
f@0
|
338 }
|
f@0
|
339
|
f@0
|
340 } // stk namespace
|