Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

LameLibEncoder.cpp

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002 
00003    Copyright (c) 2000 Tyrell Corporation. All rights reserved.
00004 
00005    Tyrell DarkIce
00006 
00007    File     : LameLibEncoder.cpp
00008    Version  : $Revision: 1.19 $
00009    Author   : $Author: jbebel $
00010    Location : $Source: /cvsroot/darkice/darkice/src/LameLibEncoder.cpp,v $
00011    
00012    Copyright notice:
00013 
00014     This program is free software; you can redistribute it and/or
00015     modify it under the terms of the GNU General Public License  
00016     as published by the Free Software Foundation; either version 2
00017     of the License, or (at your option) any later version.
00018    
00019     This program is distributed in the hope that it will be useful,
00020     but WITHOUT ANY WARRANTY; without even the implied warranty of 
00021     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
00022     GNU General Public License for more details.
00023    
00024     You should have received a copy of the GNU General Public License
00025     along with this program; if not, write to the Free Software
00026     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00027 
00028 ------------------------------------------------------------------------------*/
00029 
00030 /* ============================================================ include files */
00031 
00032 #ifdef HAVE_CONFIG_H
00033 #include "config.h"
00034 #endif
00035 
00036 // compile the whole file only if lame support configured in
00037 #ifdef HAVE_LAME_LIB
00038 
00039 
00040 
00041 #include "Exception.h"
00042 #include "Util.h"
00043 #include "LameLibEncoder.h"
00044 
00045 
00046 /* ===================================================  local data structures */
00047 
00048 
00049 /* ================================================  local constants & macros */
00050 
00051 /*------------------------------------------------------------------------------
00052  *  File identity
00053  *----------------------------------------------------------------------------*/
00054 static const char fileid[] = "$Id: LameLibEncoder.cpp,v 1.19 2005/04/13 19:04:55 jbebel Exp $";
00055 
00056 
00057 /* ===============================================  local function prototypes */
00058 
00059 
00060 /* =============================================================  module code */
00061 
00062 /*------------------------------------------------------------------------------
00063  *  Open an encoding session
00064  *----------------------------------------------------------------------------*/
00065 bool
00066 LameLibEncoder :: open ( void )
00067                                                             throw ( Exception )
00068 {
00069     if ( isOpen() ) {
00070         close();
00071     }
00072 
00073     // open the underlying sink
00074     if ( !sink->open() ) {
00075         throw Exception( __FILE__, __LINE__,
00076                          "lame lib opening underlying sink error");
00077     }
00078  
00079     lameGlobalFlags = lame_init();
00080 
00081     // ugly lame returns -1 in a pointer on allocation errors
00082     if ( !lameGlobalFlags || ((int)lameGlobalFlags) == -1 ) {
00083         throw Exception( __FILE__, __LINE__,
00084                          "lame lib init error",
00085                          (int) lameGlobalFlags);
00086     }
00087 
00088     if ( 0 > lame_set_num_channels( lameGlobalFlags, getInChannel()) ) {
00089         throw Exception( __FILE__, __LINE__,
00090                          "lame lib setting channels error",
00091                          getInChannel() );
00092     }
00093 
00094     if ( 0 > lame_set_mode( lameGlobalFlags,
00095                             getOutChannel() == 1 ? MONO : JOINT_STEREO) ) {
00096         throw Exception( __FILE__, __LINE__,
00097                          "lame lib setting mode error",
00098                          JOINT_STEREO );
00099     }
00100 
00101     reportEvent( 5, "set lame mode", lame_get_mode( lameGlobalFlags));
00102     
00103     reportEvent( 5,
00104                  "set lame channels",
00105                  lame_get_num_channels( lameGlobalFlags));
00106     
00107     if ( 0 > lame_set_in_samplerate( lameGlobalFlags, getInSampleRate()) ) {
00108         throw Exception( __FILE__, __LINE__,
00109                          "lame lib setting input sample rate error",
00110                          getInSampleRate() );
00111     }
00112 
00113     reportEvent( 5,
00114                  "set lame in sample rate",
00115                  lame_get_in_samplerate( lameGlobalFlags));
00116     
00117     if ( 0 > lame_set_out_samplerate( lameGlobalFlags, getOutSampleRate()) ) {
00118         throw Exception( __FILE__, __LINE__,
00119                          "lame lib setting output sample rate error",
00120                          getOutSampleRate() );
00121     }
00122 
00123     reportEvent( 5,
00124                  "set lame out sample rate",
00125                  lame_get_out_samplerate( lameGlobalFlags));
00126     
00127     switch ( getOutBitrateMode() ) {
00128         
00129         case cbr: {
00130 
00131             if ( 0 > lame_set_brate( lameGlobalFlags, getOutBitrate()) ) {
00132                 throw Exception( __FILE__, __LINE__,
00133                                 "lame lib setting output bit rate error",
00134                                 getOutBitrate() );
00135             }
00136             
00137             reportEvent( 5,
00138                          "set lame bit rate",
00139                          lame_get_brate( lameGlobalFlags));
00140             
00141             double  d = (1.0 - getOutQuality()) * 10.0;
00142 
00143             if ( d > 9 ) {
00144                 d = 9;
00145             }
00146 
00147             int     q = int (d);
00148 
00149             if ( 0 > lame_set_quality( lameGlobalFlags, q) ) {
00150                 throw Exception( __FILE__, __LINE__,
00151                                 "lame lib setting quality error", q);
00152             }
00153             
00154             reportEvent( 5,
00155                          "set lame quality",
00156                          lame_get_quality( lameGlobalFlags));
00157             } break;
00158 
00159         case abr:
00160 
00161             if ( 0 > lame_set_VBR( lameGlobalFlags,vbr_abr)) {
00162                 throw Exception( __FILE__, __LINE__,
00163                                  "lame lib setting abr error", vbr_abr);
00164             }
00165             
00166             reportEvent( 5,
00167                          "set lame abr bitrate",
00168                          lame_get_VBR( lameGlobalFlags));
00169             
00170             if ( 0 > lame_set_VBR_mean_bitrate_kbps( lameGlobalFlags,
00171                                                      getOutBitrate())) {
00172                 throw Exception( __FILE__, __LINE__,
00173                                  "lame lib setting abr mean bitrate error",
00174                                  getOutBitrate());
00175             }
00176             
00177             reportEvent( 5,
00178                          "set lame abr mean bitrate", 
00179                          lame_get_VBR_mean_bitrate_kbps( lameGlobalFlags));
00180             break;
00181 
00182         case vbr: {
00183         
00184             if ( 0 > lame_set_VBR( lameGlobalFlags, vbr_mtrh)) {
00185                 throw Exception( __FILE__, __LINE__,
00186                                  "lame lib setting vbr error", vbr_mtrh );
00187             }
00188         
00189             reportEvent( 5,
00190                          "set lame vbr bitrate",
00191                          lame_get_VBR( lameGlobalFlags));
00192 
00193             double  d = (1.0 - getOutQuality()) * 10.0;
00194 
00195             if ( d > 9 ) {
00196                 d = 9;
00197             }
00198 
00199             int     q = int (d);
00200 
00201             if ( 0 > lame_set_VBR_q( lameGlobalFlags, q) ) {
00202                 throw Exception( __FILE__, __LINE__,
00203                                  "lame lib setting vbr quality error", q);
00204             }
00205         
00206             reportEvent( 5,
00207                          "set lame vbr quality",
00208                          lame_get_VBR_q( lameGlobalFlags));
00209             } break;
00210     }
00211 
00212 
00213     if ( 0 > lame_set_lowpassfreq( lameGlobalFlags, lowpass) ) {
00214         throw Exception( __FILE__, __LINE__,
00215                          "lame lib setting lowpass frequency error",
00216                          lowpass );
00217     }
00218 
00219     reportEvent( 5,
00220                  "set lame lowpass frequency",
00221                  lame_get_lowpassfreq( lameGlobalFlags));
00222     
00223     if ( 0 > lame_set_highpassfreq( lameGlobalFlags, highpass) ) {
00224         throw Exception( __FILE__, __LINE__,
00225                          "lame lib setting highpass frequency error",
00226                          lowpass );
00227     }
00228 
00229     reportEvent( 5,
00230                  "set lame highpass frequency",
00231                  lame_get_highpassfreq( lameGlobalFlags));
00232 
00233 
00234     
00235     
00236     // not configurable lame settings
00237     
00238     if ( 0 > lame_set_exp_nspsytune( lameGlobalFlags, 1) ) {
00239         throw Exception( __FILE__, __LINE__,
00240                          "lame lib setting  psycho acoustic model error");
00241     }
00242 
00243     reportEvent( 5,
00244                  "set lame psycho acoustic model",
00245                  lame_get_exp_nspsytune( lameGlobalFlags));
00246     
00247     if ( 0 > lame_set_error_protection( lameGlobalFlags, 1) ) {
00248         throw Exception( __FILE__, __LINE__,
00249                          "lame lib setting error protection error",
00250                          1 );
00251     }
00252 
00253     reportEvent( 5,
00254                  "set lame error protection",
00255                  lame_get_error_protection( lameGlobalFlags));
00256 
00257     // let lame init its own params based on our settings
00258     if ( 0 > lame_init_params( lameGlobalFlags) ) {
00259         throw Exception( __FILE__, __LINE__,
00260                          "lame lib initializing params error" );
00261     }
00262 
00263     lame_print_config( lameGlobalFlags);
00264 
00265     return true;
00266 }
00267 
00268 
00269 /*------------------------------------------------------------------------------
00270  *  Write data to the encoder
00271  *----------------------------------------------------------------------------*/
00272 unsigned int
00273 LameLibEncoder :: write (   const void    * buf,
00274                             unsigned int    len )           throw ( Exception )
00275 {
00276     if ( !isOpen() || len == 0 ) {
00277         return 0;
00278     }
00279 
00280     unsigned int    bitsPerSample = getInBitsPerSample();
00281     unsigned int    inChannels    = getInChannel();
00282 
00283     unsigned int    sampleSize = (bitsPerSample / 8) * inChannels;
00284     unsigned char * b = (unsigned char*) buf;
00285     unsigned int    processed = len - (len % sampleSize);
00286     unsigned int    nSamples = processed / sampleSize;
00287     short int     * leftBuffer  = new short int[nSamples];
00288     short int     * rightBuffer = new short int[nSamples];
00289 
00290     if ( bitsPerSample == 8 ) {
00291         Util::conv8( b, processed, leftBuffer, rightBuffer, inChannels);
00292     } else if ( bitsPerSample == 16 ) {
00293         Util::conv16( b,
00294                       processed,
00295                       leftBuffer,
00296                       rightBuffer,
00297                       inChannels,
00298                       isInBigEndian());
00299     } else {
00300         delete[] leftBuffer;
00301         delete[] rightBuffer;
00302         throw Exception( __FILE__, __LINE__,
00303                         "unsupported number of bits per sample for the encoder",
00304                          bitsPerSample );
00305     }
00306 
00307     // data chunk size estimate according to lame documentation
00308     // NOTE: mp3Size is calculated based on the number of input channels
00309     //       which may be bigger than need, as output channels can be less
00310     unsigned int    mp3Size = (unsigned int) (1.25 * nSamples + 7200);
00311     unsigned char * mp3Buf  = new unsigned char[mp3Size];
00312     int             ret;
00313 
00314     ret = lame_encode_buffer( lameGlobalFlags,
00315                               leftBuffer,
00316                               inChannels == 2 ? rightBuffer : leftBuffer,
00317                               nSamples,
00318                               mp3Buf,
00319                               mp3Size );
00320 
00321     delete[] leftBuffer;
00322     delete[] rightBuffer;
00323 
00324     if ( ret < 0 ) {
00325         reportEvent( 3, "lame encoding error", ret);
00326         delete[] mp3Buf;
00327         return 0;
00328     }
00329 
00330     unsigned int    written = sink->write( mp3Buf, ret);
00331     delete[] mp3Buf;
00332     // just let go data that could not be written
00333     if ( written < (unsigned int) ret ) {
00334         reportEvent( 2,
00335                      "couldn't write all from encoder to underlying sink",
00336                      ret - written);
00337     }
00338 
00339     return processed;
00340 }
00341 
00342 
00343 /*------------------------------------------------------------------------------
00344  *  Flush the data from the encoder
00345  *----------------------------------------------------------------------------*/
00346 void
00347 LameLibEncoder :: flush ( void )
00348                                                             throw ( Exception )
00349 {
00350     if ( !isOpen() ) {
00351         return;
00352     }
00353 
00354     // data chunk size estimate according to lame documentation
00355     unsigned int    mp3Size = 7200;
00356     unsigned char * mp3Buf  = new unsigned char[mp3Size];
00357     int             ret;
00358 
00359     ret = lame_encode_flush( lameGlobalFlags, mp3Buf, mp3Size );
00360 
00361     unsigned int    written = sink->write( mp3Buf, ret);
00362     delete[] mp3Buf;
00363 
00364     // just let go data that could not be written
00365     if ( written < (unsigned int) ret ) {
00366         reportEvent( 2,
00367                      "couldn't write all from encoder to underlying sink",
00368                      ret - written);
00369     }
00370 
00371     sink->flush();
00372 }
00373 
00374 
00375 /*------------------------------------------------------------------------------
00376  *  Close the encoding session
00377  *----------------------------------------------------------------------------*/
00378 void
00379 LameLibEncoder :: close ( void )                    throw ( Exception )
00380 {
00381     if ( isOpen() ) {
00382         flush();
00383         lame_close( lameGlobalFlags);
00384         lameGlobalFlags = 0;
00385 
00386         sink->close();
00387     }
00388 }
00389 
00390 
00391 #endif // HAVE_LAME_LIB
00392 
00393 
00394 /*------------------------------------------------------------------------------
00395  
00396   $Source: /cvsroot/darkice/darkice/src/LameLibEncoder.cpp,v $
00397 
00398   $Log: LameLibEncoder.cpp,v $
00399   Revision 1.19  2005/04/13 19:04:55  jbebel
00400   Distribute lame qualities better, and prevent values greater than 9 which are invalid.
00401 
00402   Revision 1.18  2002/10/19 13:31:46  darkeye
00403   some cleanup with the open() / close() functions
00404 
00405   Revision 1.17  2002/10/19 12:22:10  darkeye
00406   return 0 immediately for write() if supplied length is 0
00407 
00408   Revision 1.16  2002/08/04 10:26:06  darkeye
00409   added additional error checking to make sure that outChannel < inChannel
00410 
00411   Revision 1.15  2002/08/03 12:41:18  darkeye
00412   added possibility to stream in mono when recording in stereo
00413 
00414   Revision 1.14  2002/07/28 00:11:58  darkeye
00415   bugfix for the previous fix :)
00416 
00417   Revision 1.13  2002/07/28 00:08:37  darkeye
00418   bugfix: mp3Buf was deleted too early
00419 
00420   Revision 1.12  2002/05/28 12:35:41  darkeye
00421   code cleanup: compiles under gcc-c++ 3.1, using -pedantic option
00422 
00423   Revision 1.11  2002/04/13 11:26:00  darkeye
00424   added cbr, abr and vbr setting feature with encoding quality
00425 
00426   Revision 1.10  2002/03/28 16:38:37  darkeye
00427   moved functions conv8() and conv16() to class Util
00428 
00429   Revision 1.9  2001/10/20 10:56:45  darkeye
00430   added possibility to disable highpass and lowpass filters for lame
00431 
00432   Revision 1.8  2001/10/19 12:39:42  darkeye
00433   created configure options to compile with or without lame / Ogg Vorbis
00434 
00435   Revision 1.7  2001/09/18 14:57:19  darkeye
00436   finalized Solaris port
00437 
00438   Revision 1.6  2001/09/15 11:35:08  darkeye
00439   minor fixes
00440 
00441   Revision 1.5  2001/09/02 09:54:12  darkeye
00442   fixed typos in CVS substition keywords
00443 
00444   Revision 1.4  2001/08/31 20:09:05  darkeye
00445   added funcitons conv8() and conv16()
00446 
00447   Revision 1.3  2001/08/30 17:25:56  darkeye
00448   renamed configure.h to config.h
00449 
00450   Revision 1.2  2001/08/29 21:06:16  darkeye
00451   added real support for 8 / 16 bit mono / stereo input
00452   (8 bit input still has to be spread on 16 bit words)
00453 
00454   Revision 1.1  2001/08/26 20:44:30  darkeye
00455   removed external command-line encoder support
00456   replaced it with a shared-object support for lame with the possibility
00457   of static linkage
00458 
00459 
00460   
00461 ------------------------------------------------------------------------------*/
00462 

Generated on Sat Oct 22 13:17:04 2005 for DarkIce by  doxygen 1.4.4