Main Page | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages

mp3core.cpp

Go to the documentation of this file.
00001 
00006 #include <iostream>
00007 
00008 #include "mp3core.h"
00009 #include "mp3frame.h"
00010 #include "mp3iterator.h"
00011 #include "bitstream.h"
00012 #include "except.h"
00013 #include "conv.h"
00014 
00015 MP3Core::MP3Core()
00016 {
00017   m_outfile = 0;
00018   m_infiles = 0;
00019   m_showinfo = false;
00020   m_gain = 0;  
00021   m_cutstart = m_cutend = 0;
00022   m_autocutstart = false;
00023   m_autocutend = false;
00024   m_numframes = 0;
00025 }
00026 
00027 bool MP3Core::Params(int argc, const char *argv[])
00028 {
00029   int i;
00030   
00031   //Skip last argument, it must be a filename
00032   for(i = 1; i < argc - 1; i++)
00033   {
00034     if(argv[i][0] == '-' && argv[i][1]) 
00035     { //Arguments are one-character only, beginning with one dash
00036       switch(argv[i][1])
00037       {
00038         case 'h': //Show usage message
00039           return false;
00040         case 'o': //Output file
00041           m_outfile = argv[++i];
00042           break;
00043         case 'g': //Gain (need to be converted from dB to numbers used in MP3)
00044           m_gain = Conv::dB2Gain(argv[++i]);
00045           break;
00046         case 'v': //Show various information
00047           m_showinfo = true;
00048           break;
00049         case 'c': //Cut frames
00050           switch(argv[i][2])
00051           {
00052             case 's': //Cut from beginning
00053               if(*argv[++i] == 'a') //Autodetect silence
00054                 m_autocutstart = true;
00055               else //Convert time to frame number
00056                 m_cutstart = Conv::Time2Frame(argv[i]);
00057               break;
00058             case 'e': //Cut from end
00059               if(*argv[++i] == 'a') //Autodetect silence
00060                 m_autocutend = true;
00061               else //Convert time to frame number
00062                 m_cutend = Conv::Time2Frame(argv[i]);;
00063               break;
00064           }
00065           break;
00066         case 't': //Edit tag
00067           i += m_tag.ParseParam(argv[i][2], argv[i+1]);
00068           break;
00069       }
00070     }
00071     else
00072       break; //If this argument is not a parameter, all others (including this one) are input files
00073   }
00074   
00075   m_infiles = argv + i; //HACK: Input files are taken as they are (null terminated array of char*)
00076   return argc > i; //At least one input file is needed
00077 }
00078 
00079 void MP3Core::GetInfo()
00080 {
00081   bool start = m_autocutstart; //Whether we should detect silence at beginning
00082   int numloud = 0; //Number of continuous non-silent frames
00083   int avgbitrate = 0; //Average bitrate
00084   
00085   try {
00086     Bitstream bs(m_infiles, Bitstream::in); //Construct a Bitstream from all input files
00087     MP3Iterator frame(bs, MP3Frame::nowrite); //Iterator of all frames, write is turned off
00088     
00089     if(m_showinfo) //Show info from ID3 tags, bitrate, etc.
00090     {
00091       m_tag.Show(std::cout); //Show ID3 tag information
00092       frame->ShowInfo(std::cout); //Show bitrate, version, etc. of first frame
00093     }
00094     
00095     while(true) //Real processing
00096     {
00097       //Log corrupted frames (done here only if no write will be done)
00098       if( !m_outfile && frame->CorruptionFound() ) 
00099         std::cerr << "Corruption found at " << Conv::Frame2Time(m_numframes) << "!" << std::endl;
00100       
00101       avgbitrate += frame->Bitrate(); //Sum of bitrate (not yet average)
00102       m_numframes++; //Count frames
00103       
00104       if(m_autocutstart && start) //Detect silent frames at the beginning 
00105       {                           // (if requested and we're still at the beginning)
00106         if( frame->isSilent() )
00107         {  
00108           m_cutstart = m_numframes; //All frames since beginning are silent
00109           numloud = 0;
00110         }
00111         else if(++numloud > mp3::maxloud) //If there are more than mp3::maxloud consecutive
00112           start = false;                  // non-silent frames, the silent block has ended
00113       }
00114       
00115       if(m_autocutend && !start) //Detect silent frames at the end
00116       {
00117         if( frame->isSilent() ) //Silent frame ends a block of non-silent ones
00118           numloud = 0;
00119         else if(++numloud > mp3::maxloud) //Block of more than mp3::maxloud non-silent frames
00120           m_cutend = m_numframes;         // makes the detection began from zero (current frame)
00121       }
00122       
00123       ++frame;
00124     }
00125   }
00126   catch(eEOF) //End of last input file
00127   {
00128     avgbitrate /= m_numframes; //Sum -> average
00129     
00130     if(m_autocutend) //Convert frame number to count of frames till the end of file
00131       m_cutend = m_numframes - m_cutend;
00132     
00133     if(m_showinfo) //Display file duration, bitrate and detected silence
00134     {  
00135       std::cout << "Duration: " << Conv::Frame2Time(m_numframes) << std::endl;
00136       std::cout << "Average bitrate: " << avgbitrate << " kbps" << std::endl;
00137       
00138       if(m_autocutstart || m_autocutend)
00139         std::cout << "Silence: " << Conv::Frame2Time(m_cutstart) << " at the beginning and " 
00140                                   << Conv::Frame2Time(m_cutend) << " at the end." << std::endl;
00141     }
00142   }
00143 }
00144 
00145 bool MP3Core::WriteResult()
00146 {
00147   int j = 0; //Number of current frame
00148   
00149   try {
00150     Bitstream bs(m_infiles, Bitstream::in); //Open input file(s)
00151     Bitstream bs_out(m_outfile, Bitstream::out); //Open output file
00152     
00153     //Get first frames, frames can be written in "fast" mode when there's no need do move data
00154     // (when no frames are removed from beginning and we're processing just one input file)
00155     MP3Iterator frame(bs, (m_cutstart == 0) ? MP3Frame::fastwrite : MP3Frame::normal);
00156     
00157     while(true) //Real processing
00158     {
00159       if( frame->CorruptionFound() ) //Log corrupted frames 
00160         std::cerr << "Corruption found at " << Conv::Frame2Time(j) << "!" << std::endl;
00161       
00162       if(m_gain) frame->ChangeGain(m_gain); //Change frame volume
00163       
00164       if(m_cutend && j >= m_numframes - m_cutend) //Immediately exit when no more
00165         break;                                    // frames should be written
00166       
00167       //### When this frame should be first, it must be set first in stream, otherwise
00168       //### data would be written from really first frame and things would break 
00169       if(j == m_cutstart)    
00170         frame->SetFirst(); 
00171       
00172       if(j >= m_cutstart) //Finally write the frame
00173         try {
00174           frame->Write(bs_out);
00175         } 
00176         catch(eCannotProceed e) //When frames needs to be enlarged
00177         {                       // but it already has maximum size
00178           std::cerr << "Sorry, this operation is not possible: " << e.what() << std::endl;
00179           return false;
00180         }
00181       
00182       ++frame; //Next frame (iterator)
00183       j++;
00184     }
00185   } 
00186   catch(eEOF) { } //EOF is normal end of processing loop
00187   
00188   m_tag.Write(m_outfile);
00189   return true;    
00190 }
00191 
00192 bool MP3Core::Process()
00193 {
00194   try {
00195     m_tag.Read(*m_infiles); //Extract tags
00196     
00197     //Process files (without writing) if needed
00198     if(m_showinfo || m_cutend || m_autocutstart || m_autocutend || !m_outfile)
00199       GetInfo();
00200     
00201     if(m_outfile) //Write result if output file was given
00202       return WriteResult();
00203   }
00204   catch(eOpenFailed e)
00205   {
00206     std::cerr << "Can't open file `" << e.filename() << "'!" << std::endl;
00207     return false;
00208   }
00209 
00210   return true; //Just to please compiler
00211 }
00212 
00213 void MP3Core::ShowHelp(const char *filename)
00214 {
00215   std::cout << "Tool for various lossless operations on MP3 files." << std::endl; 
00216   std::cout << "Usage: " << filename << " [parameters] input files" << std::endl;
00217   std::cout << "Parameters: " << std::endl;
00218   std::cout << "  -o file.mp3  Output file (input files are never changed!) " << std::endl;
00219   std::cout << "  -g N         Change volume by N dB " << std::endl;
00220   std::cout << "  -v           Show file duration, bitrate, tag information etc. " << std::endl;
00221   std::cout << "  -cs time     Cut specified time from beginning of file, " << std::endl;
00222   std::cout << "               if time is 'a', digital silence is removed " << std::endl;
00223   std::cout << "  -cs time     Cut specified time from end of file, " << std::endl;
00224   std::cout << "               if time is 'a', digital silence is removed " << std::endl;
00225   std::cout << "  -t1          Keep ID3v1 tag (or create when some field is set) " << std::endl;
00226   std::cout << "  -t2          Keep ID3v1 tag (or create when some field is set) " << std::endl;
00227   std::cout << "  -tx          Don't read ID3 tags, create from scratch " << std::endl;
00228   std::cout << "  -tt value    Set Title field in ID3 tag " << std::endl;
00229   std::cout << "  -ta value    Set Artist field in ID3 tag " << std::endl;
00230   std::cout << "  -tA value    Set Album field in ID3 tag " << std::endl;
00231   std::cout << "  -tn value    Set Track Number in ID3 tag " << std::endl;
00232   std::cout << "  -ty value    Set Year field in ID3 tag " << std::endl;
00233   std::cout << "  -tc value    Set Comment field in ID3 tag " << std::endl;
00234   std::cout << "  -tg value    Set Genre field in ID3 tag " << std::endl;
00235   std::cout << "               (only standard ID3 genres can be used) " << std::endl;
00236 }

Generated on Wed Sep 6 00:17:57 2006 for Kraken by  doxygen 1.4.4