Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/AuFileSource.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2011 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 
00020 #include "../common_source.h"
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 #include "AuFileSource.h"
00029 
00030 
00031 #ifdef MARSYAS_WIN32
00032 #ifndef MARSYAS_CYGWIN
00033 typedef __int32 int32_t;
00034 #endif
00035 #else
00036 #include <stdint.h>
00037 #endif
00038 
00039 #include <cstddef>
00040 
00041 using std::size_t;
00042 
00043 /********  NeXT/Sun Soundfile Header Struct   *******/
00044 struct Marsyas::snd_header
00045 {
00046   char pref[4];
00047   int32_t hdrLength;
00048   int32_t fileLength;
00049   int32_t mode;
00050   int32_t srate;
00051   int32_t channels;
00052   char comment[1024];
00053 };
00054 
00055 
00056 
00057 /* Array containing descriptions of
00058    the various formats for the samples
00059    of the Next .snd/ Sun .au format */
00060 
00061 
00062 using std::ostringstream;
00063 using namespace Marsyas;
00064 
00065 #define SND_MAGIC_NUM 0x2e736e64
00066 
00067 /* types of .snd files */
00068 #define SND_FORMAT_UNSPECIFIED 0
00069 #define SND_FORMAT_MULAW_8     1
00070 #define SND_FORMAT_LINEAR_8    2
00071 #define SND_FORMAT_LINEAR_16   3
00072 #define SND_FORMAT_LINEAR_24   4
00073 #define SND_FORMAT_LINEAR_32   5
00074 #define SND_FORMAT_FLOAT       6
00075 
00076 AuFileSource::AuFileSource(mrs_string name):AbsSoundFileSource("AuFileSource",name)
00077 {
00078   //type_ = "SoundFileSource";//"AuFileSource"?!?
00079   //name_ = name
00080 
00081   sdata_ = 0;
00082   cdata_ = 0;
00083   sfp_ = 0;
00084   pos_ =0;
00085   hdr_ = new snd_header;
00086   sndFormats_.push_back("Unspecified format");
00087   sndFormatSizes_.push_back(0);
00088   sndFormats_.push_back("Mulaw 8-bit");
00089   sndFormatSizes_.push_back(1);
00090   sndFormats_.push_back("Linear 8-bit");
00091   sndFormatSizes_.push_back(1);
00092   sndFormats_.push_back("Linear 16-bit");
00093   sndFormatSizes_.push_back(2);
00094   sndFormats_.push_back("Linear 24-bit");
00095   sndFormatSizes_.push_back(3);
00096   sndFormats_.push_back("Linear 32-bit");
00097   sndFormatSizes_.push_back(4);
00098   sndFormats_.push_back("Float");
00099   sndFormatSizes_.push_back(4);
00100   sndFormats_.push_back("Double");
00101   sndFormatSizes_.push_back(8);
00102 
00103   addControls();
00104 }
00105 
00106 AuFileSource::~AuFileSource()
00107 {
00108 
00109   delete [] sdata_;
00110   delete [] cdata_;
00111   delete hdr_;
00112 
00113   if (sfp_ != NULL)
00114     fclose(sfp_);
00115 }
00116 
00117 MarSystem*
00118 AuFileSource::clone() const
00119 {
00120   return new AuFileSource(*this);
00121 }
00122 
00123 
00124 AuFileSource::AuFileSource(const AuFileSource& a): AbsSoundFileSource(a)
00125 {
00126 
00127   ctrl_pos_ = getctrl("mrs_natural/pos");
00128   ctrl_size_ = getctrl("mrs_natural/size");
00129   ctrl_currentlyPlaying_ = getctrl("mrs_string/currentlyPlaying");
00130   ctrl_previouslyPlaying_ = getctrl("mrs_string/previouslyPlaying");
00131   ctrl_regression_ = getctrl("mrs_bool/regression");
00132   ctrl_currentLabel_ = getctrl("mrs_real/currentLabel");
00133   ctrl_previousLabel_ = getctrl("mrs_real/previousLabel");
00134   ctrl_nLabels_ = getctrl("mrs_natural/nLabels");
00135   ctrl_labelNames_ = getctrl("mrs_string/labelNames");
00136   ctrl_currentHasData_ = getctrl("mrs_bool/currentHasData");
00137   hdr_ = new snd_header;
00138 
00139 }
00140 
00141 
00142 
00143 
00144 void
00145 AuFileSource::addControls()
00146 {
00147   addctrl("mrs_bool/hasData", true);
00148   addctrl("mrs_bool/lastTickWithData", false);
00149 
00150   addctrl("mrs_natural/pos", (mrs_natural)0, ctrl_pos_);
00151   setctrlState("mrs_natural/pos", true);
00152 
00153   addctrl("mrs_natural/loopPos", (mrs_natural)0);
00154   setctrlState("mrs_natural/loopPos", true);
00155 
00156   addctrl("mrs_string/filename", "daufile");
00157   setctrlState("mrs_string/filename", true);
00158   addctrl("mrs_natural/size", (mrs_natural)0, ctrl_size_);
00159   addctrl("mrs_string/filetype", "au");
00160 
00161   addctrl("mrs_real/repetitions", 1.0);
00162   setctrlState("mrs_real/repetitions", true);
00163 
00164   addctrl("mrs_real/duration", -1.0);
00165   setctrlState("mrs_real/duration", true);
00166 
00167   addctrl("mrs_natural/advance", 0);
00168   setctrlState("mrs_natural/advance", true);
00169 
00170   addctrl("mrs_bool/shuffle", false);
00171   setctrlState("mrs_bool/shuffle", true);
00172 
00173   addctrl("mrs_natural/cindex", 0);
00174   setctrlState("mrs_natural/cindex", true);
00175 
00176   addctrl("mrs_string/allfilenames", ",");
00177   setctrlState("mrs_string/allfilenames", true);
00178   addctrl("mrs_natural/numFiles", 1);
00179 
00180   addctrl("mrs_string/currentlyPlaying", "daufile", ctrl_currentlyPlaying_);
00181   addctrl("mrs_string/previouslyPlaying", "daufile", ctrl_previouslyPlaying_);
00182   addctrl("mrs_bool/regression", false, ctrl_regression_);
00183   addctrl("mrs_real/currentLabel", 0.0, ctrl_currentLabel_);
00184   addctrl("mrs_real/previousLabel", 0.0, ctrl_previousLabel_);
00185   addctrl("mrs_natural/nLabels", 0, ctrl_nLabels_);
00186   addctrl("mrs_string/labelNames", ",", ctrl_labelNames_);
00187 
00188   addctrl("mrs_bool/currentHasData", true, ctrl_currentHasData_);
00189   addctrl("mrs_bool/currentLastTickWithData", false, ctrl_currentLastTickWithData_);
00190 }
00191 
00192 unsigned long
00193 AuFileSource::ByteSwapLong(unsigned long nLongNumber)
00194 {
00195   return (((nLongNumber&0x000000FF)<<24)+((nLongNumber&0x0000FF00)<<8)+
00196           ((nLongNumber&0x00FF0000)>>8)+((nLongNumber&0xFF000000)>>24));
00197 }
00198 
00199 unsigned short
00200 AuFileSource::ByteSwapShort (unsigned short nValue)
00201 {
00202   return (static_cast<unsigned short>((nValue & 0xff00) >> 8) |
00203           static_cast<unsigned short>((nValue & 0xff) << 8));
00204 }
00205 
00206 void
00207 AuFileSource::getHeader(mrs_string filename)
00208 {
00209   if (sfp_ != NULL)
00210     fclose(sfp_);
00211   sfp_ = fopen(filename.c_str(), "rb");
00212   if (sfp_)
00213   {
00214     size_t n = fread(hdr_, sizeof(snd_header), 1, sfp_);
00215     if ((n != 1) ||((hdr_->pref[0] != '.') &&(hdr_->pref[1] != 's')))
00216     {
00217       MRSWARN("Filename " + filename + " is not correct .au file \n or has settings that are not supported in Marsyas");
00218       setctrl("mrs_natural/onObservations", (mrs_natural)1);
00219       setctrl("mrs_real/israte", (mrs_real)22050.0);
00220       setctrl("mrs_natural/size", (mrs_natural)0);
00221       hasData_ = false;
00222       lastTickWithData_ = true;
00223       setctrl("mrs_bool/hasData", false);
00224       setctrl("mrs_bool/lastTickWithData", true);
00225     }
00226     else
00227     {
00228 #if defined(MARSYAS_BIGENDIAN)
00229       hdr_->hdrLength = hdr_->hdrLength;
00230       hdr_->comment[hdr_->hdrLength-24] = '\0';
00231       hdr_->srate = hdr_->srate;
00232       hdr_->channels = hdr_->channels;
00233       hdr_->mode = hdr_->mode;
00234       hdr_->fileLength = hdr_->fileLength;
00235 #else
00236       hdr_->hdrLength = ByteSwapLong(hdr_->hdrLength);
00237       hdr_->comment[hdr_->hdrLength-24] = '\0';
00238       hdr_->srate = ByteSwapLong(hdr_->srate);
00239       hdr_->channels = ByteSwapLong(hdr_->channels);
00240       hdr_->mode = ByteSwapLong(hdr_->mode);
00241       hdr_->fileLength = ByteSwapLong(hdr_->fileLength);
00242 #endif
00243 
00244       sampleSize_ = 2;
00245       size_ = (hdr_->fileLength) / sndFormatSizes_[hdr_->mode] / hdr_->channels;
00246       // csize_ = size_ * hdr_->channels;
00247       csize_ = size_;
00248 
00249       fseek(sfp_, hdr_->hdrLength, 0);
00250       sfp_begin_ = ftell(sfp_);
00251       setctrl("mrs_natural/onObservations", (mrs_natural)hdr_->channels);
00252 
00253       setctrl("mrs_real/israte", (mrs_real)hdr_->srate);
00254       setctrl("mrs_natural/size", size_);
00255       ctrl_currentlyPlaying_->setValue(filename, NOUPDATE);
00256       ctrl_previouslyPlaying_->setValue(filename, NOUPDATE);
00257       ctrl_currentLabel_->setValue(0.0, NOUPDATE);
00258       ctrl_previousLabel_->setValue(0.0, NOUPDATE);
00259       ctrl_labelNames_->setValue(",", NOUPDATE);
00260       ctrl_nLabels_->setValue(0, NOUPDATE);
00261       setctrl("mrs_bool/hasData", true);
00262       hasData_ = true;
00263       lastTickWithData_ = false;
00264       samplesOut_ = 0;
00265       pos_ = 0;
00266       setctrl("mrs_natural/pos", 0);
00267     }
00268   }
00269   else
00270   {
00271     setctrl("mrs_natural/onObservations", (mrs_natural)1);
00272     setctrl("mrs_real/israte", (mrs_real)22050.0);
00273     setctrl("mrs_natural/size", (mrs_natural)0);
00274     hasData_ = false;
00275     setctrl("mrs_bool/hasData", false);
00276     lastTickWithData_ = true;
00277     setctrl("mrs_bool/lastTickWithData", true);
00278     pos_ = 0;
00279   }
00280   nChannels_ = getctrl("mrs_natural/onObservations")->to<mrs_natural>();
00281   samplesRead_ = 0;
00282 }
00283 
00284 mrs_natural
00285 AuFileSource::getLinear16(realvec& slice)
00286 {
00287   mrs_natural c,t =0;
00288 
00289   // read samples
00290   fseek(sfp_, 2 * pos_ * nChannels_ + sfp_begin_, SEEK_SET);
00291   samplesRead_ = (mrs_natural)fread(sdata_, sizeof(short), samplesToRead_, sfp_);
00292 
00293 
00294   // pad with zeros if necessary
00295   if ((samplesRead_ != samplesToRead_)&&(samplesRead_ != 0))
00296   {
00297     for (c=0; c < nChannels_; ++c)
00298       for (t=0; t < inSamples_; t++)
00299         slice(c, t) = 0.0;
00300     samplesToWrite_ = samplesRead_ / nChannels_;
00301   }
00302   else // default case - read enough samples or no samples in which case zero output
00303   {
00304     samplesToWrite_ = inSamples_;
00305 
00306     // if there are no more samples output zeros
00307     if (samplesRead_ == 0)
00308       for (t=0; t < inSamples_; t++)
00309       {
00310         nt_ = nChannels_ * t;
00311         for (c=0; c < nChannels_; ++c)
00312         {
00313           sdata_[nt_ + c] = 0;
00314         }
00315       }
00316   }
00317 
00318   // write the read samples to output slice once for each channel
00319   for (t=0; t < samplesToWrite_; t++)
00320   {
00321     sval_ = 0;
00322     nt_ = nChannels_ * t;
00323 
00324 #if defined(MARSYAS_BIGENDIAN)
00325     for (c=0; c < nChannels_; ++c)
00326       slice(c, t) = ((mrs_real) sdata_[nt_ + c] / (PCM_FMAXSHRT));
00327 #else
00328     for (c=0; c < nChannels_; ++c)
00329     {
00330       usval_ = sdata_[nt_ + c];
00331       usval_ = ByteSwapShort (usval_);
00332       sval_ = usval_;
00333       slice(c, t) = (mrs_real) sval_ / (PCM_FMAXSHRT);
00334     }
00335 #endif
00336   }
00337   pos_ += samplesToWrite_;
00338   return pos_;
00339 }
00340 
00341 void
00342 AuFileSource::myUpdate(MarControlPtr sender)
00343 {
00344   (void) sender;  //suppress warning of unused parameter(s)
00345   nChannels_ = getctrl("mrs_natural/onObservations")->to<mrs_natural>();
00346   inSamples_ = getctrl("mrs_natural/inSamples")->to<mrs_natural>();
00347   inObservations_ = getctrl("mrs_natural/inObservations")->to<mrs_natural>();
00348   israte_ = getctrl("mrs_real/israte")->to<mrs_real>();
00349 
00350   setctrl("mrs_natural/onSamples", inSamples_);
00351   setctrl("mrs_natural/onObservations", nChannels_);
00352 
00353   setctrl("mrs_real/osrate", israte_);
00354 
00355   filename_ = getctrl("mrs_string/filename")->to<mrs_string>();
00356   pos_ = getctrl("mrs_natural/pos")->to<mrs_natural>();
00357   rewindpos_ = getctrl("mrs_natural/loopPos")->to<mrs_natural>();
00358 
00359   delete [] sdata_;
00360   delete [] cdata_;
00361 
00362   sdata_ = new short[inSamples_ * nChannels_];
00363   cdata_ = new unsigned char[inSamples_ * nChannels_];
00364 
00365   repetitions_ = getctrl("mrs_real/repetitions")->to<mrs_real>();
00366 
00367   duration_ = getctrl("mrs_real/duration")->to<mrs_real>();
00368   advance_ = getctrl("mrs_natural/advance")->to<mrs_natural>();
00369   cindex_ = getctrl("mrs_natural/cindex")->to<mrs_natural>();
00370 
00371   if (duration_ != -1.0)
00372   {
00373     csize_ = (mrs_natural)(duration_ * israte_ );
00374   }
00375 
00376   //defaultUpdate(); [!]
00377 
00378   samplesToRead_ = inSamples_ * nChannels_;
00379 }
00380 
00381 void
00382 AuFileSource::myProcess(realvec& in, realvec &out)
00383 {
00384 
00385 
00386   (void) in;
00387   if (ctrl_size_->to<mrs_natural>() != 0)
00388   {
00389     //checkFlow(in,out);
00390 
00391     switch (hdr_->mode)
00392     {
00393     case SND_FORMAT_UNSPECIFIED:
00394     {
00395       MRSWARN("AuFileSource::Unspecified format");
00396       updControl("mrs_natural/pos", pos_);
00397       updControl("mrs_bool/hasData", (pos_ < size_ * nChannels_));
00398       break;
00399     }
00400     case SND_FORMAT_MULAW_8:
00401     {
00402       MRSWARN("MU_LAW for now not supported");
00403       updControl("mrs_natural/pos", pos_);
00404       updControl("mrs_bool/hasData", (pos_ < size_ * nChannels_));
00405       break;
00406     }
00407     case SND_FORMAT_LINEAR_8:
00408     {
00409       // pos_ = getLinear8(c, out);
00410       setctrl("mrs_natural/pos", pos_);
00411       setctrl("mrs_bool/hasData", pos_ < size_ * nChannels_);
00412       break;
00413     }
00414     case SND_FORMAT_LINEAR_16:
00415     {
00416       getLinear16(out);
00417       ctrl_pos_->setValue(pos_, NOUPDATE);
00418 
00419       if (pos_ >= rewindpos_ + csize_)
00420       {
00421         if (repetitions_ != 1)
00422         {
00423           pos_ = rewindpos_;
00424         }
00425 
00426       }
00427 
00428       samplesOut_ += onSamples_;
00429 
00430       if (repetitions_ != 1)
00431       {
00432         hasData_ = (samplesOut_ < repetitions_ * csize_);
00433         lastTickWithData_ = ((samplesOut_  + onSamples_>= repetitions_ * csize_) && hasData_);
00434       }
00435       else
00436       {
00437         hasData_ = pos_ < rewindpos_ + csize_;
00438         lastTickWithData_ = ((samplesOut_  + onSamples_>= repetitions_ * csize_) && hasData_);
00439       }
00440 
00441 
00442       if (repetitions_ == -1)
00443       {
00444         hasData_ = true;
00445         lastTickWithData_ = false;
00446       }
00447 
00448       break;
00449     }
00450     case SND_FORMAT_FLOAT:
00451     {
00452       // getfloat(win);
00453       break;
00454     }
00455     default:
00456     {
00457       mrs_string warn = "File mode";
00458       warn += sndFormats_[hdr_->mode];
00459       warn += "(";
00460       warn += (char) hdr_->mode;
00461       warn += ") is not supported for now";
00462       MRSWARN(warn);
00463     }
00464     }
00465   }
00466   ctrl_currentHasData_->setValue(hasData_);
00467   ctrl_currentLastTickWithData_->setValue(lastTickWithData_);
00468 }