Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/MP3FileSource.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 "MP3FileSource.h"
00021 
00022 using std::cout;
00023 using std::endl;
00024 
00025 using std::ostringstream;
00026 using namespace Marsyas;
00027 
00028 #define INPUT_BUFFER_SIZE (5*8192)
00029 
00030 MP3FileSource::MP3FileSource(mrs_string name):AbsSoundFileSource("MP3FileSource", name)
00031 {
00032   //type_ = "MP3FileSource";
00033   //name_ = name;
00034 
00035   ri_ = preservoirSize_ = 0;
00036   ptr_ = NULL;
00037 
00038   fileSize_ = 0;
00039   fd = 0;
00040   fp = NULL;
00041   offset = 0;
00042   pos_ = 0;
00043   size_ = 0;
00044   currentPos_ = 0;
00045 
00046 
00047   bufferSize_ = 576;    // must be initialized, otherwise it may be a very big value and
00048   // may further cause segment fault when allocating space for input buffer
00049   frameSamples_ = 0;
00050   totalFrames_ = 0;
00051   frameCount_ = 0;
00052 
00053   // variables for buffer balancing
00054   reservoirSize_ = 0;
00055 
00056   advance_ = 0;
00057   cindex_ = 0;
00058 
00059   duration_ = 0;
00060   csize_ = 0;
00061   samplesOut_ = 0;
00062   repetitions_ = 0;
00063 
00064 
00065 
00066   addControls();
00067 }
00068 
00069 MP3FileSource::~MP3FileSource()
00070 {
00071   madStructFinish();
00072   closeFile();
00073 }
00074 
00075 MP3FileSource::MP3FileSource(const MP3FileSource& a):AbsSoundFileSource(a)
00076 {
00077   ptr_ = NULL;
00078   fp = NULL;
00079 
00080   pos_ = 0;
00081   size_ = 0;
00082   currentPos_ = 0;
00083 
00084 // must be initialized, otherwise it may be a very big value and
00085   bufferSize_ = 576;
00086 // may further cause segment fault when allocating space for input buffer
00087   frameSamples_ = 0;
00088   totalFrames_ = 0;
00089   frameCount_ = 0;
00090 
00091 // variables for buffer balancing
00092   reservoirSize_ = 0;
00093 
00094   advance_ = 0;
00095   cindex_ = 0;
00096 
00097   duration_ = 0;
00098   csize_ = 0;
00099   samplesOut_ = 0;
00100   repetitions_ = 0;
00101 
00102   ctrl_pos_ = getctrl("mrs_natural/pos");
00103   ctrl_currentlyPlaying_ = getctrl("mrs_string/currentlyPlaying");
00104   ctrl_previouslyPlaying_ = getctrl("mrs_string/previouslyPlaying");
00105   ctrl_regression_ = getctrl("mrs_bool/regression");
00106   ctrl_currentLabel_ = getctrl("mrs_real/currentLabel");
00107   ctrl_previousLabel_ = getctrl("mrs_real/previousLabel");
00108   ctrl_labelNames_ = getctrl("mrs_string/labelNames");
00109   ctrl_nLabels_ = getctrl("mrs_natural/nLabels");
00110   ctrl_currentHasData_ = getctrl("mrs_bool/currentHasData");
00111   ctrl_currentLastTickWithData_ = getctrl("mrs_bool/currentLastTickWithData");
00112 }
00113 
00114 MarSystem*
00115 MP3FileSource::clone() const
00116 {
00117   return new MP3FileSource(*this);
00118 }
00119 
00120 
00121 void
00122 MP3FileSource::addControls()
00123 {
00124   addctrl("mrs_natural/bitRate", 160000);
00125   addctrl("mrs_bool/init", false);
00126   setctrlState("mrs_bool/init", true);
00127   addctrl("mrs_bool/hasData", true);
00128   addctrl("mrs_bool/lastTickWithData", false);
00129   addctrl("mrs_natural/loopPos", (mrs_natural)0);
00130   setctrlState("mrs_natural/loopPos", true);
00131   addctrl("mrs_natural/pos", (mrs_natural)0, ctrl_pos_);
00132   setctrlState("mrs_natural/pos", true);
00133   addctrl("mrs_string/filename", "daufile");
00134   setctrlState("mrs_string/filename", true);
00135   addctrl("mrs_natural/size", (mrs_natural)0);
00136   addctrl("mrs_string/filetype", "mp3");
00137   addctrl("mrs_real/repetitions", 1.0);
00138   setctrlState("mrs_real/repetitions", true);
00139   addctrl("mrs_real/duration", -1.0);
00140   setctrlState("mrs_real/duration", true);
00141 
00142 
00143   addctrl("mrs_natural/advance", 0);
00144   setctrlState("mrs_natural/advance", true);
00145 
00146   addctrl("mrs_bool/shuffle", false);
00147   setctrlState("mrs_bool/shuffle", true);
00148 
00149   addctrl("mrs_natural/cindex", 0);
00150   setctrlState("mrs_natural/cindex", true);
00151 
00152   addctrl("mrs_string/allfilenames", ",");
00153   addctrl("mrs_natural/numFiles", 1);
00154 
00155   addctrl("mrs_string/currentlyPlaying", "daufile", ctrl_currentlyPlaying_);
00156   addctrl("mrs_string/previouslyPlaying", "daufile", ctrl_previouslyPlaying_);
00157 
00158   addctrl("mrs_bool/regression", false, ctrl_regression_);
00159   addctrl("mrs_real/currentLabel", 0.0, ctrl_currentLabel_);
00160   addctrl("mrs_real/previousLabel", 0.0, ctrl_previousLabel_);
00161   addctrl("mrs_string/labelNames",",", ctrl_labelNames_);
00162   addctrl("mrs_natural/nLabels", 0, ctrl_nLabels_);
00163 
00164   addctrl("mrs_bool/currentHasData", true, ctrl_currentHasData_);
00165   addctrl("mrs_bool/currentLastTickWithData", false, ctrl_currentLastTickWithData_);
00166 }
00167 
00168 
00169 
00170 
00171 void
00172 MP3FileSource::PrintFrameInfo(struct mad_header *Header)
00173 {
00174   const char    *Layer,
00175          *Mode,
00176          *Emphasis;
00177 
00178   /* Convert the layer number to it's printed representation. */
00179   switch(Header->layer)
00180   {
00181   case MAD_LAYER_I:
00182     Layer="I";
00183     break;
00184   case MAD_LAYER_II:
00185     Layer="II";
00186     break;
00187   case MAD_LAYER_III:
00188     Layer="III";
00189     break;
00190   default:
00191     Layer="(unexpected layer value)";
00192     break;
00193   }
00194 
00195   /* Convert the audio mode to it's printed representation. */
00196   switch(Header->mode)
00197   {
00198   case MAD_MODE_SINGLE_CHANNEL:
00199     Mode="single channel";
00200     break;
00201   case MAD_MODE_DUAL_CHANNEL:
00202     Mode="dual channel";
00203     break;
00204   case MAD_MODE_JOINT_STEREO:
00205     Mode="joint (MS/intensity) stereo";
00206     break;
00207   case MAD_MODE_STEREO:
00208     Mode="normal LR stereo";
00209     break;
00210   default:
00211     Mode="(unexpected mode value)";
00212     break;
00213   }
00214 
00215   /* Convert the emphasis to it's printed representation. Note that
00216    * the MAD_EMPHASIS_RESERVED enumeration value appeared in libmad
00217    * version 0.15.0b.
00218    */
00219   switch(Header->emphasis)
00220   {
00221   case MAD_EMPHASIS_NONE:
00222     Emphasis="no";
00223     break;
00224   case MAD_EMPHASIS_50_15_US:
00225     Emphasis="50/15 us";
00226     break;
00227   case MAD_EMPHASIS_CCITT_J_17:
00228     Emphasis="CCITT J.17";
00229     break;
00230 #if (MAD_VERSION_MAJOR>=1) ||                           \
00231     ((MAD_VERSION_MAJOR==0) && (MAD_VERSION_MINOR>=15))
00232   case MAD_EMPHASIS_RESERVED:
00233     Emphasis="reserved(!)";
00234     break;
00235 #endif
00236   default:
00237     Emphasis="(unexpected emphasis value)";
00238     break;
00239   }
00240 
00241   printf("%lu kb/s audio MPEG layer %s stream %s CRC, "
00242          "%s with %s emphasis at %d Hz sample rate\n",
00243          Header->bitrate,Layer,
00244          Header->flags&MAD_FLAG_PROTECTION?"with":"without",
00245          Mode,Emphasis,Header->samplerate);
00246 }
00247 
00248 
00249 
00250 
00251 
00257 void
00258 MP3FileSource::getHeader(mrs_string filename)
00259 {
00260   // cout << "getHeader " << filename << endl;
00261 
00262   debug_filename = filename;
00263 
00264   durFull_ = 0.;
00265   // if we have a file open already, close it
00266   closeFile();
00267   update();
00268 
00269   reservoir_.setval(0.0);
00270 
00271   fp = fopen(filename.c_str(), "rb");
00272   fseek(fp, 0L, SEEK_END);
00273   myStat.st_size = ftell(fp);
00274   fseek(fp, 0L, SEEK_SET);
00275 
00276 
00277 
00278   if (myStat.st_size == 0 ) {
00279     MRSWARN("Error reading file: " + filename);
00280     setctrl("mrs_natural/onObservations", 2);
00281     setctrl("mrs_real/israte", 22050.0);
00282     setctrl("mrs_natural/size", 0);
00283     hasData_ = 0;
00284     lastTickWithData_ = false;
00285     setctrl("mrs_bool/hasData", false);
00286     setctrl("mrs_bool/lastTickWithData", true);
00287     return;
00288   }
00289 
00290 
00291 
00292 
00293   // libmad seems to read sometimes beyond the file size
00294   // added 2048 as padding for these cases - most likely
00295   // mp3 that are not properly formatted
00296   ptr_ = new unsigned char[myStat.st_size+2048];
00297 
00298 
00299   int numRead = fread(ptr_, sizeof(unsigned char), myStat.st_size, fp);
00300 
00301   if (numRead != myStat.st_size)
00302   {
00303     MRSWARN("Error reading: " + filename + " to memory.");
00304     setctrl("mrs_natural/onObservations", 2);
00305     setctrl("mrs_real/israte", 22050.0);
00306     setctrl("mrs_natural/size", 0);
00307     hasData_ = 0;
00308     lastTickWithData_ = false;
00309     setctrl("mrs_bool/hasData", false);
00310     setctrl("mrs_bool/lastTickWithData", true);
00311     return;
00312   }
00313 
00314   fileSize_ = myStat.st_size;
00315   offset = 0;
00316   samplesOut_ = 0;
00317   ri_ = 0;
00318 
00319 
00320   // initialize mad structs and fill the stream
00321   madStructInitialize();
00322   fillStream();
00323 
00324 
00325   // if there is nothing in the stream...
00326   hasData_ = getctrl("mrs_bool/hasData")->to<mrs_bool>();
00327   if (!hasData_) {
00328     pos_ = 0;
00329     return;
00330   }
00331 
00332   // decode some frames until we find the samplerate and bitrate
00333   while (1)
00334   {
00335     pos_ += bufferSize_;
00336     currentPos_ = pos_;
00337 
00338 
00339     if ( mad_frame_decode(&frame, &stream) )
00340     {
00341 
00342       if(MAD_RECOVERABLE(stream.error))
00343       {
00344 
00345         if(stream.error != MAD_ERROR_LOSTSYNC) {
00346           mrs_string errmsg;
00347           errmsg += "MP3FileSource: recoverable frame level error: ";
00348           errmsg += mad_stream_errorstr(&stream);
00349           MRSDIAG(errmsg);
00350         }
00351 
00352         // get some more samples...
00353         fillStream();
00354         if (!hasData_) {
00355           pos_ = 0;
00356           return;
00357         }
00358 
00359       }
00360       else if(stream.error==MAD_ERROR_BUFLEN)
00361       {
00362 
00363         fillStream();
00364         if (!hasData_) {
00365           pos_ = 0;
00366           return;
00367         }
00368 
00369       }
00370       else
00371       {
00372         MRSERR("MP3FileSource: unrecoverable frame level error, quitting.");
00373         pos_ = 0;
00374         return;
00375       }
00376 
00377       frameCount_++;
00378     }
00379     else
00380       break;
00381 
00382 
00383   }
00384 
00385   pos_ = 0;
00386   currentPos_ = 0;
00387 
00388   // PrintFrameInfo(&frame.header);
00389 
00390 
00391   mrs_natural nChannels = MAD_NCHANNELS(&frame.header);
00392   setctrl("mrs_natural/onObservations", nChannels);
00393 
00394 
00395   frameSamples_ = 32 * MAD_NSBSAMPLES(&frame.header);
00396   bufferSize_ = frameSamples_; // mad frame size
00397   mrs_natural bitRate = frame.header.bitrate;
00398   mrs_real sampleRate = frame.header.samplerate;
00399 
00400 
00401   // only works for a constant bitrate, duration is (bits in file / bitrate)
00402   mrs_real duration_ = (fileSize_ * 8) / bitRate;
00403   advance_ = getctrl("mrs_natural/advance")->to<mrs_natural>();
00404   cindex_ = getctrl("mrs_natural/cindex")->to<mrs_natural>();
00405 
00406   size_ = (mrs_natural) (duration_ * sampleRate);
00407 
00408 
00409   csize_ = size_ ;
00410 
00411 
00412   totalFrames_ = (mrs_natural)((sampleRate * duration_) / frameSamples_);
00413 
00414 
00415   // update some controls
00416   setctrl("mrs_real/duration", duration_);
00417   setctrl("mrs_real/israte", sampleRate);
00418   setctrl("mrs_natural/size", size_ );
00419   setctrl("mrs_natural/bitRate", bitRate);
00420 
00421   update();
00422 
00423 
00424   ctrl_currentlyPlaying_->setValue(filename, NOUPDATE);
00425   ctrl_previouslyPlaying_->setValue(filename, NOUPDATE);
00426 
00427   ctrl_currentLabel_->setValue(0.0, NOUPDATE);
00428   ctrl_previousLabel_->setValue(0.0, NOUPDATE);
00429   ctrl_nLabels_->setValue(0, NOUPDATE);
00430 
00431 
00432   ctrl_labelNames_->setValue(",", NOUPDATE);
00433 
00434 
00435 
00436   offset = 0;
00437   pos_ = samplesOut_ = frameCount_ = 0;
00438   currentPos_ = 0;
00439   hasData_ = 1;
00440 
00441 
00442 }
00443 
00444 
00455 void
00456 MP3FileSource::myUpdate(MarControlPtr sender)
00457 {
00458   (void) sender;  //suppress warning of unused parameter(s)
00459   MRSDIAG("MP3FileSource::myUpdate");
00460 
00461 
00462 
00463   israte_ = ctrl_israte_->to<mrs_real>();
00464   inSamples_ = ctrl_inSamples_->to<mrs_natural>();
00465   // pos_ = getctrl("mrs_natural/pos")->to<mrs_natural>();
00466 
00467   mrs_natural nChannels = ctrl_onObservations_->to<mrs_natural>();
00468 
00469   setctrl("mrs_natural/onSamples", inSamples_);
00470   setctrl("mrs_real/osrate", israte_);
00471 
00472 
00473 
00474 
00475   filename_ = getctrl("mrs_string/filename")->to<mrs_string>();
00476   duration_ = getctrl("mrs_real/duration")->to<mrs_real>();
00477   advance_ = getctrl("mrs_natural/advance")->to<mrs_natural>();
00478   //rewindpos_ = pos_;
00479 
00480   repetitions_ = getctrl("mrs_real/repetitions")->to<mrs_real>();
00481 
00482   if (duration_ != -1.0)
00483   {
00484     csize_ = (mrs_natural)(duration_ * israte_);
00485   }
00486 
00487   inSamples_ = ctrl_inSamples_->to<mrs_natural>();
00488 
00489   if (inSamples_ < bufferSize_/2) {
00490     reservoirSize_ = 2 * nChannels * bufferSize_;
00491   } else {
00492     reservoirSize_ = 2 * nChannels * inSamples_;
00493   }
00494   if (reservoirSize_ > preservoirSize_) {
00495     reservoir_.stretch(nChannels,reservoirSize_);
00496   }
00497   preservoirSize_ = reservoirSize_;
00498 
00499 
00500 
00501 }
00502 
00503 
00504 
00517 mrs_natural
00518 MP3FileSource::getLinear16(realvec& slice)
00519 {
00520 
00521 
00522   register double peak = 1.0/32767; // normalize 24-bit sample
00523   register mad_fixed_t left_ch, right_ch;
00524   register mrs_real sample;
00525 
00526 
00527 
00528   // decode a frame if necessary
00529   while (ri_ < inSamples_) {
00530 
00531     fillStream();
00532 
00533     // if (!hasData_) {
00534     // pos_ = 0;
00535     // return pos_;
00536     // }
00537 
00538     if (mad_frame_decode(&frame, &stream ))
00539     {
00540       long bufferSize = ((long)stream.bufend-(long)stream.buffer)*8  - stream.md_len*8;
00541 
00542       if (frame.header.bitrate!=0 && bufferSize>0) durFull_ += (float)bufferSize/(float)frame.header.bitrate;
00543       // std::cout<<"decoded: bufptr="<<(long)stream.buffer<<" cnt="<<frameCount_<<" bps="<<frame.header.bitrate<<" bufSize="<<bufferSize<<" dur="<<durFull_<<std::endl;
00544       // std::cout<<"possible buffersize c="<<bufferSize<<" 1="<<((long)stream.next_frame-(long)stream.this_frame)*8<<" 2="<<stream.anc_bitlen<<" 3="<<stream.md_len*8<<std::endl;
00545 
00546       if(MAD_RECOVERABLE(stream.error))
00547       {
00548 
00549         if(stream.error != MAD_ERROR_LOSTSYNC) {
00550           mrs_string errmsg;
00551           errmsg += "MP3FileSource: recoverable frame level error :";
00552           errmsg += mad_stream_errorstr(&stream);
00553           MRSDIAG(errmsg);
00554         }
00555 
00556         fillStream();
00557         if (!hasData_) {
00558           pos_ = 0;
00559           return pos_;
00560         }
00561 
00562       }
00563       else if(stream.error==MAD_ERROR_BUFLEN)
00564       {
00565 
00566         fillStream();
00567         if (!hasData_) {
00568           pos_ = 0;
00569           return pos_;
00570         }
00571 
00572       }
00573 
00574       else
00575       {
00576         MRSERR("MP3FileSource: unrecoverable frame level error, quitting.");
00577       }
00578 
00579       frameCount_++;
00580     }
00581 
00582 
00583     mad_synth_frame(&synth, &frame);
00584 
00585 
00586 
00587     // fill the reservoir...
00588     for (mrs_natural t=0; t < bufferSize_; t++) {
00589 
00590       left_ch = synth.pcm.samples[0][t];
00591       sample = (mrs_real) scale(left_ch);
00592       sample *= peak;
00593 
00594       reservoir_(0, ri_) = sample;
00595 
00596 
00597       // for 2 channel audio we can add the channels
00598       // and divide by two
00599       if(MAD_NCHANNELS(&frame.header)==2) {
00600         right_ch = synth.pcm.samples[1][t];
00601         sample = (mrs_real) scale(right_ch);
00602         sample *= peak;
00603 
00604 
00605         reservoir_(1, ri_) = sample;
00606       }
00607 
00608       ri_++;
00609     }
00610 
00611   } // reservoir fill
00612 
00613 
00614   // spit out the first inSamples_ in our reservoir
00615   for (mrs_natural t=0; t < inSamples_; t++) {
00616     slice(0,t) = reservoir_(0,t);
00617     if (MAD_NCHANNELS(&frame.header)==2)
00618     {
00619       slice(1,t) = reservoir_(1,t);
00620     }
00621   }
00622 
00623 
00624 
00625   // keep track of where we are
00626   pos_ += inSamples_; // (inSamples_ * getctrl("mrs_natural/nChannels")->to<mrs_natural>());
00627 
00628 
00629   currentPos_ = pos_;
00630 
00631 
00632   // move the data we ticked to the front of the reservoir
00633   for (mrs_natural t=inSamples_; t < ri_; t++) {
00634     reservoir_(0,t-inSamples_) = reservoir_(0,t);
00635     if (MAD_NCHANNELS(&frame.header)==2)
00636       reservoir_(1,t-inSamples_) = reservoir_(1,t);
00637   }
00638 
00639   // update our reservroi index
00640   ri_ = ri_ - inSamples_;
00641 
00642   return pos_;
00643 }
00644 
00645 
00651 void MP3FileSource::myProcess(realvec& in, realvec& out)
00652 {
00653   (void) in;
00654   //checkFlow(in,out);
00655 
00656 
00657   if (hasData_)
00658     getLinear16(out);
00659   // else
00660   // out.setval(0.0);
00661 
00662   //if (!hasData_)
00663   // out.setval(0.0);
00664 
00665 
00666 
00667   ctrl_pos_->setValue(pos_, NOUPDATE);
00668 
00669 
00670   if (pos_ >= rewindpos_ + csize_)
00671   {
00672     if (repetitions_ != 1)
00673     {
00674       if (repetitions_ != 1)
00675         pos_ = rewindpos_;
00676       // compute a new file offset using the frame target
00677       mrs_real ratio = (mrs_real)pos_/size_;
00678 
00679       madStructInitialize();
00680 
00681       mrs_natural targetOffset = (mrs_natural) (fileSize_ * (mrs_real)ratio);
00682 
00683       // if we are rewinding, we call fillStream with -1
00684       if (targetOffset==0) {
00685         fillStream(-1);
00686       } else {
00687         fillStream(targetOffset);
00688       }
00689       currentPos_ = pos_;
00690     }
00691 
00692   }
00693   samplesOut_ += onSamples_;
00694 
00695 
00696 
00697   if (repetitions_ != 1)
00698   {
00699     hasData_ = (samplesOut_ < repetitions_ * csize_);
00700     lastTickWithData_ = ((samplesOut_  + onSamples_>= repetitions_ * csize_) && hasData_);
00701   }
00702   else
00703   {
00704     hasData_ = samplesOut_ < rewindpos_ + csize_;
00705     lastTickWithData_ = ((samplesOut_ + onSamples_ >= rewindpos_ + csize_) && hasData_);
00706   }
00707 
00708   if (repetitions_ == -1)
00709   {
00710     hasData_ = true;
00711     lastTickWithData_ = false;
00712   }
00713 
00714 
00715 
00716 
00717   ctrl_currentHasData_->setValue(hasData_);
00718   ctrl_currentLastTickWithData_->setValue(lastTickWithData_);
00719 
00720 
00721 }
00722 
00723 
00724 /*
00725  * Initialize mad structs
00726  */
00727 void MP3FileSource::madStructInitialize() {
00728 
00729   mad_stream_init(&stream);
00730   mad_frame_init(&frame);
00731   mad_synth_init(&synth);
00732 }
00733 
00734 
00735 
00736 /*
00737  * Release mad structs
00738  */
00739 void MP3FileSource::madStructFinish() {
00740 
00741   mad_stream_finish(&stream);
00742   mad_frame_finish(&frame);
00743   mad_synth_finish(&synth);
00744 }
00745 
00746 
00747 
00748 
00756 void
00757 MP3FileSource::fillStream( mrs_natural target )
00758 {
00759 
00760   // fill the input buffer
00761   if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN)
00762   {
00763 
00764     register mrs_natural remaining = 0;
00765     register mrs_natural chunk = INPUT_BUFFER_SIZE;
00766 
00767     // cout << "offset = " << offset << endl;
00768 
00769     // when called with the default parameter, carry on decoding...
00770     if ( stream.next_frame != NULL ) {
00771       offset = stream.next_frame - ptr_;
00772       remaining = fileSize_ - offset;
00773     } else if ( target != 0 ) {
00774       // we have seeked somewhere in the file...
00775       offset = target;
00776       remaining = fileSize_ - offset;
00777     } else if ( target == -1 ) {
00778       // we rewound the track...
00779       offset = 0;
00780       remaining = fileSize_;
00781     }
00782 
00783 
00784     // there may not be enough to fill the buffer
00785     if ( remaining < INPUT_BUFFER_SIZE ) {
00786       chunk = remaining + MAD_BUFFER_GUARD;
00787     }
00788 
00789     // if we have hit the end...
00790     if ( offset >= fileSize_ ) {
00791       hasData_ = false;
00792       // MRSWARN("MP3FileSource: cannot seek to offset");
00793     } else {
00794       // fill the mad buffer
00795       if (offset == -1)
00796         offset = 1;
00797 
00798       mad_stream_buffer(&stream, ptr_ + offset, chunk);
00799 
00800       stream.error = MAD_ERROR_NONE;
00801     }
00802   }
00803 }
00804 
00805 
00806 
00807 
00808 
00809 
00810 
00811 
00819 void MP3FileSource::closeFile()
00820 {
00821 
00822   // close the file and release mad structs
00823   if (fp == NULL)
00824     return;
00825 
00826   fclose(fp);
00827   fd = 0;
00828   pos_ = 0;
00829   currentPos_ = 0;
00830   size_ = 0;
00831   ctrl_pos_->setValue(0, NOUPDATE);
00832 
00833   delete [] ptr_;
00834 
00835 
00836   madStructFinish();
00837 }
00838 
00839 
00840 
00841 
00856 inline signed int MP3FileSource::scale(mad_fixed_t sample)
00857 {
00858   // round
00859   sample += (1L << (MAD_F_FRACBITS - 16));
00860 
00861   // clip
00862   if (sample >= MAD_F_ONE)
00863     sample = MAD_F_ONE - 1;
00864   else if (sample < -MAD_F_ONE)
00865     sample = -MAD_F_ONE;
00866 
00867   // quantize
00868   return sample >> (MAD_F_FRACBITS + 1 - 16);
00869 }