/***************************************************/ /*! \class FileWvIn \brief STK audio file input class. This class inherits from WvIn. It provides a "tick-level" interface to the FileRead class. It also provides variable-rate playback functionality. Audio file support is provided by the FileRead class. Linear interpolation is used for fractional read rates. FileWvIn supports multi-channel data. It is important to distinguish the tick() method that computes a single frame (and returns only the specified sample of a multi-channel frame) from the overloaded one that takes an StkFrames object for multi-channel and/or multi-frame data. FileWvIn will either load the entire content of an audio file into local memory or incrementally read file data from disk in chunks. This behavior is controlled by the optional constructor arguments \e chunkThreshold and \e chunkSize. File sizes greater than \e chunkThreshold (in sample frames) will be read incrementally in chunks of \e chunkSize each (also in sample frames). When the file end is reached, subsequent calls to the tick() functions return zeros and isFinished() returns \e true. See the FileRead class for a description of the supported audio file formats. by Perry R. Cook and Gary P. Scavone, 1995--2014. */ /***************************************************/ #include "FileWvIn.h" #include namespace stk { FileWvIn :: FileWvIn( unsigned long chunkThreshold, unsigned long chunkSize ) : finished_(true), interpolate_(false), time_(0.0), rate_(0.0), chunkThreshold_(chunkThreshold), chunkSize_(chunkSize) { Stk::addSampleRateAlert( this ); } FileWvIn :: FileWvIn( std::string fileName, bool raw, bool doNormalize, unsigned long chunkThreshold, unsigned long chunkSize ) : finished_(true), interpolate_(false), time_(0.0), rate_(0.0), chunkThreshold_(chunkThreshold), chunkSize_(chunkSize) { openFile( fileName, raw, doNormalize ); Stk::addSampleRateAlert( this ); } FileWvIn :: ~FileWvIn() { this->closeFile(); Stk::removeSampleRateAlert( this ); } void FileWvIn :: sampleRateChanged( StkFloat newRate, StkFloat oldRate ) { if ( !ignoreSampleRateChange_ ) this->setRate( oldRate * rate_ / newRate ); } void FileWvIn :: closeFile( void ) { if ( file_.isOpen() ) file_.close(); finished_ = true; lastFrame_.resize( 0, 0 ); } void FileWvIn :: openFile( std::string fileName, bool raw, bool doNormalize ) { // Call close() in case another file is already open. this->closeFile(); // Attempt to open the file ... an error might be thrown here. file_.open( fileName, raw ); // Determine whether chunking or not. if ( file_.fileSize() > chunkThreshold_ ) { chunking_ = true; chunkPointer_ = 0; data_.resize( chunkSize_, file_.channels() ); if ( doNormalize ) normalizing_ = true; else normalizing_ = false; } else { chunking_ = false; data_.resize( (size_t) file_.fileSize(), file_.channels() ); } // Load all or part of the data. file_.read( data_, 0, doNormalize ); // Resize our lastFrame container. lastFrame_.resize( 1, file_.channels() ); // Set default rate based on file sampling rate. this->setRate( data_.dataRate() / Stk::sampleRate() ); if ( doNormalize & !chunking_ ) this->normalize(); this->reset(); } void FileWvIn :: reset(void) { time_ = (StkFloat) 0.0; for ( unsigned int i=0; inormalize( 1.0 ); } // Normalize all channels equally by the greatest magnitude in all of the data. void FileWvIn :: normalize( StkFloat peak ) { // When chunking, the "normalization" scaling is performed by FileRead. if ( chunking_ ) return; size_t i; StkFloat max = 0.0; for ( i=0; i max ) max = (StkFloat) fabs((double) data_[i]); } if ( max > 0.0 ) { max = 1.0 / max; max *= peak; for ( i=0; i file_.fileSize() - 1.0 ) { time_ = file_.fileSize() - 1.0; for ( unsigned int i=0; i= data_.channels() ) { oStream_ << "FileWvIn::tick(): channel argument and soundfile data are incompatible!"; handleError( StkError::FUNCTION_ARGUMENT ); } #endif if ( finished_ ) return 0.0; if ( time_ < 0.0 || time_ > (StkFloat) ( file_.fileSize() - 1.0 ) ) { for ( unsigned int i=0; i (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) ) { while ( time_ < (StkFloat) chunkPointer_ ) { // negative rate chunkPointer_ -= chunkSize_ - 1; // overlap chunks by one frame if ( chunkPointer_ < 0 ) chunkPointer_ = 0; } while ( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) { // positive rate chunkPointer_ += chunkSize_ - 1; // overlap chunks by one frame if ( chunkPointer_ + chunkSize_ > file_.fileSize() ) // at end of file chunkPointer_ = file_.fileSize() - chunkSize_; } // Load more data. file_.read( data_, chunkPointer_, normalizing_ ); } // Adjust index for the current buffer. tyme -= chunkPointer_; } if ( interpolate_ ) { for ( unsigned int i=0; i frames.channels() - nChannels ) { oStream_ << "FileWvIn::tick(): channel and StkFrames arguments are incompatible!"; handleError( StkError::FUNCTION_ARGUMENT ); } #endif StkFloat *samples = &frames[channel]; unsigned int j, hop = frames.channels() - nChannels; if ( nChannels == 1 ) { for ( unsigned int i=0; i