f@0: #ifndef STK_STK_H f@0: #define STK_STK_H f@0: f@0: #include f@0: #include f@0: #include f@0: #include f@0: #include f@0: //#include f@0: f@0: /*! \namespace stk f@0: \brief The STK namespace. f@0: f@0: Most Stk classes are defined within the STK namespace. Exceptions f@0: to this include the classes RtAudio and RtMidi. f@0: */ f@0: namespace stk { f@0: f@0: /***************************************************/ f@0: /*! \class Stk f@0: \brief STK base class f@0: f@0: Nearly all STK classes inherit from this class. f@0: The global sample rate and rawwave path variables f@0: can be queried and modified via Stk. In addition, f@0: this class provides error handling and f@0: byte-swapping functions. f@0: f@0: The Synthesis ToolKit in C++ (STK) is a set of open source audio f@0: signal processing and algorithmic synthesis classes written in the f@0: C++ programming language. STK was designed to facilitate rapid f@0: development of music synthesis and audio processing software, with f@0: an emphasis on cross-platform functionality, realtime control, f@0: ease of use, and educational example code. STK currently runs f@0: with realtime support (audio and MIDI) on Linux, Macintosh OS X, f@0: and Windows computer platforms. Generic, non-realtime support has f@0: been tested under NeXTStep, Sun, and other platforms and should f@0: work with any standard C++ compiler. f@0: f@0: STK WWW site: http://ccrma.stanford.edu/software/stk/ f@0: f@0: The Synthesis ToolKit in C++ (STK) f@0: Copyright (c) 1995--2014 Perry R. Cook and Gary P. Scavone f@0: f@0: Permission is hereby granted, free of charge, to any person f@0: obtaining a copy of this software and associated documentation files f@0: (the "Software"), to deal in the Software without restriction, f@0: including without limitation the rights to use, copy, modify, merge, f@0: publish, distribute, sublicense, and/or sell copies of the Software, f@0: and to permit persons to whom the Software is furnished to do so, f@0: subject to the following conditions: f@0: f@0: The above copyright notice and this permission notice shall be f@0: included in all copies or substantial portions of the Software. f@0: f@0: Any person wishing to distribute modifications to the Software is f@0: asked to send the modifications to the original developer so that f@0: they can be incorporated into the canonical version. This is, f@0: however, not a binding provision of this license. f@0: f@0: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, f@0: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF f@0: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. f@0: IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR f@0: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF f@0: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION f@0: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. f@0: */ f@0: /***************************************************/ f@0: f@0: //#define _STK_DEBUG_ f@0: f@0: // Most data in STK is passed and calculated with the f@0: // following user-definable floating-point type. You f@0: // can change this to "float" if you prefer or perhaps f@0: // a "long double" in the future. f@0: typedef double StkFloat; f@0: f@0: //! STK error handling class. f@0: /*! f@0: This is a fairly abstract exception handling class. There could f@0: be sub-classes to take care of more specific error conditions ... or f@0: not. f@0: */ f@0: class StkError f@0: { f@0: public: f@0: enum Type { f@0: STATUS, f@0: WARNING, f@0: DEBUG_PRINT, f@0: MEMORY_ALLOCATION, f@0: MEMORY_ACCESS, f@0: FUNCTION_ARGUMENT, f@0: FILE_NOT_FOUND, f@0: FILE_UNKNOWN_FORMAT, f@0: FILE_ERROR, f@0: PROCESS_THREAD, f@0: PROCESS_SOCKET, f@0: PROCESS_SOCKET_IPADDR, f@0: AUDIO_SYSTEM, f@0: MIDI_SYSTEM, f@0: UNSPECIFIED f@0: }; f@0: f@0: protected: f@0: std::string message_; f@0: Type type_; f@0: f@0: public: f@0: //! The constructor. f@0: StkError(const std::string& message, Type type = StkError::UNSPECIFIED) f@0: : message_(message), type_(type) {} f@0: f@0: //! The destructor. f@0: virtual ~StkError(void) {}; f@0: f@0: //! Prints thrown error message to stderr. f@0: virtual void printMessage(void) { std::cerr << '\n' << message_ << "\n\n"; } f@0: f@0: //! Returns the thrown error message type. f@0: virtual const Type& getType(void) { return type_; } f@0: f@0: //! Returns the thrown error message string. f@0: virtual const std::string& getMessage(void) { return message_; } f@0: f@0: //! Returns the thrown error message as a C string. f@0: virtual const char *getMessageCString(void) { return message_.c_str(); } f@0: }; f@0: f@0: f@0: class Stk f@0: { f@0: public: f@0: f@0: typedef unsigned long StkFormat; f@0: static const StkFormat STK_SINT8; /*!< -128 to +127 */ f@0: static const StkFormat STK_SINT16; /*!< -32768 to +32767 */ f@0: static const StkFormat STK_SINT24; /*!< Lower 3 bytes of 32-bit signed integer. */ f@0: static const StkFormat STK_SINT32; /*!< -2147483648 to +2147483647. */ f@0: static const StkFormat STK_FLOAT32; /*!< Normalized between plus/minus 1.0. */ f@0: static const StkFormat STK_FLOAT64; /*!< Normalized between plus/minus 1.0. */ f@0: f@0: //! Static method that returns the current STK sample rate. f@0: static StkFloat sampleRate( void ) { return srate_; } f@0: f@0: //! Static method that sets the STK sample rate. f@0: /*! f@0: The sample rate set using this method is queried by all STK f@0: classes that depend on its value. It is initialized to the f@0: default SRATE set in Stk.h. Many STK classes use the sample rate f@0: during instantiation. Therefore, if you wish to use a rate that f@0: is different from the default rate, it is imperative that it be f@0: set \e BEFORE STK objects are instantiated. A few classes that f@0: make use of the global STK sample rate are automatically notified f@0: when the rate changes so that internal class data can be f@0: appropriately updated. However, this has not been fully f@0: implemented. Specifically, classes that appropriately update f@0: their own data when either a setFrequency() or noteOn() function f@0: is called do not currently receive the automatic notification of f@0: rate change. If the user wants a specific class instance to f@0: ignore such notifications, perhaps in a multi-rate context, the f@0: function Stk::ignoreSampleRateChange() should be called. f@0: */ f@0: static void setSampleRate( StkFloat rate ); f@0: f@0: //! A function to enable/disable the automatic updating of class data when the STK sample rate changes. f@0: /*! f@0: This function allows the user to enable or disable class data f@0: updates in response to global sample rate changes on a class by f@0: class basis. f@0: */ f@0: void ignoreSampleRateChange( bool ignore = true ) { ignoreSampleRateChange_ = ignore; }; f@0: f@0: //! Static method that returns the current rawwave path. f@0: static std::string rawwavePath(void) { return rawwavepath_; } f@0: f@0: //! Static method that sets the STK rawwave path. f@0: static void setRawwavePath( std::string path ); f@0: f@0: //! Static method that byte-swaps a 16-bit data type. f@0: static void swap16( unsigned char *ptr ); f@0: f@0: //! Static method that byte-swaps a 32-bit data type. f@0: static void swap32( unsigned char *ptr ); f@0: f@0: //! Static method that byte-swaps a 64-bit data type. f@0: static void swap64( unsigned char *ptr ); f@0: f@0: //! Static cross-platform method to sleep for a number of milliseconds. f@0: static void sleep( unsigned long milliseconds ); f@0: f@0: //! Static method to check whether a value is within a specified range. f@0: static bool inRange( StkFloat value, StkFloat min, StkFloat max ) { f@0: if ( value < min ) return false; f@0: else if ( value > max ) return false; f@0: else return true; f@0: } f@0: f@0: //! Static function for error reporting and handling using c-strings. f@0: static void handleError( const char *message, StkError::Type type ); f@0: f@0: //! Static function for error reporting and handling using c++ strings. f@0: static void handleError( std::string message, StkError::Type type ); f@0: f@0: //! Toggle display of WARNING and STATUS messages. f@0: static void showWarnings( bool status ) { showWarnings_ = status; } f@0: f@0: //! Toggle display of error messages before throwing exceptions. f@0: static void printErrors( bool status ) { printErrors_ = status; } f@0: f@0: private: f@0: static StkFloat srate_; f@0: static std::string rawwavepath_; f@0: static bool showWarnings_; f@0: static bool printErrors_; f@0: static std::vector alertList_; f@0: f@0: protected: f@0: f@0: static std::ostringstream oStream_; f@0: bool ignoreSampleRateChange_; f@0: f@0: //! Default constructor. f@0: Stk( void ); f@0: f@0: //! Class destructor. f@0: virtual ~Stk( void ); f@0: f@0: //! This function should be implemented in subclasses that depend on the sample rate. f@0: virtual void sampleRateChanged( StkFloat newRate, StkFloat oldRate ); f@0: f@0: //! Add class pointer to list for sample rate change notification. f@0: void addSampleRateAlert( Stk *ptr ); f@0: f@0: //! Remove class pointer from list for sample rate change notification. f@0: void removeSampleRateAlert( Stk *ptr ); f@0: f@0: //! Internal function for error reporting that assumes message in \c oStream_ variable. f@0: void handleError( StkError::Type type ) const; f@0: }; f@0: f@0: f@0: /***************************************************/ f@0: /*! \class StkFrames f@0: \brief An STK class to handle vectorized audio data. f@0: f@0: This class can hold single- or multi-channel audio data. The data f@0: type is always StkFloat and the channel format is always f@0: interleaved. In an effort to maintain efficiency, no f@0: out-of-bounds checks are performed in this class unless f@0: _STK_DEBUG_ is defined. f@0: f@0: Internally, the data is stored in a one-dimensional C array. An f@0: indexing operator is available to set and retrieve data values. f@0: Alternately, one can use pointers to access the data, using the f@0: index operator to get an address for a particular location in the f@0: data: f@0: f@0: StkFloat* ptr = &myStkFrames[0]; f@0: f@0: Note that this class can also be used as a table with interpolating f@0: lookup. f@0: f@0: Possible future improvements in this class could include functions f@0: to convert to and return other data types. f@0: f@0: by Perry R. Cook and Gary P. Scavone, 1995--2014. f@0: */ f@0: /***************************************************/ f@0: f@0: class StkFrames f@0: { f@0: public: f@0: f@0: //! The default constructor initializes the frame data structure to size zero. f@0: StkFrames( unsigned int nFrames = 0, unsigned int nChannels = 0 ); f@0: f@0: //! Overloaded constructor that initializes the frame data to the specified size with \c value. f@0: StkFrames( const StkFloat& value, unsigned int nFrames, unsigned int nChannels ); f@0: f@0: //! The destructor. f@0: ~StkFrames(); f@0: f@0: // A copy constructor. f@0: StkFrames( const StkFrames& f ); f@0: f@0: // Assignment operator that returns a reference to self. f@0: StkFrames& operator= ( const StkFrames& f ); f@0: f@0: //! Subscript operator that returns a reference to element \c n of self. f@0: /*! f@0: The result can be used as an lvalue. This reference is valid f@0: until the resize function is called or the array is destroyed. The f@0: index \c n must be between 0 and size less one. No range checking f@0: is performed unless _STK_DEBUG_ is defined. f@0: */ f@0: StkFloat& operator[] ( size_t n ); f@0: f@0: //! Subscript operator that returns the value at element \c n of self. f@0: /*! f@0: The index \c n must be between 0 and size less one. No range f@0: checking is performed unless _STK_DEBUG_ is defined. f@0: */ f@0: StkFloat operator[] ( size_t n ) const; f@0: f@0: //! Assignment by sum operator into self. f@0: /*! f@0: The dimensions of the argument are expected to be the same as f@0: self. No range checking is performed unless _STK_DEBUG_ is f@0: defined. f@0: */ f@0: void operator+= ( StkFrames& f ); f@0: f@0: //! Assignment by product operator into self. f@0: /*! f@0: The dimensions of the argument are expected to be the same as f@0: self. No range checking is performed unless _STK_DEBUG_ is f@0: defined. f@0: */ f@0: void operator*= ( StkFrames& f ); f@0: f@0: //! Channel / frame subscript operator that returns a reference. f@0: /*! f@0: The result can be used as an lvalue. This reference is valid f@0: until the resize function is called or the array is destroyed. The f@0: \c frame index must be between 0 and frames() - 1. The \c channel f@0: index must be between 0 and channels() - 1. No range checking is f@0: performed unless _STK_DEBUG_ is defined. f@0: */ f@0: StkFloat& operator() ( size_t frame, unsigned int channel ); f@0: f@0: //! Channel / frame subscript operator that returns a value. f@0: /*! f@0: The \c frame index must be between 0 and frames() - 1. The \c f@0: channel index must be between 0 and channels() - 1. No range checking f@0: is performed unless _STK_DEBUG_ is defined. f@0: */ f@0: StkFloat operator() ( size_t frame, unsigned int channel ) const; f@0: f@0: //! Return an interpolated value at the fractional frame index and channel. f@0: /*! f@0: This function performs linear interpolation. The \c frame f@0: index must be between 0.0 and frames() - 1. The \c channel index f@0: must be between 0 and channels() - 1. No range checking is f@0: performed unless _STK_DEBUG_ is defined. f@0: */ f@0: StkFloat interpolate( StkFloat frame, unsigned int channel = 0 ) const; f@0: f@0: //! Returns the total number of audio samples represented by the object. f@0: size_t size() const { return size_; }; f@0: f@0: //! Returns \e true if the object size is zero and \e false otherwise. f@0: bool empty() const; f@0: f@0: //! Resize self to represent the specified number of channels and frames. f@0: /*! f@0: Changes the size of self based on the number of frames and f@0: channels. No element assignment is performed. No memory f@0: deallocation occurs if the new size is smaller than the previous f@0: size. Further, no new memory is allocated when the new size is f@0: smaller or equal to a previously allocated size. f@0: */ f@0: void resize( size_t nFrames, unsigned int nChannels = 1 ); f@0: f@0: //! Resize self to represent the specified number of channels and frames and perform element initialization. f@0: /*! f@0: Changes the size of self based on the number of frames and f@0: channels, and assigns \c value to every element. No memory f@0: deallocation occurs if the new size is smaller than the previous f@0: size. Further, no new memory is allocated when the new size is f@0: smaller or equal to a previously allocated size. f@0: */ f@0: void resize( size_t nFrames, unsigned int nChannels, StkFloat value ); f@0: f@0: //! Return the number of channels represented by the data. f@0: unsigned int channels( void ) const { return nChannels_; }; f@0: f@0: //! Return the number of sample frames represented by the data. f@0: unsigned int frames( void ) const { return (unsigned int)nFrames_; }; f@0: f@0: //! Set the sample rate associated with the StkFrames data. f@0: /*! f@0: By default, this value is set equal to the current STK sample f@0: rate at the time of instantiation. f@0: */ f@0: void setDataRate( StkFloat rate ) { dataRate_ = rate; }; f@0: f@0: //! Return the sample rate associated with the StkFrames data. f@0: /*! f@0: By default, this value is set equal to the current STK sample f@0: rate at the time of instantiation. f@0: */ f@0: StkFloat dataRate( void ) const { return dataRate_; }; f@0: f@0: private: f@0: f@0: StkFloat *data_; f@0: StkFloat dataRate_; f@0: size_t nFrames_; f@0: unsigned int nChannels_; f@0: size_t size_; f@0: size_t bufferSize_; f@0: f@0: }; f@0: f@0: inline bool StkFrames :: empty() const f@0: { f@0: if ( size_ > 0 ) return false; f@0: else return true; f@0: } f@0: f@0: inline StkFloat& StkFrames :: operator[] ( size_t n ) f@0: { f@0: #if defined(_STK_DEBUG_) f@0: if ( n >= size_ ) { f@0: std::ostringstream error; f@0: error << "StkFrames::operator[]: invalid index (" << n << ") value!"; f@0: Stk::handleError( error.str(), StkError::MEMORY_ACCESS ); f@0: } f@0: #endif f@0: f@0: return data_[n]; f@0: } f@0: f@0: inline StkFloat StkFrames :: operator[] ( size_t n ) const f@0: { f@0: #if defined(_STK_DEBUG_) f@0: if ( n >= size_ ) { f@0: std::ostringstream error; f@0: error << "StkFrames::operator[]: invalid index (" << n << ") value!"; f@0: Stk::handleError( error.str(), StkError::MEMORY_ACCESS ); f@0: } f@0: #endif f@0: f@0: return data_[n]; f@0: } f@0: f@0: inline StkFloat& StkFrames :: operator() ( size_t frame, unsigned int channel ) f@0: { f@0: #if defined(_STK_DEBUG_) f@0: if ( frame >= nFrames_ || channel >= nChannels_ ) { f@0: std::ostringstream error; f@0: error << "StkFrames::operator(): invalid frame (" << frame << ") or channel (" << channel << ") value!"; f@0: Stk::handleError( error.str(), StkError::MEMORY_ACCESS ); f@0: } f@0: #endif f@0: f@0: return data_[ frame * nChannels_ + channel ]; f@0: } f@0: f@0: inline StkFloat StkFrames :: operator() ( size_t frame, unsigned int channel ) const f@0: { f@0: #if defined(_STK_DEBUG_) f@0: if ( frame >= nFrames_ || channel >= nChannels_ ) { f@0: std::ostringstream error; f@0: error << "StkFrames::operator(): invalid frame (" << frame << ") or channel (" << channel << ") value!"; f@0: Stk::handleError( error.str(), StkError::MEMORY_ACCESS ); f@0: } f@0: #endif f@0: f@0: return data_[ frame * nChannels_ + channel ]; f@0: } f@0: f@0: inline void StkFrames :: operator+= ( StkFrames& f ) f@0: { f@0: #if defined(_STK_DEBUG_) f@0: if ( f.frames() != nFrames_ || f.channels() != nChannels_ ) { f@0: std::ostringstream error; f@0: error << "StkFrames::operator+=: frames argument must be of equal dimensions!"; f@0: Stk::handleError( error.str(), StkError::MEMORY_ACCESS ); f@0: } f@0: #endif f@0: f@0: StkFloat *fptr = &f[0]; f@0: StkFloat *dptr = data_; f@0: for ( unsigned int i=0; i