Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/RawFileSource.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2010 George Tzanetakis <gtzan@cs.uvic.ca>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "RawFileSource.h"
00020 
00021 using namespace std;
00022 using namespace Marsyas;
00023 
00024 RawFileSource::RawFileSource(mrs_string name):AbsSoundFileSource("RawFileSource", name)
00025 {
00026   sfp_ = NULL;
00027   buffer_ = NULL;
00028 
00029   phaseOffset_ = 0.0;
00030   bufferSize_ = 0;
00031   time_ = 0.0;
00032 
00033   hasData_ = true;
00034 
00035   addControls();
00036 }
00037 
00038 RawFileSource::~RawFileSource()
00039 {
00040   if (sfp_ != NULL)
00041     fclose(sfp_);
00042 
00043   delete [] buffer_;
00044 
00045 }
00046 
00047 MarSystem* RawFileSource::clone() const
00048 {
00049   return new RawFileSource(*this);//[?] copy constructor?!?
00050 }
00051 
00052 void
00053 RawFileSource::addControls()
00054 {
00055   addctrl("mrs_natural/nChannels",1);
00056   addctrl("mrs_real/frequency",440.0);
00057   setctrlState("mrs_real/frequency",true);
00058   addctrl("mrs_natural/size", 0);
00059   addctrl("mrs_natural/pos", 0);
00060   setctrlState("mrs_natural/pos", true);
00061   addctrl("mrs_bool/hasData", true);
00062   addctrl("mrs_bool/noteon", false);
00063   setctrlState("mrs_bool/noteon", true);
00064   addctrl("mrs_string/filetype", "raw");
00065   addctrl("mrs_bool/currentHasData", true, ctrl_currentHasData_);
00066 }
00067 
00068 
00069 void RawFileSource::openFile(mrs_string filename)
00070 {
00071   getHeader(filename);
00072   rate_ = fileSize_ * getctrl("mrs_real/frequency")->to<mrs_real>() / getctrl("mrs_real/israte")->to<mrs_real>();
00073 }
00074 
00075 
00076 // get file data info from the raw file
00077 bool RawFileSource::getRawInfo( const char *fileName )
00078 {
00079   // Use the system call "stat" to determine the file length.
00080   struct stat filestat;
00081   if ( stat(fileName, &filestat) == -1 ) {
00082     return false;
00083   }
00084 
00085   // length in 2-byte samples
00086   fileSize_ = (mrs_natural) filestat.st_size / 2;
00087   bufferSize_ = fileSize_;
00088 
00089   // assume little endian for now
00090   byteSwap_ = true;
00091 
00092   return true;
00093 }
00094 
00095 //
00096 // STK raw files don't have a header, so just open the file and get info
00097 //
00098 void RawFileSource::getHeader(mrs_string fileName)
00099 {
00100 
00101   sfp_ = fopen(fileName.c_str(), "raw");
00102   if (sfp_ == NULL) {
00103     MRSWARN("Could not open file: " + fileName);
00104     return;
00105   }
00106 
00107   bool result = getRawInfo( fileName.c_str() );
00108   if ( ! result ) {
00109     MRSWARN("Could not get raw data information from file: " + fileName);
00110     return;
00111   }
00112 
00113   // allocate storage for the buffer
00114   mrs_natural samples = (bufferSize_+1)* getctrl("mrs_natural/nChannels")->to<mrs_natural>();
00115   data_.create(samples);
00116 
00117   if(buffer_)
00118     delete [] buffer_;
00119   buffer_ = new short[bufferSize_];
00120 
00121   // now read the data into our buffer (data_[]).
00122   readData(0);
00123 }
00124 
00125 
00126 void RawFileSource::swap16(unsigned char *ptr)
00127 {
00128   register unsigned char val;
00129 
00130   // Swap 1st and 2nd bytes
00131   val = *(ptr);
00132   *(ptr) = *(ptr+1);
00133   *(ptr+1) = val;
00134 }
00135 
00136 
00137 //
00138 // read all the raw data into data[]
00139 //
00140 void RawFileSource::readData(unsigned long index)//[!]
00141 {
00142   mrs_natural i;
00143   mrs_natural length = bufferSize_;
00144 
00145   // Read samples into data[].
00146   if (fseek(sfp_, index, SEEK_SET) == -1) {
00147     MRSWARN("ERROR(fseek): could not read raw file data.");
00148     return;
00149   }
00150 
00151   if (fread(buffer_, length, 2, sfp_) != 2 ) {
00152     MRSWARN("ERROR(fread): could not read raw file data");
00153     return;
00154   }
00155 
00156   // if we are on a little endian machine.
00157   byteSwap_ = true;
00158   if ( byteSwap_ ) {
00159     short* ptr = buffer_;
00160     for ( i=length; i>=0; i-- )
00161       swap16((unsigned char *)(ptr++));
00162   }
00163 
00164   for ( i=length-1; i>=0; i-- ) {
00165     data_(i) = buffer_[i];
00166   }
00167 
00168   // repeat last sample frame for interpolation
00169   data_(length) = data_(length-1);
00170 
00171   // find the peak
00172   mrs_real max = 0.0;
00173   for (i=0; i < length; ++i) {
00174     if (fabs(data_(i)) > max)
00175       max = (mrs_real) fabs((double) data_(i));
00176   }
00177 
00178   // now normalize according to the peak.
00179   if (max > 0.0) {
00180     max = (mrs_real)(1.0 / max);
00181     max *= 1.0;                 // constant factor for now.
00182     for ( i=0; i <= length; ++i )  {
00183       data_(i) *= max;
00184     }
00185   }
00186 
00187 }
00188 
00189 void RawFileSource::myUpdate(MarControlPtr sender)
00190 {
00191   (void) sender;  //suppress warning of unused parameter(s)
00192 
00193   nChannels_ = getctrl("mrs_natural/nChannels")->to<mrs_natural>();
00194   inSamples_ = getctrl("mrs_natural/inSamples")->to<mrs_natural>();
00195   inObservations_ = getctrl("mrs_natural/inObservations")->to<mrs_natural>();
00196   israte_ = getctrl("mrs_real/israte")->to<mrs_real>();
00197 
00198   setctrl("mrs_natural/onSamples", inSamples_);
00199   setctrl("mrs_natural/onObservations", inObservations_);
00200   setctrl("mrs_real/osrate", israte_);
00201 
00202   pos_ = getctrl("mrs_natural/pos")->to<mrs_natural>();
00203 
00204   rate_ = fileSize_ * getctrl("mrs_real/frequency")->to<mrs_real>() / israte_;
00205 }
00206 
00207 
00208 void RawFileSource::myProcess(realvec& in,realvec &out)
00209 {
00210   (void) in;
00211   //checkFlow(in,out);
00212 
00213   mrs_real alpha;
00214   mrs_natural i, index;
00215 
00216   if (!getctrl("mrs_bool/noteon")->isTrue()) {
00217     return;
00218   }
00219 
00220   for (i = 0; i < inSamples_; ++i ) {
00221 
00222     // loop back to start of the wavetable
00223     if (time_ >= fileSize_) {
00224       time_ -= fileSize_;
00225     }
00226 
00227     // linear interpolation
00228     index = (mrs_natural) time_;
00229     alpha = time_ - (mrs_real) index;           // fractional part of time address
00230     out(0,i) = data_(index);
00231     out(0,i) += (alpha * (data_(index+1) - data_(index)));
00232 
00233     time_ += rate_;
00234 
00235   }
00236   ctrl_currentHasData_->setValue(hasData_);
00237 }