Marsyas
0.6.0-alpha
|
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 }