Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/OggFileSource.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 <marsyas/common_source.h>
00020 #include "OggFileSource.h"
00021 
00022 #include <cstdio>
00023 
00024 #ifndef WIN32
00025 #include <sys/stat.h>
00026 #include <sys/types.h>
00027 #include <sys/mman.h>
00028 #include <fcntl.h>
00029 #endif
00030 
00031 #include <vorbis/vorbisfile.h>
00032 
00033 
00034 using std::ostringstream;
00035 using namespace Marsyas;
00036 
00037 OggFileSource::OggFileSource(mrs_string name):AbsSoundFileSource("OggFileSource", name)
00038 {
00039   //type_ = "OggFileSource";
00040   //name_ = name;
00041   hasData_ = false;
00042   addControls();
00043 }
00044 
00045 OggFileSource::~OggFileSource()
00046 {
00047   closeFile();
00048 }
00049 
00050 OggFileSource::OggFileSource(const OggFileSource& a):AbsSoundFileSource(a)
00051 {
00052 //  type_ = a.type_;
00053 //  name_ = a.name_;
00054 //  ncontrols_ = a.ncontrols_;
00055 //
00056 //  inSamples_ = a.inSamples_;
00057 //  inObservations_ = a.inObservations_;
00058 //  onSamples_ = a.onSamples_;
00059 //  onObservations_ = a.onObservations_;
00060 //  dbg_ = a.dbg_;
00061 //  mute_ = a.mute_;
00062   ctrl_currentlyPlaying_ = getctrl("mrs_string/currentlyPlaying");
00063   ctrl_previouslyPlaying_ = getctrl("mrs_string/previouslyPlaying");
00064   ctrl_regression_ = getctrl("mrs_bool/regression");
00065   ctrl_currentLabel_ = getctrl("mrs_real/currentLabel");
00066   ctrl_previousLabel_ = getctrl("mrs_real/previousLabel");
00067   ctrl_labelNames_ = getctrl("mrs_string/labelNames");
00068   ctrl_nLabels_ = getctrl("mrs_natural/nLabels");
00069 }
00070 
00071 MarSystem*
00072 OggFileSource::clone() const
00073 {
00074   return new OggFileSource(*this);
00075 }
00076 
00077 void
00078 OggFileSource::addControls()
00079 {
00080   // nChannels is one for now
00081   addctrl("mrs_natural/nChannels",1);
00082   addctrl("mrs_natural/bitRate", 160000);
00083   setctrlState("mrs_natural/nChannels", true);
00084   addctrl("mrs_bool/init", false);
00085   setctrlState("mrs_bool/init", true);
00086   addctrl("mrs_bool/hasData", true);
00087   addctrl("mrs_natural/loopPos", (mrs_natural)0);
00088   setctrlState("mrs_natural/loopPos", true);
00089   addctrl("mrs_natural/pos", (mrs_natural)0);
00090   setctrlState("mrs_natural/pos", true);
00091   addctrl("mrs_string/filename", "daufile");
00092   setctrlState("mrs_string/filename", true);
00093   addctrl("mrs_natural/size", (mrs_natural)0);
00094   addctrl("mrs_string/filetype", "ogg");
00095   addctrl("mrs_real/repetitions", 1.0);
00096   setctrlState("mrs_real/repetitions", true);
00097   addctrl("mrs_real/duration", -1.0);
00098   setctrlState("mrs_real/duration", true);
00099 
00100   addctrl("mrs_natural/advance", 0);
00101   setctrlState("mrs_natural/advance", true);
00102 
00103   addctrl("mrs_bool/shuffle", false);
00104   setctrlState("mrs_bool/shuffle", true);
00105 
00106   addctrl("mrs_natural/cindex", 0);
00107   setctrlState("mrs_natural/cindex", true);
00108 
00109   addctrl("mrs_string/allfilenames", ",");
00110   addctrl("mrs_natural/numFiles", 1);
00111 
00112   // addctrl("mrs_string/currentlyPlaying", "daufile");
00113 
00114   addctrl("mrs_string/currentlyPlaying", "doggfile", ctrl_currentlyPlaying_);
00115   addctrl("mrs_string/previouslyPlaying", "doggfile", ctrl_previouslyPlaying_);
00116   addctrl("mrs_bool/regression", false, ctrl_regression_);
00117   addctrl("mrs_real/currentLabel", 0.0, ctrl_currentLabel_);
00118   addctrl("mrs_real/previousLabel", 0.0, ctrl_previousLabel_);
00119   addctrl("mrs_natural/nLabels", 0, ctrl_nLabels_);
00120   addctrl("mrs_string/labelNames", ",", ctrl_labelNames_);
00121 
00122   addctrl("mrs_bool/lastTickWithData", false);
00123   addctrl("mrs_bool/currentLastTickWithData", false, ctrl_currentLastTickWithData_);
00124 }
00125 
00126 
00132 void
00133 OggFileSource::getHeader(mrs_string filename)
00134 {
00135   // if we have a file open already, close it
00136   closeFile();
00137   mrs_real duration = 0;
00138   mrs_real israte = 22050.0;
00139   mrs_natural nChannels = 1;
00140   mrs_natural size = 0;
00141   hasData_ = false;
00142   mrs_natural bitRate = 128*1024;
00143 
00144   FILE* fp = fopen(filename.c_str(), "rb");
00145   vf = new OggVorbis_File;
00146 
00147   /* Using ov_open_callbacks because ov_open fails under windows. */
00148   if(fp && ov_open_callbacks(fp, vf, NULL, 0, OV_CALLBACKS_DEFAULT) == 0)
00149   {
00150     vi=ov_info(vf,-1);
00151     size = ov_pcm_total(vf,-1);
00152     duration = ov_time_total(vf,-1);
00153     nChannels = vi->channels;
00154     israte = vi->rate;
00155     hasData_ = true;
00156     bitRate = ov_bitrate(vf, -1);
00157   }
00158   else
00159   {
00160     (void) filename; // in case the macro is not expanded
00161     MRSWARN(filename + " does not appear to be an Ogg bitstream.");
00162   }
00163   setctrl("mrs_natural/nChannels", nChannels);
00164   setctrl("mrs_real/israte", israte);
00165   setctrl("mrs_natural/size", size);
00166   setctrl("mrs_bool/hasData", hasData_);
00167   setctrl("mrs_natural/bitRate", bitRate);
00168   updControl("mrs_real/duration", duration);
00169 }
00170 
00181 void
00182 OggFileSource::myUpdate(MarControlPtr sender)
00183 {
00184   (void) sender;  //suppress warning of unused parameter(s)
00185   MRSDIAG("OggFileSource::myUpdate");
00186 
00187   setctrl("mrs_natural/onSamples", getctrl("mrs_natural/inSamples"));
00188   setctrl("mrs_natural/onObservations", getctrl("mrs_natural/inObservations"));
00189   setctrl("mrs_real/osrate", getctrl("mrs_real/israte"));
00190 
00191   mrs_natural pos = getctrl("mrs_natural/pos")->to<mrs_natural>();
00192   mrs_natural size = getctrl("mrs_natural/size")->to<mrs_natural>();
00193 
00194   // if the user has seeked somewhere in the file
00195   if ( pos < size && pos != ov_pcm_tell(vf))
00196   {
00197     ov_pcm_seek(vf, pos_);
00198   }
00199 
00200 }
00201 
00207 void OggFileSource::myProcess(realvec& in, realvec& out)
00208 {
00209   (void) in;
00210   //checkFlow(in,out);
00211 
00212   if (hasData_)
00213   {
00214     /*mrs_real duration = getctrl("mrs_real/duration")->to<mrs_real>();
00215     mrs_real rate = getctrl("mrs_real/israte")->to<mrs_real>();
00216     */
00217     mrs_natural observations = getctrl("mrs_natural/inObservations")->to<mrs_natural>();
00218     mrs_natural samples = getctrl("mrs_natural/inSamples")->to<mrs_natural>();
00219     mrs_natural israte = (mrs_natural)getctrl("mrs_real/israte")->to<mrs_real>();
00220 
00221     //mrs_natural size = (mrs_natural)(duration * rate);
00222     mrs_natural size = vi->channels*sizeof(short int)*((mrs_natural)(observations * samples));
00223     char* buf = new char[size];
00224     int bitstream=0;
00225     mrs_natural read = 0;
00226     long r = 0;
00227     bool eof = false;
00228     do
00229     {
00230       r = ov_read(vf, buf+read, size-read, 0, 2/*use 1 for 8bit samples..use 2 for 16*/, 1, &bitstream);
00231       if(r <= 0)
00232       {
00233         eof = true;
00234         break;
00235       }
00236       read += (mrs_natural) r;
00237     }
00238     while(read < size);
00239 
00240     //   getLinear16(out);  for (o=0; o < inObservations_; o++) {
00241     const double peak = 1.0/32768; // normalize 24-bit sample
00242     short int* src = (short int*)buf;
00243     for (mrs_natural o=0; o < observations; o++)
00244     {
00245       for (mrs_natural t=0; t < samples; t++)
00246       {
00247         const unsigned int i=vi->channels*t;
00248         switch(vi->channels)
00249         {
00250         case 2:
00251           out(0,t) = (src[i] + src[i+1])*peak/2;
00252           break;
00253         default:
00254           out(0,t) = src[i]*peak;
00255         }
00256       }
00257     }
00258     delete [] buf;
00259     if(eof)
00260       closeFile();
00261 
00262   }
00263   else
00264     out.setval(0.0);
00265   if (hasData_)
00266   {
00267     // hasData_ = (samplesOut_ < repetitions_ * csize_);
00268   }
00269   else
00270   {
00271     // if hasData_ was false already it got set in fillStream
00272     MRSWARN("OggFileSource: track ended.");
00273   }
00274 }
00275 
00283 void OggFileSource::closeFile()
00284 {
00285 
00286   if(hasData_)
00287   {
00288     ov_clear(vf);
00289     delete vf;
00290   }
00291 
00292   hasData_ = false;
00293 }