Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/WavFileSource2.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 "WavFileSource2.h"
00020 
00021 using namespace std;
00022 using namespace Marsyas;
00023 
00024 WavFileSource2::WavFileSource2(mrs_string name):AbsSoundFileSource2("WavFileSource2",name)
00025 {
00026   sdata_ = NULL;
00027   cdata_ = NULL;
00028   sfp_ = NULL;
00029 
00030   addControls();
00031 }
00032 
00033 WavFileSource2::~WavFileSource2()
00034 {
00035   delete [] sdata_;
00036   delete [] cdata_;
00037   if (sfp_ != NULL)
00038     fclose(sfp_);
00039 }
00040 
00041 WavFileSource2::WavFileSource2(const WavFileSource2& a):AbsSoundFileSource2(a) //[!][?]
00042 {
00043   sdata_ = NULL;
00044   cdata_ = NULL;
00045   sfp_ = NULL;
00046 }
00047 
00048 MarSystem*
00049 WavFileSource2::clone() const
00050 {
00051   return new WavFileSource2(*this); //shouldn't this class have a copy constructor?!? [?][!]
00052 }
00053 
00054 void
00055 WavFileSource2::addControls()
00056 {
00057   setctrl("mrs_string/filetype", "wav");
00058 }
00059 
00060 void
00061 WavFileSource2::hdrError()
00062 {
00063   setctrl("mrs_natural/nChannels", (mrs_natural)1);
00064   setctrl("mrs_real/israte", MRS_DEFAULT_SLICE_SRATE);//(mrs_real)22050.0);
00065   setctrl("mrs_natural/size", (mrs_natural)0);
00066   setctrl("mrs_bool/hasData", false);
00067   setctrl("mrs_string/filename", string());
00068 }
00069 
00070 bool
00071 WavFileSource2::getHeader()
00072 {
00073   unsigned short channels, srate;
00074   mrs_natural size;
00075 
00076   mrs_string filename = getctrl("mrs_string/filename")->to<mrs_string>();
00077   //if an empty filename, return error and default configuration
00078   if(filename.empty())
00079   {
00080     MRSERR("WavFileSource2::getHeader: empty FileName");
00081     hdrError();
00082     return false;
00083   }
00084 
00085   sfp_ = fopen(filename.c_str(), "rb");
00086   if (sfp_)
00087   {
00088     char magic[5];
00089 
00090     fseek(sfp_, 8, SEEK_SET); // Locate wave id
00091     if (fread(magic, 4, 1, sfp_) == 0)
00092     {
00093       MRSERR("WavFileSource2::getHeader: File " + filename + " is empty ");
00094       hdrError();
00095       return false;
00096     }
00097     magic[4] = '\0';
00098 
00099     if (strcmp(magic, "WAVE"))
00100     {
00101       MRSWARN("WavFileSource2::getHeader: Filename " + filename + " is not correct .wav file \n or has settings that are not supported in Marsyas");
00102       hdrError();
00103       return false;
00104     }
00105     else
00106     {
00107       char id[5];
00108       int chunkSize;
00109       if (fread(id, 4, 1, sfp_) != 1) {
00110         MRSERR("Error reading wav file");
00111       }
00112       id[4] = '\0';
00113 
00114       while (strcmp(id, "fmt "))
00115       {
00116         if (fread(&chunkSize, 4, 1, sfp_) != 1) {
00117           MRSERR("Error reading wav file");
00118         }
00119 #if defined(MARSYAS_BIGENDIAN)
00120         chunkSize = ByteSwapLong(chunkSize);
00121 #endif
00122         fseek(sfp_, chunkSize, SEEK_CUR);
00123         if (fread(id, 4, 1, sfp_) != 1) {
00124           MRSERR("Error reading wav file");
00125         }
00126       }
00127 
00128       if (fread(&chunkSize, 4, 1, sfp_) != 1) {
00129         MRSERR("Error reading wav file");
00130       }
00131 #if defined(MARSYAS_BIGENDIAN)
00132       chunkSize = ByteSwapLong(chunkSize);
00133 #endif
00134 
00135       unsigned short format_tag;
00136       if (fread(&format_tag, 2, 1, sfp_) != 1) {
00137         MRSERR("Error reading wav file");
00138       }
00139 #if defined(MARSYAS_BIGENDIAN)
00140       format_tag = ByteSwapShort(format_tag);
00141 #endif
00142       if (format_tag != 1)
00143       {
00144         fclose(sfp_);
00145         MRSWARN("WavFileSource2::getHeader: Non pcm(compressed) wave files are not supported");
00146         hdrError();
00147         return false;
00148       }
00149 
00150       // Get number of channels
00151       if (fread(&channels, 2, 1, sfp_) != 1) {
00152         MRSERR("Error reading wav file");
00153       }
00154 #if defined(MARSYAS_BIGENDIAN)
00155       channels = ByteSwapShort(channels);
00156 #endif
00157       // access directly controls to avoid update() recursion
00158       setctrl("mrs_natural/nChannels", (mrs_natural)channels);
00159       //nChannels_ = channels; //getctrl("mrs_natural/nChannels")->to<mrs_natural>();//[!]
00160 
00161       if (fread(&srate, 2, 1, sfp_) != 1) {
00162         MRSERR("Error reading wav file");
00163       }
00164 #if defined(MARSYAS_BIGENDIAN)
00165       srate = ByteSwapShort(srate);
00166 #endif
00167       setctrl("mrs_real/israte", (mrs_real)srate);
00168       //israte_ = (mrs_real)srate;
00169 
00170       fseek(sfp_,8,SEEK_CUR);
00171       if (fread(&bits_, 2, 1, sfp_) != 1) {
00172         MRSERR("Error reading wav file");
00173       }
00174 #if defined(MARSYAS_BIGENDIAN)
00175       bits_ = ByteSwapShort(bits_);
00176 #endif
00177       if ((bits_ != 16))//&&(bits_ != 8))
00178       {
00179         fclose(sfp_);
00180         //MRSWARN("WavFileSource2::getHeader: WavFileSource2::Only linear 8-bit and 16-bit samples are supported ");
00181         MRSWARN("WavFileSource2::getHeader: WavFileSource2::Only linear 16-bit samples are supported for now...");
00182         hdrError();
00183         return false;
00184       }
00185 
00186       fseek(sfp_, chunkSize - 16, SEEK_CUR);
00187       if (fread(id, 4, 1, sfp_) != 1) {
00188         MRSERR("Error reading wav file");
00189       }
00190       id[4] = '\0';
00191       while (strcmp(id, "data"))
00192       {
00193         if (fread(&chunkSize, 4, 1, sfp_) != 1) {
00194           MRSERR("Error reading wav file");
00195         }
00196 #if defined(MARSYAS_BIGENDIAN)
00197         chunkSize = ByteSwapLong(chunkSize);
00198 #endif
00199         fseek(sfp_,chunkSize,SEEK_CUR);
00200         if (fread(&id,4,1,sfp_) != 1) {
00201           MRSERR("Error reading wav file");
00202         }
00203       }
00204 
00205       int bytes;
00206       if (fread(&bytes, 4, 1, sfp_) != 1) {
00207         MRSERR("Error reading wav file");
00208       }
00209 #if defined(MARSYAS_BIGENDIAN)
00210       bytes = ByteSwapLong(bytes);
00211 #endif
00212       //size in number of samples per channel
00213       size = bytes / (bits_ / 8)/ channels;
00214       setctrl("mrs_natural/size", size);
00215 
00216       sfp_begin_ = ftell(sfp_);
00217 
00218       //check if there is in fact any audio data in the soundfile
00219       if(size > 0)
00220         setctrl("mrs_bool/hasData", true);
00221       else
00222         setctrl("mrs_bool/hasData", false);
00223     }
00224   }
00225   else
00226   {
00227     hdrError();
00228     return false;
00229   }
00230 
00231   return true;
00232 }
00233 
00234 void
00235 WavFileSource2::myUpdate(MarControlPtr sender)
00236 {
00237   (void) sender;  //suppress warning of unused parameter(s)
00238   //if not a new audiofile, no need to read header again
00239   mrs_string filename = getctrl("mrs_string/filename")->to<mrs_string>();
00240   if(filename_ != filename)
00241   {
00242     getHeader();//sets controls filename, nChannels, israte and size
00243     filename_ = getctrl("mrs_string/filename")->to<mrs_string>();
00244     nChannels_ = getctrl("mrs_natural/nChannels")->to<mrs_natural>();
00245     israte_ = getctrl("mrs_real/israte")->to<mrs_real>();
00246     size_ = getctrl("mrs_natural/size")->to<mrs_natural>();
00247   }
00248 
00249   //update internal vars
00250   inSamples_ = getctrl("mrs_natural/inSamples")->to<mrs_natural>();
00251   osrate_ = israte_;
00252 
00253   //update output pin config
00254   setctrl("mrs_natural/onSamples", inSamples_);
00255   setctrl("mrs_natural/onObservations", nChannels_);
00256   setctrl("mrs_real/osrate", osrate_);
00257 
00258   //update internal buffers
00259   delete [] sdata_;
00260   delete [] cdata_;
00261   sdata_ = new short[inSamples_ * nChannels_];
00262   cdata_ = new unsigned char[inSamples_ * nChannels_];
00263 
00264   samplesToRead_ = inSamples_ * nChannels_;
00265 
00266   //observation's names
00267   ostringstream oss;
00268   for (mrs_natural i = 0; i < nChannels_; ++i)
00269     oss << "audio_ch_" << i+1 << ",";
00270   setctrl("mrs_string/onObsNames", oss.str());
00271 }
00272 
00273 // mrs_natural
00274 // WavFileSource2::getLinear8(mrs_natural c, realvec& slice)//this does not seem to be working!!! [!][?]
00275 // {
00276 //  mrs_natural nChannels = getctrl("nChannels")->to<mrs_natural>();
00277 //  mrs_natural inSamples = getctrl("mrs_natural/inSamples")->to<mrs_natural>();
00278 //
00279 //  samplesToRead_ = inSamples * nChannels;
00280 //
00281 //  // only read data when called for first channel
00282 //  if (c == 0)
00283 //  {
00284 //      samplesRead_ = (mrs_natural)fread(cdata_, sizeof(unsigned char), samplesToRead_, sfp_);
00285 //  }
00286 //  if (samplesRead_ != samplesToRead_)
00287 //  {
00288 //      for (t=0; t < inSamples; t++)
00289 //      {
00290 //          slice(0,t) = 0.0;
00291 //      }
00292 //  }
00293 //  for (t=0; t < inSamples; t++)
00294 //  {
00295 //      slice(0, t) = (mrs_real)-1.0 + (mrs_real) cdata_[nChannels * t + c] / 128;
00296 //  }
00297 //
00298 //  pos_ += samplesToRead_;
00299 //  return pos_;
00300 // }
00301 
00302 unsigned long
00303 WavFileSource2::ByteSwapLong(unsigned long nLongNumber)
00304 {
00305   return (((nLongNumber&0x000000FF)<<24)+((nLongNumber&0x0000FF00)<<8)+
00306           ((nLongNumber&0x00FF0000)>>8)+((nLongNumber&0xFF000000)>>24));
00307 }
00308 
00309 unsigned short
00310 WavFileSource2::ByteSwapShort (unsigned short nValue)
00311 {
00312   return (static_cast<unsigned short>((nValue & 0xff00) >> 8) |
00313           static_cast<unsigned short>((nValue & 0xff) << 8));
00314 }
00315 
00316 mrs_natural
00317 WavFileSource2::getLinear16(realvec& slice)
00318 {
00319   mrs_natural c,t;
00320   mrs_natural pos = getctrl("mrs_natural/pos")->to<mrs_natural>();
00321 
00322   fseek(sfp_, 2 * pos * nChannels_ + sfp_begin_, SEEK_SET);
00323 
00324   samplesToRead_ = inSamples_ * nChannels_;
00325 
00326   samplesRead_ = (mrs_natural)fread(sdata_, sizeof(short), samplesToRead_, sfp_);
00327 
00328   if (samplesRead_ != samplesToRead_)
00329   {
00330     samplesToWrite_ = samplesRead_ / nChannels_;
00331     for (c=0; c < nChannels_; ++c)
00332       //only fill remaining space with zeros => faster
00333       for(t = samplesToWrite_; t < inSamples_; t++)
00334       {
00335         slice(c, t) = 0.0;
00336       }
00337   }
00338   else
00339     samplesToWrite_ = inSamples_;
00340 
00341   for (t=0; t < samplesToWrite_; t++)
00342   {
00343     sval_ = 0;
00344 #if defined(MARSYAS_BIGENDIAN)
00345     for (c=0; c < nChannels_; ++c)
00346     {
00347       sval_ = ByteSwapShort(sdata_[nChannels_*t + c]);
00348       slice(c, t) = (mrs_real) sval_ / (PCM_FMAXSHRT);
00349     }
00350 #else
00351     for (c=0; c < nChannels_; ++c)
00352     {
00353       sval_ = sdata_[nChannels_ *t + c];
00354       slice(c, t) = ((mrs_real) sval_ / (PCM_FMAXSHRT));
00355     }
00356 #endif
00357   }
00358 
00359   //update play position
00360   pos += samplesToWrite_;
00361   setctrl("mrs_natural/pos", pos);
00362   return pos;
00363 }
00364 
00365 realvec&
00366 WavFileSource2::getAudioRegion(mrs_natural startSample, mrs_natural endSample)
00367 {
00368   (void) startSample; // FIXME Unused parameters
00369   (void) endSample;
00370 
00371   //fill audioRegion_ with corresponding audio data!
00372   // ...
00373   // ...
00374 
00375   return audioRegion_;
00376 }
00377 
00378 void
00379 WavFileSource2::myProcess(realvec& in, realvec& out)
00380 {
00381   (void) in;
00382   //in case of problems opening the .wav file,
00383   //or no audiodata available to read, just send silence
00384   if(!getctrl("mrs_bool/hasData")->to<mrs_bool>())
00385   {
00386     out.setval(0.0);
00387     return;
00388   }
00389 
00390   switch(bits_)
00391   {
00392   case 16:
00393   {
00394     //read audio samples from .wav file
00395     getLinear16(out);
00396     break;
00397   }
00398   case 8:
00399   {
00400     //getLinear8(out); [!]
00401     break;
00402   }
00403   }
00404 
00405   //if reached end of file, signal it!
00406   if(getctrl("mrs_natural/pos")->to<mrs_natural>() >= size_)
00407     setctrl("mrs_bool/hasData", false);
00408 }
00409 
00410 
00411 
00412 
00413 
00414 
00415 
00416 
00417 
00418 
00419 
00420 
00421 
00422 
00423 
00424 
00425