00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "common.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
00033
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;
00048
00049 frameSamples_ = 0;
00050 totalFrames_ = 0;
00051 frameCount_ = 0;
00052
00053
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 #ifdef MARSYAS_MAD
00072 madStructFinish();
00073 #endif
00074 closeFile();
00075 }
00076
00077 MP3FileSource::MP3FileSource(const MP3FileSource& a):AbsSoundFileSource(a)
00078 {
00079 ptr_ = NULL;
00080 fp = NULL;
00081
00082 pos_ = 0;
00083 size_ = 0;
00084 currentPos_ = 0;
00085
00086
00087 bufferSize_ = 576;
00088
00089 frameSamples_ = 0;
00090 totalFrames_ = 0;
00091 frameCount_ = 0;
00092
00093
00094 reservoirSize_ = 0;
00095
00096 advance_ = 0;
00097 cindex_ = 0;
00098
00099 duration_ = 0;
00100 csize_ = 0;
00101 samplesOut_ = 0;
00102 repetitions_ = 0;
00103
00104 ctrl_pos_ = getctrl("mrs_natural/pos");
00105 ctrl_currentlyPlaying_ = getctrl("mrs_string/currentlyPlaying");
00106 ctrl_previouslyPlaying_ = getctrl("mrs_string/previouslyPlaying");
00107 ctrl_regression_ = getctrl("mrs_bool/regression");
00108 ctrl_currentLabel_ = getctrl("mrs_real/currentLabel");
00109 ctrl_previousLabel_ = getctrl("mrs_real/previousLabel");
00110 ctrl_labelNames_ = getctrl("mrs_string/labelNames");
00111 ctrl_nLabels_ = getctrl("mrs_natural/nLabels");
00112 ctrl_currentHasData_ = getctrl("mrs_bool/currentHasData");
00113 ctrl_currentLastTickWithData_ = getctrl("mrs_bool/currentLastTickWithData");
00114 }
00115
00116 MarSystem*
00117 MP3FileSource::clone() const
00118 {
00119 return new MP3FileSource(*this);
00120 }
00121
00122
00123 void
00124 MP3FileSource::addControls()
00125 {
00126 addctrl("mrs_natural/bitRate", 160000);
00127 addctrl("mrs_bool/init", false);
00128 setctrlState("mrs_bool/init", true);
00129 addctrl("mrs_bool/hasData", true);
00130 addctrl("mrs_bool/lastTickWithData", false);
00131 addctrl("mrs_natural/loopPos", (mrs_natural)0);
00132 setctrlState("mrs_natural/loopPos", true);
00133 addctrl("mrs_natural/pos", (mrs_natural)0, ctrl_pos_);
00134 setctrlState("mrs_natural/pos", true);
00135 addctrl("mrs_string/filename", "daufile");
00136 setctrlState("mrs_string/filename", true);
00137 addctrl("mrs_natural/size", (mrs_natural)0);
00138 addctrl("mrs_string/filetype", "mp3");
00139 addctrl("mrs_real/repetitions", 1.0);
00140 setctrlState("mrs_real/repetitions", true);
00141 addctrl("mrs_real/duration", -1.0);
00142 setctrlState("mrs_real/duration", true);
00143
00144
00145 addctrl("mrs_natural/advance", 0);
00146 setctrlState("mrs_natural/advance", true);
00147
00148 addctrl("mrs_bool/shuffle", false);
00149 setctrlState("mrs_bool/shuffle", true);
00150
00151 addctrl("mrs_natural/cindex", 0);
00152 setctrlState("mrs_natural/cindex", true);
00153
00154 addctrl("mrs_string/allfilenames", ",");
00155 addctrl("mrs_natural/numFiles", 1);
00156
00157 addctrl("mrs_string/currentlyPlaying", "daufile", ctrl_currentlyPlaying_);
00158 addctrl("mrs_string/previouslyPlaying", "daufile", ctrl_previouslyPlaying_);
00159
00160 addctrl("mrs_bool/regression", false, ctrl_regression_);
00161 addctrl("mrs_real/currentLabel", 0.0, ctrl_currentLabel_);
00162 addctrl("mrs_real/previousLabel", 0.0, ctrl_previousLabel_);
00163 addctrl("mrs_string/labelNames",",", ctrl_labelNames_);
00164 addctrl("mrs_natural/nLabels", 0, ctrl_nLabels_);
00165
00166 addctrl("mrs_bool/currentHasData", true, ctrl_currentHasData_);
00167 addctrl("mrs_bool/currentLastTickWithData", false, ctrl_currentLastTickWithData_);
00168 }
00169
00170
00171
00172
00173 void
00174 MP3FileSource::PrintFrameInfo(struct mad_header *Header)
00175 {
00176 #ifdef MARSYAS_MAD
00177 const char *Layer,
00178 *Mode,
00179 *Emphasis;
00180
00181
00182 switch(Header->layer)
00183 {
00184 case MAD_LAYER_I:
00185 Layer="I";
00186 break;
00187 case MAD_LAYER_II:
00188 Layer="II";
00189 break;
00190 case MAD_LAYER_III:
00191 Layer="III";
00192 break;
00193 default:
00194 Layer="(unexpected layer value)";
00195 break;
00196 }
00197
00198
00199 switch(Header->mode)
00200 {
00201 case MAD_MODE_SINGLE_CHANNEL:
00202 Mode="single channel";
00203 break;
00204 case MAD_MODE_DUAL_CHANNEL:
00205 Mode="dual channel";
00206 break;
00207 case MAD_MODE_JOINT_STEREO:
00208 Mode="joint (MS/intensity) stereo";
00209 break;
00210 case MAD_MODE_STEREO:
00211 Mode="normal LR stereo";
00212 break;
00213 default:
00214 Mode="(unexpected mode value)";
00215 break;
00216 }
00217
00218
00219
00220
00221
00222 switch(Header->emphasis)
00223 {
00224 case MAD_EMPHASIS_NONE:
00225 Emphasis="no";
00226 break;
00227 case MAD_EMPHASIS_50_15_US:
00228 Emphasis="50/15 us";
00229 break;
00230 case MAD_EMPHASIS_CCITT_J_17:
00231 Emphasis="CCITT J.17";
00232 break;
00233 #if (MAD_VERSION_MAJOR>=1) || \
00234 ((MAD_VERSION_MAJOR==0) && (MAD_VERSION_MINOR>=15))
00235 case MAD_EMPHASIS_RESERVED:
00236 Emphasis="reserved(!)";
00237 break;
00238 #endif
00239 default:
00240 Emphasis="(unexpected emphasis value)";
00241 break;
00242 }
00243
00244 printf("%lu kb/s audio MPEG layer %s stream %s CRC, "
00245 "%s with %s emphasis at %d Hz sample rate\n",
00246 Header->bitrate,Layer,
00247 Header->flags&MAD_FLAG_PROTECTION?"with":"without",
00248 Mode,Emphasis,Header->samplerate);
00249
00250 #endif
00251 }
00252
00253
00254
00255
00256
00262 void
00263 MP3FileSource::getHeader(mrs_string filename)
00264 {
00265
00266
00267 debug_filename = filename;
00268
00269 #ifdef MARSYAS_MAD
00270 durFull_ = 0.;
00271
00272 closeFile();
00273 update();
00274
00275 reservoir_.setval(0.0);
00276
00277 fp = fopen(filename.c_str(), "rb");
00278 fseek(fp, 0L, SEEK_END);
00279 myStat.st_size = ftell(fp);
00280 fseek(fp, 0L, SEEK_SET);
00281
00282
00283
00284 if (myStat.st_size == 0 ) {
00285 MRSWARN("Error reading file: " + filename);
00286 setctrl("mrs_natural/onObservations", 2);
00287 setctrl("mrs_real/israte", 22050.0);
00288 setctrl("mrs_natural/size", 0);
00289 hasData_ = 0;
00290 lastTickWithData_ = false;
00291 setctrl("mrs_bool/hasData", false);
00292 setctrl("mrs_bool/lastTickWithData", true);
00293 return;
00294 }
00295
00296
00297
00298
00299
00300
00301
00302 ptr_ = new unsigned char[myStat.st_size+2048];
00303
00304
00305 int numRead = fread(ptr_, sizeof(unsigned char), myStat.st_size, fp);
00306
00307 if (numRead != myStat.st_size)
00308 {
00309 MRSWARN("Error reading: " + filename + " to memory.");
00310 setctrl("mrs_natural/onObservations", 2);
00311 setctrl("mrs_real/israte", 22050.0);
00312 setctrl("mrs_natural/size", 0);
00313 hasData_ = 0;
00314 lastTickWithData_ = false;
00315 setctrl("mrs_bool/hasData", false);
00316 setctrl("mrs_bool/lastTickWithData", true);
00317 return;
00318 }
00319
00320 fileSize_ = myStat.st_size;
00321 offset = 0;
00322 samplesOut_ = 0;
00323 ri_ = 0;
00324
00325
00326
00327 madStructInitialize();
00328 fillStream();
00329
00330
00331
00332 hasData_ = getctrl("mrs_bool/hasData")->to<mrs_bool>();
00333 if (!hasData_) {
00334 pos_ = 0;
00335 return;
00336 }
00337
00338
00339 while (1)
00340 {
00341 pos_ += bufferSize_;
00342 currentPos_ = pos_;
00343
00344
00345 if ( mad_frame_decode(&frame, &stream) )
00346 {
00347
00348 if(MAD_RECOVERABLE(stream.error))
00349 {
00350
00351 if(stream.error != MAD_ERROR_LOSTSYNC) {
00352 mrs_string errmsg;
00353 errmsg += "MP3FileSource: recoverable frame level error: ";
00354 errmsg += mad_stream_errorstr(&stream);
00355 MRSDIAG(errmsg);
00356 }
00357
00358
00359 fillStream();
00360 if (!hasData_) {
00361 pos_ = 0;
00362 return;
00363 }
00364
00365 }
00366 else if(stream.error==MAD_ERROR_BUFLEN)
00367 {
00368
00369 fillStream();
00370 if (!hasData_) {
00371 pos_ = 0;
00372 return;
00373 }
00374
00375 }
00376 else
00377 {
00378 MRSERR("MP3FileSource: unrecoverable frame level error, quitting.");
00379 pos_ = 0;
00380 return;
00381 }
00382
00383 frameCount_++;
00384 }
00385 else
00386 break;
00387
00388
00389 }
00390
00391 pos_ = 0;
00392 currentPos_ = 0;
00393
00394
00395
00396
00397 mrs_natural nChannels = MAD_NCHANNELS(&frame.header);
00398 setctrl("mrs_natural/onObservations", nChannels);
00399
00400
00401 frameSamples_ = 32 * MAD_NSBSAMPLES(&frame.header);
00402 bufferSize_ = frameSamples_;
00403 mrs_natural bitRate = frame.header.bitrate;
00404 mrs_real sampleRate = frame.header.samplerate;
00405
00406
00407
00408 mrs_real duration_ = (fileSize_ * 8) / bitRate;
00409 advance_ = getctrl("mrs_natural/advance")->to<mrs_natural>();
00410 cindex_ = getctrl("mrs_natural/cindex")->to<mrs_natural>();
00411
00412 size_ = (mrs_natural) ((duration_ * sampleRate) / nChannels);
00413
00414
00415 csize_ = size_ ;
00416
00417
00418 totalFrames_ = (mrs_natural)((sampleRate * duration_) / frameSamples_);
00419
00420
00421
00422 setctrl("mrs_real/duration", duration_);
00423 setctrl("mrs_real/israte", sampleRate);
00424 setctrl("mrs_natural/size", size_ );
00425 setctrl("mrs_natural/bitRate", bitRate);
00426
00427 update();
00428
00429
00430 ctrl_currentlyPlaying_->setValue(filename, NOUPDATE);
00431 ctrl_previouslyPlaying_->setValue(filename, NOUPDATE);
00432
00433 ctrl_currentLabel_->setValue(0.0, NOUPDATE);
00434 ctrl_previousLabel_->setValue(0.0, NOUPDATE);
00435 ctrl_nLabels_->setValue(0, NOUPDATE);
00436
00437
00438 ctrl_labelNames_->setValue(",", NOUPDATE);
00439
00440
00441
00442 offset = 0;
00443 pos_ = samplesOut_ = frameCount_ = 0;
00444 currentPos_ = 0;
00445 hasData_ = 1;
00446
00447
00448 #endif
00449 }
00450
00451
00462 void
00463 MP3FileSource::myUpdate(MarControlPtr sender)
00464 {
00465 (void) sender;
00466 MRSDIAG("MP3FileSource::myUpdate");
00467
00468
00469
00470 israte_ = ctrl_israte_->to<mrs_real>();
00471 inSamples_ = ctrl_inSamples_->to<mrs_natural>();
00472
00473
00474 mrs_natural nChannels = ctrl_onObservations_->to<mrs_natural>();
00475
00476 setctrl("mrs_natural/onSamples", inSamples_);
00477 setctrl("mrs_real/osrate", israte_);
00478
00479
00480
00481
00482 filename_ = getctrl("mrs_string/filename")->to<mrs_string>();
00483 duration_ = getctrl("mrs_real/duration")->to<mrs_real>();
00484 advance_ = getctrl("mrs_natural/advance")->to<mrs_natural>();
00485
00486
00487 repetitions_ = getctrl("mrs_real/repetitions")->to<mrs_real>();
00488
00489 if (duration_ != -1.0)
00490 {
00491 csize_ = (mrs_natural)(duration_ * israte_);
00492 }
00493
00494 inSamples_ = ctrl_inSamples_->to<mrs_natural>();
00495
00496 if (inSamples_ < bufferSize_/2) {
00497 reservoirSize_ = 2 * nChannels * bufferSize_;
00498 } else {
00499 reservoirSize_ = 2 * nChannels * inSamples_;
00500 }
00501 if (reservoirSize_ > preservoirSize_) {
00502 reservoir_.stretch(nChannels,reservoirSize_);
00503 }
00504 preservoirSize_ = reservoirSize_;
00505
00506
00507
00508 }
00509
00510
00511
00524 mrs_natural
00525 MP3FileSource::getLinear16(realvec& slice)
00526 {
00527
00528
00529 #ifdef MARSYAS_MAD
00530 register double peak = 1.0/32767;
00531 register mad_fixed_t left_ch, right_ch;
00532 register mrs_real sample;
00533
00534
00535
00536
00537 while (ri_ < inSamples_) {
00538
00539 fillStream();
00540
00541
00542
00543
00544
00545
00546 if (mad_frame_decode(&frame, &stream ))
00547 {
00548 long bufferSize = ((long)stream.bufend-(long)stream.buffer)*8 - stream.md_len*8;
00549
00550 if (frame.header.bitrate!=0 && bufferSize>0) durFull_ += (float)bufferSize/(float)frame.header.bitrate;
00551
00552
00553
00554 if(MAD_RECOVERABLE(stream.error))
00555 {
00556
00557 if(stream.error != MAD_ERROR_LOSTSYNC) {
00558 mrs_string errmsg;
00559 errmsg += "MP3FileSource: recoverable frame level error :";
00560 errmsg += mad_stream_errorstr(&stream);
00561 MRSDIAG(errmsg);
00562 }
00563
00564 fillStream();
00565 if (!hasData_) {
00566 pos_ = 0;
00567 return pos_;
00568 }
00569
00570 }
00571 else
00572 if(stream.error==MAD_ERROR_BUFLEN)
00573 {
00574
00575 fillStream();
00576 if (!hasData_) {
00577 pos_ = 0;
00578 return pos_;
00579 }
00580
00581 }
00582
00583 else
00584 {
00585 MRSERR("MP3FileSource: unrecoverable frame level error, quitting.");
00586 }
00587
00588 frameCount_++;
00589 }
00590
00591
00592 mad_synth_frame(&synth, &frame);
00593
00594
00595
00596
00597 for (t=0; t < bufferSize_; t++) {
00598
00599 left_ch = synth.pcm.samples[0][t];
00600 sample = (mrs_real) scale(left_ch);
00601 sample *= peak;
00602
00603 reservoir_(0, ri_) = sample;
00604
00605
00606
00607
00608 if(MAD_NCHANNELS(&frame.header)==2) {
00609 right_ch = synth.pcm.samples[1][t];
00610 sample = (mrs_real) scale(right_ch);
00611 sample *= peak;
00612
00613
00614 reservoir_(1, ri_) = sample;
00615 }
00616
00617 ri_++;
00618 }
00619
00620 }
00621
00622
00623
00624 for (t=0; t < inSamples_; t++) {
00625 slice(0,t) = reservoir_(0,t);
00626 if (MAD_NCHANNELS(&frame.header)==2)
00627 {
00628 slice(1,t) = reservoir_(1,t);
00629 }
00630 }
00631
00632
00633
00634
00635 pos_ += inSamples_;
00636
00637
00638 currentPos_ = pos_;
00639
00640
00641
00642 for (t=inSamples_; t < ri_; t++) {
00643 reservoir_(0,t-inSamples_) = reservoir_(0,t);
00644 if (MAD_NCHANNELS(&frame.header)==2)
00645 reservoir_(1,t-inSamples_) = reservoir_(1,t);
00646 }
00647
00648
00649 ri_ = ri_ - inSamples_;
00650
00651 return pos_;
00652 #else
00653 return 0;
00654
00655 #endif
00656
00657 }
00658
00659
00665 void MP3FileSource::myProcess(realvec& in, realvec& out)
00666 {
00667 (void) in;
00668
00669
00670
00671 if (hasData_)
00672 getLinear16(out);
00673
00674
00675
00676
00677
00678
00679
00680
00681 ctrl_pos_->setValue(pos_, NOUPDATE);
00682
00683
00684 if (pos_ >= rewindpos_ + csize_)
00685 {
00686 if (repetitions_ != 1)
00687 {
00688 if (repetitions_ != 1)
00689 pos_ = rewindpos_;
00690
00691 mrs_real ratio = (mrs_real)pos_/size_;
00692
00693 #ifdef MARSYAS_MAD
00694 madStructInitialize();
00695 #endif
00696
00697 mrs_natural targetOffset = (mrs_natural) (fileSize_ * (mrs_real)ratio);
00698
00699
00700 if (targetOffset==0) {
00701 fillStream(-1);
00702 } else {
00703 fillStream(targetOffset);
00704 }
00705 currentPos_ = pos_;
00706 }
00707
00708 }
00709 samplesOut_ += onSamples_;
00710
00711
00712
00713 if (repetitions_ != 1)
00714 {
00715 hasData_ = (samplesOut_ < repetitions_ * csize_);
00716 lastTickWithData_ = ((samplesOut_ + onSamples_>= repetitions_ * csize_) && hasData_);
00717 }
00718 else
00719 {
00720 hasData_ = samplesOut_ < rewindpos_ + csize_;
00721 lastTickWithData_ = ((samplesOut_ + onSamples_ >= rewindpos_ + csize_) && hasData_);
00722 }
00723
00724 if (repetitions_ == -1)
00725 {
00726 hasData_ = true;
00727 lastTickWithData_ = false;
00728 }
00729
00730
00731
00732
00733 ctrl_currentHasData_->setValue(hasData_);
00734 ctrl_currentLastTickWithData_->setValue(lastTickWithData_);
00735
00736
00737 }
00738
00739
00740
00741
00742
00743 #ifdef MARSYAS_MAD
00744 void MP3FileSource::madStructInitialize() {
00745
00746 mad_stream_init(&stream);
00747 mad_frame_init(&frame);
00748 mad_synth_init(&synth);
00749 }
00750 #endif
00751
00752
00753
00754
00755
00756
00757 #ifdef MARSYAS_MAD
00758 void MP3FileSource::madStructFinish() {
00759
00760 mad_stream_finish(&stream);
00761 mad_frame_finish(&frame);
00762 mad_synth_finish(&synth);
00763 }
00764 #endif
00765
00766
00767
00768
00776 void
00777 MP3FileSource::fillStream( mrs_natural target )
00778 {
00779
00780
00781 #ifdef MARSYAS_MAD
00782 if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN)
00783 {
00784
00785 register mrs_natural remaining = 0;
00786 register mrs_natural chunk = INPUT_BUFFER_SIZE;
00787
00788
00789
00790
00791 if ( stream.next_frame != NULL ) {
00792 offset = stream.next_frame - ptr_;
00793 remaining = fileSize_ - offset;
00794 } else if ( target != 0 ) {
00795
00796 offset = target;
00797 remaining = fileSize_ - offset;
00798 } else if ( target == -1 ) {
00799
00800 offset = 0;
00801 remaining = fileSize_;
00802 }
00803
00804
00805
00806 if ( remaining < INPUT_BUFFER_SIZE ) {
00807 chunk = remaining + MAD_BUFFER_GUARD;
00808 }
00809
00810
00811 if ( offset >= fileSize_ ) {
00812 hasData_ = false;
00813
00814 } else {
00815
00816 if (offset == -1)
00817 offset = 1;
00818
00819 mad_stream_buffer(&stream, ptr_ + offset, chunk);
00820
00821 stream.error = MAD_ERROR_NONE;
00822 }
00823 }
00824
00825 #endif
00826 }
00827
00828
00829
00830
00831
00832
00833
00834
00842 void MP3FileSource::closeFile()
00843 {
00844
00845
00846 if (fp == NULL)
00847 return;
00848
00849 fclose(fp);
00850 fd = 0;
00851 pos_ = 0;
00852 currentPos_ = 0;
00853 size_ = 0;
00854 ctrl_pos_->setValue(0, NOUPDATE);
00855
00856 delete [] ptr_;
00857
00858
00859 #ifdef MARSYAS_MAD
00860 madStructFinish();
00861 #endif
00862 }
00863
00864
00865
00866
00881 #ifdef MARSYAS_MAD
00882 inline signed int MP3FileSource::scale(mad_fixed_t sample)
00883 {
00884
00885 sample += (1L << (MAD_F_FRACBITS - 16));
00886
00887
00888 if (sample >= MAD_F_ONE)
00889 sample = MAD_F_ONE - 1;
00890 else if (sample < -MAD_F_ONE)
00891 sample = -MAD_F_ONE;
00892
00893
00894 return sample >> (MAD_F_FRACBITS + 1 - 16);
00895 }
00896 #endif