Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/MP3FileSink.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 "MP3FileSink.h"
00021 
00022 #include "lame/lame.h"
00023 
00024 using std::ostringstream;
00025 using namespace Marsyas;
00026 
00027 MP3FileSink::MP3FileSink(mrs_string name):AbsSoundFileSink("MP3FileSink",name)
00028 {
00029   //type_ = "MP3FileSink";
00030   //name_ = name;
00031   gfp_ = NULL;
00032   sfp_ = NULL;
00033   leftpcm_ = NULL;
00034   rightpcm_ = NULL;
00035 
00036   mp3Buffer_ = NULL;
00037   addControls();
00038 }
00039 
00040 MP3FileSink::~MP3FileSink()
00041 {
00042 
00043 
00044   if (sfp_)
00045   {
00046     mrs_natural encodeCheck = lame_encode_flush(gfp_, mp3Buffer_, 0);
00047     mrs_natural owrite = (int) fwrite(mp3Buffer_, 1, encodeCheck, sfp_);
00048     if (owrite != encodeCheck) {
00049       MRSWARN("Writing MP3 data to "+filename_+" failed.");
00050     }
00051     fclose(sfp_);
00052   }
00053 
00054 
00055   delete [] mp3Buffer_;
00056   delete [] leftpcm_;
00057   delete [] rightpcm_;
00058 }
00059 
00060 MarSystem*
00061 MP3FileSink::clone() const
00062 {
00063   return new MP3FileSink(*this);
00064 }
00065 
00066 void
00067 MP3FileSink::addControls()
00068 {
00069   addctrl("mrs_string/filename", "default");
00070   setctrlState("mrs_string/filename", true);
00071   addctrl("mrs_natural/bitrate", 128);
00072   setctrlState("mrs_natural/bitrate", true);
00073   addctrl("mrs_natural/encodingQuality", 2);
00074   setctrlState("mrs_natural/encodingQuality", true);
00075   addctrl("mrs_string/id3tags", "noTitle|noArtist|noAlbum|1978|noComment|1|0");  // 1: track one O Blues genreopen
00076   setctrlState("mrs_string/filename", true);
00077 }
00078 
00079 bool
00080 MP3FileSink::checkExtension(mrs_string filename)
00081 {
00082   FileName fn(filename);
00083   mrs_string mp3ext  = "mp3";
00084 
00085   if (fn.ext() == mp3ext)
00086     return true;
00087   else
00088     return false;
00089 }
00090 
00091 void
00092 MP3FileSink::myUpdate(MarControlPtr sender)
00093 {
00094   (void) sender;  //suppress warning of unused parameter(s)
00095   MRSDIAG("MP3FileSink::myUpdate");
00096 
00097   setctrl("mrs_natural/onSamples", getctrl("mrs_natural/inSamples"));
00098   setctrl("mrs_natural/onObservations", getctrl("mrs_natural/inObservations"));
00099   setctrl("mrs_real/osrate", getctrl("mrs_real/israte"));
00100 
00101   nChannels_ = getctrl("mrs_natural/inObservations")->to<mrs_natural>();
00102 
00103   // initialize to default encoding parameters
00104   gfp_ = lame_init();
00105 
00106   mrs_natural lameNbChannels = getctrl("mrs_natural/inObservations")->to<mrs_natural>();
00107   delete [] mp3Buffer_;
00108   mrs_natural mp3BufferSize = (int) ceil(1.25*inSamples_ + 7200);
00109   mp3Buffer_ = new unsigned char[mp3BufferSize]; //[LAME_MAXMP3BUFFER];
00110   delete [] leftpcm_;
00111   delete [] rightpcm_;
00112   leftpcm_ = new short[getctrl("mrs_natural/inSamples")->to<mrs_natural>()];
00113   rightpcm_ = new short[getctrl("mrs_natural/inSamples")->to<mrs_natural>()];
00114 
00115   if (lameNbChannels>2) {
00116     MRSWARN("Lame can handle up to 2 channels. Only the first 2 observation vectors will be written.");
00117     lameNbChannels = 2;
00118   }
00119   if (lameNbChannels==1)
00120     lame_set_mode(gfp_, (MPEG_mode) 3); // mode = 0,1,2,3 = stereo, jstereo, dual channel (not supported), mono
00121   else
00122     lame_set_mode(gfp_, (MPEG_mode) 1);
00123 
00124   lame_set_num_channels(gfp_,lameNbChannels);
00125   lame_set_in_samplerate(gfp_,(int) ceil(getctrl("mrs_real/israte")->to<mrs_real>()));
00126   lame_set_brate(gfp_,128); // ,(int) ceil(getctrl("mrs_natural/bitrate")->to<mrs_natural>())
00127   lame_set_quality(gfp_,2);   /* 2=high  5 = medium  7=low */ // ,(int) ceil(getctrl("mrs_natural/encodingQuality")->to<mrs_natural>())
00128 
00129   // split id3 string
00130   mrs_string id3tags = getctrl("mrs_string/id3tags")->to<mrs_string>();
00131   mrs_natural pos=0;
00132   pos = id3tags.find("|", 0);
00133   id3tag_set_title(gfp_, id3tags.substr(0, pos).c_str());
00134   id3tags = id3tags.substr(pos+1);
00135   pos = id3tags.find("|", 0);
00136   id3tag_set_artist(gfp_, id3tags.substr(0, pos).c_str());
00137   id3tags = id3tags.substr(pos+1);
00138   pos = id3tags.find("|", 0);
00139   id3tag_set_album(gfp_, id3tags.substr(0, pos).c_str());
00140   id3tags = id3tags.substr(pos+1);
00141   pos = id3tags.find("|", 0);
00142   id3tag_set_year(gfp_, id3tags.substr(0, pos).c_str());
00143   id3tags = id3tags.substr(pos+1);
00144   pos = id3tags.find("|", 0);
00145   id3tag_set_comment(gfp_, id3tags.substr(0, pos).c_str());
00146   id3tags = id3tags.substr(pos+1);
00147   pos = id3tags.find("|", 0);
00148   id3tag_set_track(gfp_, id3tags.substr(0, pos).c_str());
00149   id3tags = id3tags.substr(pos+1);
00150   pos = id3tags.find("|", 0);
00151   id3tag_set_genre(gfp_, id3tags.substr(0, pos).c_str());
00152 
00153   int ret_code = lame_init_params(gfp_);
00154   if (ret_code == -1)
00155     MRSWARN("Initialization of the lame encoder failed.");
00156 
00157 
00158 
00159   filename_ = getctrl("mrs_string/filename")->to<mrs_string>();
00160 }
00161 
00162 void
00163 MP3FileSink::putHeader(mrs_string filename)
00164 {
00165   sfp_ = fopen(filename.c_str(), "wb");
00166 }
00167 
00168 void
00169 MP3FileSink::myProcess(realvec& in, realvec& out)
00170 {
00171 
00172 
00173   mrs_natural t,o;
00174 
00175   // copy input to output
00176   for (o=0; o < inObservations_; o++)
00177     for (t=0; t < inSamples_; t++)
00178     {
00179       out(o,t) = in(o,t);
00180     }
00181 
00182   mrs_natural encodeCheck=-1;
00183 
00184   // fill left buffer
00185   for (t=0; t < inSamples_; t++)
00186     leftpcm_[t] = (short)(in(0,t) * PCM_MAXSHRT);
00187   if (inObservations_>1) {
00188 // fill right buffer
00189     for (t=0; t < inSamples_; t++)
00190       rightpcm_[t] = (short)(in(1,t) * PCM_MAXSHRT);
00191 
00192     encodeCheck = lame_encode_buffer(gfp_,
00193                                      leftpcm_, rightpcm_,
00194                                      inSamples_, mp3Buffer_, 0);
00195   }
00196   else
00197     encodeCheck = lame_encode_buffer(gfp_,
00198                                      leftpcm_, leftpcm_,
00199                                      inSamples_, mp3Buffer_,0); // [ML] 0 do not check for buffer size, should be sizeof(mp3Buffer_) but check fails
00200 
00201 
00202   /* was our output buffer big enough? */
00203   if (encodeCheck < 0) {
00204     if (encodeCheck == -1) {
00205       MRSWARN("mp3 buffer is not big enough... \n");
00206     }
00207     else
00208       MRSWARN("mp3 internal error");
00209   }
00210   mrs_natural owrite = (int) fwrite(mp3Buffer_, 1, encodeCheck, sfp_);
00211   if (owrite != encodeCheck) {
00212     MRSWARN("Writing MP3 data to "+filename_+" failed.");
00213   }
00214 
00215 
00216 
00217 }
00218 
00219 
00220 
00221 
00222 
00223 
00224 
00225 
00226 
00227 
00228 
00229 
00230 
00231 
00232 
00233 
00234 
00235