2010-01-23 19:44:49 +00:00
/**********************************************************************
Audacity : A Digital Audio Editor
ExportMP3 . cpp
Joshua Haberman
This just acts as an interface to LAME . A Lame dynamic library must
be present
The difficulty in our approach is that we are attempting to use LAME
in a way it was not designed to be used . LAME ' s API is reasonably
consistant , so if we were linking directly against it we could expect
this code to work with a variety of different LAME versions . However ,
the data structures change from version to version , and so linking
with one version of the header and dynamically linking against a
different version of the dynamic library will not work correctly .
The solution is to find the lowest common denominator between versions .
The bare minimum of functionality we must use is this :
1. Initialize the library .
2. Set , at minimum , the following global options :
i . input sample rate
ii . input channels
3. Encode the stream
4. Call the finishing routine
Just so that it ' s clear that we ' re NOT free to use whatever features
of LAME we like , I ' m not including lame . h , but instead enumerating
here the extent of functions and structures that we can rely on being
able to import and use from a dynamic library .
For the record , we aim to support LAME 3.70 on . Since LAME 3.70 was
released in April of 2000 , that should be plenty .
Copyright 2002 , 2003 Joshua Haberman .
Some portions may be Copyright 2003 Paolo Patruno .
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /**
\ class MP3Exporter
\ brief Class used to export MP3 files
*/ /********************************************************************/
2019-03-22 15:01:00 +00:00
# include "../Audacity.h" // for USE_* macros
2015-06-18 14:24:36 +00:00
# include "ExportMP3.h"
2016-11-22 18:16:03 +00:00
# include <wx/app.h>
2010-01-23 19:44:49 +00:00
# include <wx/defs.h>
# include <wx/choice.h>
2016-04-01 20:46:32 +00:00
# include <wx/checkbox.h>
2010-01-23 19:44:49 +00:00
# include <wx/dynlib.h>
# include <wx/ffile.h>
2017-08-02 16:41:29 +00:00
# include <wx/filedlg.h>
2010-01-23 19:44:49 +00:00
# include <wx/intl.h>
# include <wx/log.h>
# include <wx/mimetype.h>
# include <wx/radiobut.h>
# include <wx/stattext.h>
# include <wx/textctrl.h>
# include <wx/timer.h>
# include <wx/utils.h>
# include <wx/window.h>
2011-03-06 20:58:33 +00:00
# include "../FileNames.h"
2010-01-23 19:44:49 +00:00
# include "../float_cast.h"
# include "../Mix.h"
# include "../Prefs.h"
2019-05-29 15:31:40 +00:00
# include "../ProjectSettings.h"
2019-05-29 16:05:22 +00:00
# include "../ProjectWindow.h"
2015-06-18 14:24:36 +00:00
# include "../ShuttleGui.h"
2010-01-23 19:44:49 +00:00
# include "../Tags.h"
2019-05-06 23:00:10 +00:00
# include "../Track.h"
2017-10-18 08:14:45 +00:00
# include "../widgets/HelpSystem.h"
2019-05-20 18:27:11 +00:00
# include "../widgets/AudacityMessageBox.h"
2019-03-31 20:12:07 +00:00
# include "../widgets/ProgressDialog.h"
2010-01-23 19:44:49 +00:00
# include "Export.h"
2012-06-25 01:41:57 +00:00
# include <lame/lame.h>
2010-01-23 19:44:49 +00:00
2014-06-03 20:30:19 +00:00
# ifdef USE_LIBID3TAG
2010-01-23 19:44:49 +00:00
# include <id3tag.h>
# endif
//----------------------------------------------------------------------------
// ExportMP3Options
//----------------------------------------------------------------------------
2019-04-03 01:00:35 +00:00
enum MP3ChannelMode : unsigned {
CHANNEL_JOINT = 0 ,
CHANNEL_STEREO = 1 ,
CHANNEL_MONO = 2 ,
} ;
enum : int {
QUALITY_0 = 0 ,
QUALITY_1 = 1 ,
QUALITY_2 = 2 ,
QUALITY_3 = 3 ,
QUALITY_4 = 4 ,
QUALITY_5 = 5 ,
QUALITY_6 = 6 ,
QUALITY_7 = 7 ,
QUALITY_8 = 8 ,
QUALITY_9 = 9 ,
ROUTINE_FAST = 0 ,
ROUTINE_STANDARD = 1 ,
PRESET_INSANE = 0 ,
PRESET_EXTREME = 1 ,
PRESET_STANDARD = 2 ,
PRESET_MEDIUM = 3 ,
} ;
2010-01-23 19:44:49 +00:00
// Note: The label field is what will be written to preferences and carries
// no numerical significance. It is simply a means to look up a value
// in a table.
//
// The entries should be listed in order you want them to appear in the
// choice dropdown based on the name field.
typedef struct
{
wxString name ;
int label ;
} CHOICES ;
static CHOICES fixRates [ ] =
{
/* i18n-hint: kbps is the bitrate of the MP3 file, kilobits per second*/
2016-04-07 12:15:31 +00:00
{ wxT ( " " ) , 320 } ,
2010-01-23 19:44:49 +00:00
{ wxT ( " " ) , 256 } ,
2016-04-07 12:15:31 +00:00
{ wxT ( " " ) , 224 } ,
{ wxT ( " " ) , 192 } ,
{ wxT ( " " ) , 160 } ,
{ wxT ( " " ) , 144 } ,
{ wxT ( " " ) , 128 } ,
{ wxT ( " " ) , 112 } ,
{ wxT ( " " ) , 96 } ,
{ wxT ( " " ) , 80 } ,
{ wxT ( " " ) , 64 } ,
{ wxT ( " " ) , 56 } ,
{ wxT ( " " ) , 48 } ,
{ wxT ( " " ) , 40 } ,
{ wxT ( " " ) , 32 } ,
{ wxT ( " " ) , 24 } ,
{ wxT ( " " ) , 16 } ,
{ wxT ( " " ) , 8 }
2010-01-23 19:44:49 +00:00
} ;
static CHOICES varRates [ ] =
{
{ wxT ( " " ) , QUALITY_0 } ,
{ wxT ( " " ) , QUALITY_1 } ,
{ wxT ( " " ) , QUALITY_2 } ,
{ wxT ( " " ) , QUALITY_3 } ,
{ wxT ( " " ) , QUALITY_4 } ,
{ wxT ( " " ) , QUALITY_5 } ,
{ wxT ( " " ) , QUALITY_6 } ,
{ wxT ( " " ) , QUALITY_7 } ,
{ wxT ( " " ) , QUALITY_8 } ,
2016-04-07 12:15:31 +00:00
{ wxT ( " " ) , QUALITY_9 }
2010-01-23 19:44:49 +00:00
} ;
2018-03-25 20:10:41 +00:00
static const wxChar * const varRatesNumbers [ ] = {
wxT ( " 220-260 " ) ,
wxT ( " 200-250 " ) ,
wxT ( " 170-210 " ) ,
wxT ( " 155-195 " ) ,
wxT ( " 145-185 " ) ,
wxT ( " 110-150 " ) ,
wxT ( " 95-135 " ) ,
wxT ( " 80-120 " ) ,
wxT ( " 65-105 " ) ,
wxT ( " 45-85 " )
} ;
static_assert ( WXSIZEOF ( varRates ) = = WXSIZEOF ( varRatesNumbers ) ,
" size mismatch " ) ;
2010-01-23 19:44:49 +00:00
static CHOICES varModes [ ] =
{
{ wxT ( " " ) , ROUTINE_FAST } ,
{ wxT ( " " ) , ROUTINE_STANDARD }
} ;
static CHOICES setRates [ ] =
{
{ wxT ( " " ) , PRESET_INSANE } ,
{ wxT ( " " ) , PRESET_EXTREME } ,
{ wxT ( " " ) , PRESET_STANDARD } ,
2016-04-07 12:15:31 +00:00
{ wxT ( " " ) , PRESET_MEDIUM }
2010-01-23 19:44:49 +00:00
} ;
static CHOICES sampRates [ ] =
{
{ wxT ( " " ) , 8000 } ,
{ wxT ( " " ) , 11025 } ,
{ wxT ( " " ) , 12000 } ,
{ wxT ( " " ) , 16000 } ,
{ wxT ( " " ) , 22050 } ,
{ wxT ( " " ) , 24000 } ,
{ wxT ( " " ) , 32000 } ,
{ wxT ( " " ) , 44100 } ,
2016-04-07 12:15:31 +00:00
{ wxT ( " " ) , 48000 }
2010-01-23 19:44:49 +00:00
} ;
# define ID_SET 7000
# define ID_VBR 7001
# define ID_ABR 7002
# define ID_CBR 7003
2011-03-21 23:39:16 +00:00
# define ID_QUALITY 7004
2016-04-01 20:46:32 +00:00
# define ID_MONO 7005
2010-01-23 19:44:49 +00:00
2013-02-22 21:29:19 +00:00
static void InitMP3_Statics ( )
2010-01-23 19:44:49 +00:00
{
for ( size_t i = 0 ; i < WXSIZEOF ( fixRates ) ; i + + )
2018-03-25 20:10:41 +00:00
fixRates [ i ] . name = wxString : : Format ( _ ( " %d kbps " ) , fixRates [ i ] . label ) ;
varRates [ 0 ] . name = wxString : : Format (
_ ( " %s kbps (Best Quality) " ) , varRatesNumbers [ 0 ] ) ;
for ( size_t i = 1 ; i < WXSIZEOF ( varRates ) - 1 ; i + + )
varRates [ i ] . name = wxString : : Format ( _ ( " %s kbps " ) , varRatesNumbers [ i ] ) ;
varRates [ 9 ] . name = wxString : : Format (
_ ( " %s kbps (Smaller files) " ) , varRatesNumbers [ 9 ] ) ;
2010-01-23 19:44:49 +00:00
varModes [ 0 ] . name = _ ( " Fast " ) ;
varModes [ 1 ] . name = _ ( " Standard " ) ;
2012-03-20 16:17:37 +00:00
/* i18n-hint: Slightly humorous - as in use an insane precision with MP3.*/
2018-03-25 20:10:41 +00:00
setRates [ 0 ] . name = _ ( " Insane, 320 kbps " ) ;
setRates [ 1 ] . name = _ ( " Extreme, 220-260 kbps " ) ;
setRates [ 2 ] . name = _ ( " Standard, 170-210 kbps " ) ;
setRates [ 3 ] . name = _ ( " Medium, 145-185 kbps " ) ;
2010-01-23 19:44:49 +00:00
for ( size_t i = 0 ; i < WXSIZEOF ( sampRates ) ; i + + )
2018-03-25 20:10:41 +00:00
sampRates [ i ] . name = wxString : : Format ( wxT ( " %d " ) , sampRates [ i ] . label ) ;
2010-01-23 19:44:49 +00:00
}
2016-06-25 18:18:23 +00:00
class ExportMP3Options final : public wxPanelWrapper
2010-01-23 19:44:49 +00:00
{
public :
2015-07-13 17:36:40 +00:00
ExportMP3Options ( wxWindow * parent , int format ) ;
virtual ~ ExportMP3Options ( ) ;
2010-01-23 19:44:49 +00:00
void PopulateOrExchange ( ShuttleGui & S ) ;
2017-10-01 17:28:04 +00:00
bool TransferDataToWindow ( ) override ;
bool TransferDataFromWindow ( ) override ;
2015-08-05 07:28:42 +00:00
2010-01-23 19:44:49 +00:00
void OnSET ( wxCommandEvent & evt ) ;
void OnVBR ( wxCommandEvent & evt ) ;
void OnABR ( wxCommandEvent & evt ) ;
void OnCBR ( wxCommandEvent & evt ) ;
2011-03-21 23:39:16 +00:00
void OnQuality ( wxCommandEvent & evt ) ;
2016-04-01 20:46:32 +00:00
void OnMono ( wxCommandEvent & evt ) ;
2011-03-21 23:39:16 +00:00
2010-01-23 19:44:49 +00:00
void LoadNames ( CHOICES * choices , int count ) ;
wxArrayString GetNames ( CHOICES * choices , int count ) ;
2018-02-02 19:49:46 +00:00
std : : vector < int > GetLabels ( CHOICES * choices , int count ) ;
2011-03-21 23:39:16 +00:00
int FindIndex ( CHOICES * choices , int cnt , int needle , int def ) ;
2010-01-23 19:44:49 +00:00
private :
wxRadioButton * mStereo ;
wxRadioButton * mJoint ;
2016-04-01 20:46:32 +00:00
wxCheckBox * mMono ;
2010-01-23 19:44:49 +00:00
wxRadioButton * mSET ;
wxRadioButton * mVBR ;
wxRadioButton * mABR ;
wxRadioButton * mCBR ;
wxChoice * mRate ;
wxChoice * mMode ;
2011-03-21 23:39:16 +00:00
long mSetRate ;
long mVbrRate ;
long mAbrRate ;
long mCbrRate ;
2010-01-23 19:44:49 +00:00
DECLARE_EVENT_TABLE ( )
} ;
2016-06-25 18:18:23 +00:00
BEGIN_EVENT_TABLE ( ExportMP3Options , wxPanelWrapper )
2010-01-23 19:44:49 +00:00
EVT_RADIOBUTTON ( ID_SET , ExportMP3Options : : OnSET )
EVT_RADIOBUTTON ( ID_VBR , ExportMP3Options : : OnVBR )
EVT_RADIOBUTTON ( ID_ABR , ExportMP3Options : : OnABR )
EVT_RADIOBUTTON ( ID_CBR , ExportMP3Options : : OnCBR )
2011-03-21 23:39:16 +00:00
EVT_CHOICE ( wxID_ANY , ExportMP3Options : : OnQuality )
2016-04-01 20:46:32 +00:00
EVT_CHECKBOX ( ID_MONO , ExportMP3Options : : OnMono )
2010-01-23 19:44:49 +00:00
END_EVENT_TABLE ( )
2014-06-03 20:30:19 +00:00
///
///
2015-07-13 17:36:40 +00:00
ExportMP3Options : : ExportMP3Options ( wxWindow * parent , int WXUNUSED ( format ) )
2016-06-25 18:18:23 +00:00
: wxPanelWrapper ( parent , wxID_ANY )
2010-01-23 19:44:49 +00:00
{
InitMP3_Statics ( ) ;
2011-03-21 23:39:16 +00:00
2015-08-16 20:20:29 +00:00
mSetRate = gPrefs - > Read ( wxT ( " /FileFormats/MP3SetRate " ) , PRESET_STANDARD ) ;
2015-08-24 05:58:23 +00:00
mVbrRate = gPrefs - > Read ( wxT ( " /FileFormats/MP3VbrRate " ) , QUALITY_2 ) ;
mAbrRate = gPrefs - > Read ( wxT ( " /FileFormats/MP3AbrRate " ) , 192 ) ;
mCbrRate = gPrefs - > Read ( wxT ( " /FileFormats/MP3CbrRate " ) , 192 ) ;
2015-08-16 20:20:29 +00:00
2010-01-23 19:44:49 +00:00
ShuttleGui S ( this , eIsCreatingFromPrefs ) ;
2015-07-13 17:36:40 +00:00
PopulateOrExchange ( S ) ;
2015-08-05 07:28:42 +00:00
TransferDataToWindow ( ) ;
2015-07-13 17:36:40 +00:00
}
2010-01-23 19:44:49 +00:00
2015-07-13 17:36:40 +00:00
ExportMP3Options : : ~ ExportMP3Options ( )
{
2015-08-05 07:28:42 +00:00
TransferDataFromWindow ( ) ;
2010-01-23 19:44:49 +00:00
}
2019-03-19 16:06:57 +00:00
EnumSetting < MP3RateMode > MP3RateModeSetting {
wxT ( " /FileFormats/MP3RateModeChoice " ) ,
{
{ wxT ( " SET " ) , XO ( " Preset " ) } ,
{ wxT ( " VBR " ) , XO ( " Variable " ) } ,
{ wxT ( " ABR " ) , XO ( " Average " ) } ,
{ wxT ( " CBR " ) , XO ( " Constant " ) } ,
} ,
0 , // MODE_SET
// for migrating old preferences:
{
MODE_SET , MODE_VBR , MODE_ABR , MODE_CBR
} ,
wxT ( " /FileFormats/MP3RateMode " ) ,
} ;
static EnumSetting < MP3ChannelMode > MP3ChannelModeSetting {
wxT ( " /FileFormats/MP3ChannelModeChoice " ) ,
{
EnumValueSymbol { wxT ( " JOINT " ) , XO ( " Joint Stereo " ) } ,
EnumValueSymbol { wxT ( " STEREO " ) , XO ( " Stereo " ) } ,
} ,
0 , // CHANNEL_JOINT
// for migrating old preferences:
{
CHANNEL_JOINT , CHANNEL_STEREO ,
} ,
wxT ( " /FileFormats/MP3ChannelMode " ) ,
} ;
2014-06-03 20:30:19 +00:00
///
///
2010-01-23 19:44:49 +00:00
void ExportMP3Options : : PopulateOrExchange ( ShuttleGui & S )
{
2015-07-13 17:36:40 +00:00
S . StartVerticalLay ( ) ;
2010-01-23 19:44:49 +00:00
{
2015-07-13 17:36:40 +00:00
S . StartHorizontalLay ( wxCENTER ) ;
2010-01-23 19:44:49 +00:00
{
2015-07-13 17:36:40 +00:00
S . StartMultiColumn ( 2 , wxCENTER ) ;
2010-01-23 19:44:49 +00:00
{
S . SetStretchyCol ( 1 ) ;
S . StartTwoColumn ( ) ;
{
S . AddPrompt ( _ ( " Bit Rate Mode: " ) ) ;
S . StartHorizontalLay ( ) ;
{
2019-03-19 16:06:57 +00:00
S . StartRadioButtonGroup ( wxT ( " /FileFormats/MP3RateModeChoice " ) , wxT ( " SET " ) ) ;
2010-01-23 19:44:49 +00:00
{
2019-03-19 16:06:57 +00:00
mSET = S . Id ( ID_SET ) . TieRadioButton ( _ ( " Preset " ) , wxT ( " SET " ) ) ;
mVBR = S . Id ( ID_VBR ) . TieRadioButton ( _ ( " Variable " ) , wxT ( " VBR " ) ) ;
mABR = S . Id ( ID_ABR ) . TieRadioButton ( _ ( " Average " ) , wxT ( " ABR " ) ) ;
mCBR = S . Id ( ID_CBR ) . TieRadioButton ( _ ( " Constant " ) , wxT ( " CBR " ) ) ;
2010-01-23 19:44:49 +00:00
}
S . EndRadioButtonGroup ( ) ;
}
S . EndHorizontalLay ( ) ;
2015-07-13 17:36:40 +00:00
2010-01-23 19:44:49 +00:00
CHOICES * choices ;
int cnt ;
bool enable ;
int defrate ;
2015-07-13 17:36:40 +00:00
2010-01-23 19:44:49 +00:00
if ( mSET - > GetValue ( ) ) {
choices = setRates ;
cnt = WXSIZEOF ( setRates ) ;
enable = true ;
2011-03-21 23:39:16 +00:00
defrate = mSetRate ;
2010-01-23 19:44:49 +00:00
}
else if ( mVBR - > GetValue ( ) ) {
choices = varRates ;
cnt = WXSIZEOF ( varRates ) ;
enable = true ;
2011-03-21 23:39:16 +00:00
defrate = mVbrRate ;
2010-01-23 19:44:49 +00:00
}
else if ( mABR - > GetValue ( ) ) {
choices = fixRates ;
cnt = WXSIZEOF ( fixRates ) ;
enable = false ;
2011-03-21 23:39:16 +00:00
defrate = mAbrRate ;
2010-01-23 19:44:49 +00:00
}
else {
mCBR - > SetValue ( true ) ;
choices = fixRates ;
cnt = WXSIZEOF ( fixRates ) ;
enable = false ;
2011-03-21 23:39:16 +00:00
defrate = mCbrRate ;
2010-01-23 19:44:49 +00:00
}
2015-07-13 17:36:40 +00:00
2011-03-21 23:39:16 +00:00
mRate = S . Id ( ID_QUALITY ) . TieChoice ( _ ( " Quality " ) ,
2014-06-03 20:30:19 +00:00
wxT ( " /FileFormats/MP3Bitrate " ) ,
2011-03-21 23:39:16 +00:00
defrate ,
GetNames ( choices , cnt ) ,
GetLabels ( choices , cnt ) ) ;
2015-07-13 17:36:40 +00:00
2010-01-23 19:44:49 +00:00
mMode = S . TieChoice ( _ ( " Variable Speed: " ) ,
2014-06-03 20:30:19 +00:00
wxT ( " /FileFormats/MP3VarMode " ) ,
2010-01-23 19:44:49 +00:00
ROUTINE_FAST ,
GetNames ( varModes , WXSIZEOF ( varModes ) ) ,
GetLabels ( varModes , WXSIZEOF ( varModes ) ) ) ;
mMode - > Enable ( enable ) ;
2015-07-13 17:36:40 +00:00
2010-01-23 19:44:49 +00:00
S . AddPrompt ( _ ( " Channel Mode: " ) ) ;
2016-04-01 20:46:32 +00:00
S . StartMultiColumn ( 3 , wxEXPAND ) ;
2010-01-23 19:44:49 +00:00
{
2016-04-01 20:46:32 +00:00
bool mono = false ;
gPrefs - > Read ( wxT ( " /FileFormats/MP3ForceMono " ) , & mono , 0 ) ;
2019-03-19 16:06:57 +00:00
S . StartRadioButtonGroup ( wxT ( " /FileFormats/MP3ChannelModeChoice " ) , wxT ( " JOINT " ) ) ;
2010-01-23 19:44:49 +00:00
{
2019-03-19 16:06:57 +00:00
mJoint = S . TieRadioButton ( _ ( " Joint Stereo " ) , wxT ( " JOINT " ) ) ;
mStereo = S . TieRadioButton ( _ ( " Stereo " ) , wxT ( " STEREO " ) ) ;
2016-04-01 20:46:32 +00:00
mJoint - > Enable ( ! mono ) ;
mStereo - > Enable ( ! mono ) ;
2010-01-23 19:44:49 +00:00
}
S . EndRadioButtonGroup ( ) ;
2016-04-01 20:46:32 +00:00
2018-02-02 02:37:34 +00:00
mMono = S . Id ( ID_MONO ) . AddCheckBox ( _ ( " Force export to mono " ) , mono ) ;
2010-01-23 19:44:49 +00:00
}
S . EndTwoColumn ( ) ;
}
S . EndTwoColumn ( ) ;
}
S . EndMultiColumn ( ) ;
}
2015-07-13 17:36:40 +00:00
S . EndHorizontalLay ( ) ;
2010-01-23 19:44:49 +00:00
}
2015-07-13 17:36:40 +00:00
S . EndVerticalLay ( ) ;
2010-01-23 19:44:49 +00:00
}
2015-08-05 07:28:42 +00:00
///
///
bool ExportMP3Options : : TransferDataToWindow ( )
{
return true ;
}
bool ExportMP3Options : : TransferDataFromWindow ( )
{
ShuttleGui S ( this , eIsSavingToPrefs ) ;
PopulateOrExchange ( S ) ;
gPrefs - > Write ( wxT ( " /FileFormats/MP3SetRate " ) , mSetRate ) ;
gPrefs - > Write ( wxT ( " /FileFormats/MP3VbrRate " ) , mVbrRate ) ;
gPrefs - > Write ( wxT ( " /FileFormats/MP3AbrRate " ) , mAbrRate ) ;
gPrefs - > Write ( wxT ( " /FileFormats/MP3CbrRate " ) , mCbrRate ) ;
gPrefs - > Flush ( ) ;
return true ;
}
2014-06-03 20:30:19 +00:00
///
///
2013-08-25 21:51:26 +00:00
void ExportMP3Options : : OnSET ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
LoadNames ( setRates , WXSIZEOF ( setRates ) ) ;
2011-03-21 23:39:16 +00:00
mRate - > SetSelection ( FindIndex ( setRates , WXSIZEOF ( setRates ) , mSetRate , 2 ) ) ;
2010-01-23 19:44:49 +00:00
mRate - > Refresh ( ) ;
mMode - > Enable ( true ) ;
}
2014-06-03 20:30:19 +00:00
///
///
2013-08-25 21:51:26 +00:00
void ExportMP3Options : : OnVBR ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
LoadNames ( varRates , WXSIZEOF ( varRates ) ) ;
2011-03-21 23:39:16 +00:00
mRate - > SetSelection ( FindIndex ( varRates , WXSIZEOF ( varRates ) , mVbrRate , 2 ) ) ;
2010-01-23 19:44:49 +00:00
mRate - > Refresh ( ) ;
mMode - > Enable ( true ) ;
}
2014-06-03 20:30:19 +00:00
///
///
2013-08-25 21:51:26 +00:00
void ExportMP3Options : : OnABR ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
LoadNames ( fixRates , WXSIZEOF ( fixRates ) ) ;
2011-03-21 23:39:16 +00:00
mRate - > SetSelection ( FindIndex ( fixRates , WXSIZEOF ( fixRates ) , mAbrRate , 10 ) ) ;
2010-01-23 19:44:49 +00:00
mRate - > Refresh ( ) ;
mMode - > Enable ( false ) ;
}
2014-06-03 20:30:19 +00:00
///
///
2013-08-25 21:51:26 +00:00
void ExportMP3Options : : OnCBR ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
LoadNames ( fixRates , WXSIZEOF ( fixRates ) ) ;
2011-03-21 23:39:16 +00:00
mRate - > SetSelection ( FindIndex ( fixRates , WXSIZEOF ( fixRates ) , mCbrRate , 10 ) ) ;
2010-01-23 19:44:49 +00:00
mRate - > Refresh ( ) ;
mMode - > Enable ( false ) ;
2011-03-21 23:39:16 +00:00
}
2013-08-25 21:51:26 +00:00
void ExportMP3Options : : OnQuality ( wxCommandEvent & WXUNUSED ( event ) )
2011-03-21 23:39:16 +00:00
{
int sel = mRate - > GetSelection ( ) ;
if ( mSET - > GetValue ( ) ) {
mSetRate = setRates [ sel ] . label ;
}
else if ( mVBR - > GetValue ( ) ) {
mVbrRate = varRates [ sel ] . label ;
}
else if ( mABR - > GetValue ( ) ) {
mAbrRate = fixRates [ sel ] . label ;
}
else {
mCbrRate = fixRates [ sel ] . label ;
}
2010-01-23 19:44:49 +00:00
}
2016-09-11 19:30:06 +00:00
void ExportMP3Options : : OnMono ( wxCommandEvent & /*evt*/ )
2016-04-01 20:46:32 +00:00
{
bool mono = false ;
mono = mMono - > GetValue ( ) ;
mJoint - > Enable ( ! mono ) ;
mStereo - > Enable ( ! mono ) ;
gPrefs - > Write ( wxT ( " /FileFormats/MP3ForceMono " ) , mono ) ;
gPrefs - > Flush ( ) ;
}
2010-01-23 19:44:49 +00:00
void ExportMP3Options : : LoadNames ( CHOICES * choices , int count )
{
mRate - > Clear ( ) ;
for ( int i = 0 ; i < count ; i + + )
{
mRate - > Append ( choices [ i ] . name ) ;
}
}
wxArrayString ExportMP3Options : : GetNames ( CHOICES * choices , int count )
{
wxArrayString names ;
for ( int i = 0 ; i < count ; i + + ) {
2019-02-12 00:10:48 +00:00
names . push_back ( choices [ i ] . name ) ;
2010-01-23 19:44:49 +00:00
}
return names ;
}
2018-02-02 19:49:46 +00:00
std : : vector < int > ExportMP3Options : : GetLabels ( CHOICES * choices , int count )
2010-01-23 19:44:49 +00:00
{
2018-02-02 19:49:46 +00:00
std : : vector < int > labels ;
2010-01-23 19:44:49 +00:00
for ( int i = 0 ; i < count ; i + + ) {
2018-02-02 19:49:46 +00:00
labels . push_back ( choices [ i ] . label ) ;
2010-01-23 19:44:49 +00:00
}
return labels ;
}
2011-03-21 23:39:16 +00:00
int ExportMP3Options : : FindIndex ( CHOICES * choices , int cnt , int needle , int def )
{
for ( int i = 0 ; i < cnt ; i + + ) {
if ( choices [ i ] . label = = needle ) {
return i ;
}
}
return def ;
}
2010-01-23 19:44:49 +00:00
//----------------------------------------------------------------------------
// FindDialog
//----------------------------------------------------------------------------
# define ID_BROWSE 5000
# define ID_DLOAD 5001
2016-07-10 21:10:50 +00:00
class FindDialog final : public wxDialogWrapper
2010-01-23 19:44:49 +00:00
{
public :
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
FindDialog ( wxWindow * parent , wxString path , wxString name , wxString type )
2016-07-10 21:10:50 +00:00
: wxDialogWrapper ( parent , wxID_ANY ,
2012-03-20 16:17:37 +00:00
/* i18n-hint: LAME is the name of an MP3 converter and should not be translated*/
2016-10-14 15:36:41 +00:00
wxString ( _ ( " Locate LAME " ) ) )
2010-01-23 19:44:49 +00:00
{
2015-05-18 12:57:05 +00:00
SetName ( GetTitle ( ) ) ;
2010-01-23 19:44:49 +00:00
ShuttleGui S ( this , eIsCreating ) ;
mPath = path ;
mName = name ;
mType = type ;
mLibPath . Assign ( mPath , mName ) ;
PopulateOrExchange ( S ) ;
}
void PopulateOrExchange ( ShuttleGui & S )
{
wxString text ;
S . SetBorder ( 10 ) ;
S . StartVerticalLay ( true ) ;
{
2017-10-09 05:03:14 +00:00
text . Printf ( _ ( " Audacity needs the file %s to create MP3s. " ) , mName ) ;
2010-01-23 19:44:49 +00:00
S . AddTitle ( text ) ;
S . SetBorder ( 3 ) ;
S . StartHorizontalLay ( wxALIGN_LEFT , true ) ;
{
2017-10-09 05:03:14 +00:00
text . Printf ( _ ( " Location of %s: " ) , mName ) ;
2010-01-23 19:44:49 +00:00
S . AddTitle ( text ) ;
}
S . EndHorizontalLay ( ) ;
S . StartMultiColumn ( 2 , wxEXPAND ) ;
S . SetStretchyCol ( 0 ) ;
{
2019-02-12 00:10:48 +00:00
if ( mLibPath . GetFullPath ( ) . empty ( ) ) {
2012-03-20 15:36:02 +00:00
/* i18n-hint: There is a button to the right of the arrow.*/
2017-10-09 05:03:14 +00:00
text . Printf ( _ ( " To find %s, click here --> " ) , mName ) ;
2017-09-28 01:20:14 +00:00
mPathText = S . AddTextBox ( { } , text , 0 ) ;
2010-01-23 19:44:49 +00:00
}
else {
2017-09-28 01:20:14 +00:00
mPathText = S . AddTextBox ( { } , mLibPath . GetFullPath ( ) , 0 ) ;
2010-01-23 19:44:49 +00:00
}
S . Id ( ID_BROWSE ) . AddButton ( _ ( " Browse... " ) , wxALIGN_RIGHT ) ;
2012-03-20 15:36:02 +00:00
/* i18n-hint: There is a button to the right of the arrow.*/
2016-10-14 15:36:41 +00:00
S . AddVariableText ( _ ( " To get a free copy of LAME, click here --> " ) , true ) ;
2012-03-20 15:36:02 +00:00
/* i18n-hint: (verb)*/
2010-01-23 19:44:49 +00:00
S . Id ( ID_DLOAD ) . AddButton ( _ ( " Download " ) , wxALIGN_RIGHT ) ;
}
S . EndMultiColumn ( ) ;
S . AddStandardButtons ( ) ;
}
S . EndVerticalLay ( ) ;
Layout ( ) ;
Fit ( ) ;
SetMinSize ( GetSize ( ) ) ;
Center ( ) ;
return ;
}
2013-08-25 21:51:26 +00:00
void OnBrowse ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
wxString question ;
/* i18n-hint: It's asking for the location of a file, for
2012-03-20 15:36:02 +00:00
* example , " Where is lame_enc.dll? " - you could translate
* " Where would I find the file %s " instead if you want . */
2017-10-09 05:03:14 +00:00
question . Printf ( _ ( " Where is %s? " ) , mName ) ;
2010-01-23 19:44:49 +00:00
2017-08-03 15:29:11 +00:00
wxString path = FileNames : : SelectFile ( FileNames : : Operation : : _None ,
2017-08-02 16:41:29 +00:00
question ,
2010-01-23 19:44:49 +00:00
mLibPath . GetPath ( ) ,
mLibPath . GetName ( ) ,
wxT ( " " ) ,
mType ,
wxFD_OPEN | wxRESIZE_BORDER ,
this ) ;
2019-02-12 00:10:48 +00:00
if ( ! path . empty ( ) ) {
2010-01-23 19:44:49 +00:00
mLibPath = path ;
mPathText - > SetValue ( path ) ;
}
}
2013-08-25 21:51:26 +00:00
void OnDownload ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
2017-10-19 00:59:39 +00:00
HelpSystem : : ShowHelp ( this , wxT ( " FAQ:Installing_the_LAME_MP3_Encoder " ) ) ;
2010-01-23 19:44:49 +00:00
}
wxString GetLibPath ( )
{
return mLibPath . GetFullPath ( ) ;
}
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
private :
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
wxFileName mLibPath ;
wxString mPath ;
wxString mName ;
wxString mType ;
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
wxTextCtrl * mPathText ;
DECLARE_EVENT_TABLE ( )
} ;
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2016-07-10 21:10:50 +00:00
BEGIN_EVENT_TABLE ( FindDialog , wxDialogWrapper )
2010-01-23 19:44:49 +00:00
EVT_BUTTON ( ID_BROWSE , FindDialog : : OnBrowse )
EVT_BUTTON ( ID_DLOAD , FindDialog : : OnDownload )
END_EVENT_TABLE ( )
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
//----------------------------------------------------------------------------
// MP3Exporter
//----------------------------------------------------------------------------
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
typedef lame_global_flags * lame_init_t ( void ) ;
typedef int lame_init_params_t ( lame_global_flags * ) ;
typedef const char * get_lame_version_t ( void ) ;
typedef int lame_encode_buffer_t (
lame_global_flags * gf ,
const short int buffer_l [ ] ,
const short int buffer_r [ ] ,
const int nsamples ,
unsigned char * mp3buf ,
const int mp3buf_size ) ;
typedef int lame_encode_buffer_interleaved_t (
lame_global_flags * gf ,
short int pcm [ ] ,
int num_samples , /* per channel */
unsigned char * mp3buf ,
int mp3buf_size ) ;
typedef int lame_encode_flush_t (
lame_global_flags * gf ,
unsigned char * mp3buf ,
int size ) ;
typedef int lame_close_t ( lame_global_flags * ) ;
typedef int lame_set_in_samplerate_t ( lame_global_flags * , int ) ;
typedef int lame_set_out_samplerate_t ( lame_global_flags * , int ) ;
typedef int lame_set_num_channels_t ( lame_global_flags * , int ) ;
typedef int lame_set_quality_t ( lame_global_flags * , int ) ;
typedef int lame_set_brate_t ( lame_global_flags * , int ) ;
typedef int lame_set_VBR_t ( lame_global_flags * , vbr_mode ) ;
typedef int lame_set_VBR_q_t ( lame_global_flags * , int ) ;
typedef int lame_set_VBR_min_bitrate_kbps_t ( lame_global_flags * , int ) ;
typedef int lame_set_mode_t ( lame_global_flags * , MPEG_mode ) ;
typedef int lame_set_preset_t ( lame_global_flags * , int ) ;
typedef int lame_set_error_protection_t ( lame_global_flags * , int ) ;
typedef int lame_set_disable_reservoir_t ( lame_global_flags * , int ) ;
typedef int lame_set_padding_type_t ( lame_global_flags * , Padding_type ) ;
typedef int lame_set_bWriteVbrTag_t ( lame_global_flags * , int ) ;
typedef size_t lame_get_lametag_frame_t ( const lame_global_flags * , unsigned char * buffer , size_t size ) ;
typedef void lame_mp3_tags_fid_t ( lame_global_flags * , FILE * ) ;
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
# if defined(__WXMSW__)
// An alternative solution to give Windows an additional chance of writing the tag before
// falling bato to lame_mp3_tag_fid(). The latter can have DLL sharing issues when mixing
// Debug/Release builds of Audacity and the lame DLL.
typedef unsigned long beWriteInfoTag_t ( lame_global_flags * , char * ) ;
// We use this to determine if the user has selected an older, Blade API only, lame_enc.dll
// so we can be more specific about why their library isn't acceptable.
typedef struct {
2013-02-23 04:33:20 +00:00
// BladeEnc DLL Version number
2010-01-23 19:44:49 +00:00
2013-02-23 04:33:20 +00:00
BYTE byDLLMajorVersion ;
BYTE byDLLMinorVersion ;
2010-01-23 19:44:49 +00:00
2013-02-23 04:33:20 +00:00
// BladeEnc Engine Version Number
2010-01-23 19:44:49 +00:00
2013-02-23 04:33:20 +00:00
BYTE byMajorVersion ;
BYTE byMinorVersion ;
2010-01-23 19:44:49 +00:00
2013-02-23 04:33:20 +00:00
// DLL Release date
2010-01-23 19:44:49 +00:00
2013-02-23 04:33:20 +00:00
BYTE byDay ;
BYTE byMonth ;
WORD wYear ;
2010-01-23 19:44:49 +00:00
2013-02-23 04:33:20 +00:00
// BladeEnc Homepage URL
2010-01-23 19:44:49 +00:00
2013-02-23 04:33:20 +00:00
CHAR zHomepage [ 129 ] ;
2010-01-23 19:44:49 +00:00
2013-02-23 04:33:20 +00:00
BYTE byAlphaLevel ;
BYTE byBetaLevel ;
BYTE byMMXEnabled ;
2010-01-23 19:44:49 +00:00
2013-02-23 04:33:20 +00:00
BYTE btReserved [ 125 ] ;
2010-01-23 19:44:49 +00:00
} be_version ;
typedef void beVersion_t ( be_version * ) ;
# endif
class MP3Exporter
{
public :
enum AskUser
{
No ,
Maybe ,
Yes
} ;
MP3Exporter ( ) ;
2018-02-27 09:13:54 +00:00
~ MP3Exporter ( ) ;
2010-01-23 19:44:49 +00:00
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
bool FindLibrary ( wxWindow * parent ) ;
bool LoadLibrary ( wxWindow * parent , AskUser askuser ) ;
bool ValidLibraryLoaded ( ) ;
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
/* These global settings keep state over the life of the object */
void SetMode ( int mode ) ;
void SetBitrate ( int rate ) ;
void SetQuality ( int q , int r ) ;
void SetChannel ( int mode ) ;
/* Virtual methods that must be supplied by library interfaces */
/* initialize the library interface */
bool InitLibrary ( wxString libpath ) ;
2019-03-26 17:47:41 +00:00
bool InitLibraryInternal ( ) ;
bool InitLibraryExternal ( wxString libpath ) ;
2010-01-23 19:44:49 +00:00
void FreeLibrary ( ) ;
/* get library info */
wxString GetLibraryVersion ( ) ;
wxString GetLibraryName ( ) ;
wxString GetLibraryPath ( ) ;
wxString GetLibraryTypeString ( ) ;
/* returns the number of samples PER CHANNEL to send for each call to EncodeBuffer */
2016-09-02 19:53:09 +00:00
int InitializeStream ( unsigned channels , int sampleRate ) ;
2010-01-23 19:44:49 +00:00
/* In bytes. must be called AFTER InitializeStream */
int GetOutBufferSize ( ) ;
/* returns the number of bytes written. input is interleaved if stereo*/
int EncodeBuffer ( short int inbuffer [ ] , unsigned char outbuffer [ ] ) ;
int EncodeRemainder ( short int inbuffer [ ] , int nSamples ,
unsigned char outbuffer [ ] ) ;
int EncodeBufferMono ( short int inbuffer [ ] , unsigned char outbuffer [ ] ) ;
int EncodeRemainderMono ( short int inbuffer [ ] , int nSamples ,
unsigned char outbuffer [ ] ) ;
int FinishStream ( unsigned char outbuffer [ ] ) ;
void CancelEncoding ( ) ;
2018-01-22 19:10:03 +00:00
bool PutInfoTag ( wxFFile & f , wxFileOffset off ) ;
2010-01-23 19:44:49 +00:00
private :
2019-03-26 17:47:41 +00:00
bool mLibIsExternal ;
2010-01-23 19:44:49 +00:00
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
wxString mLibPath ;
wxDynamicLibrary lame_lib ;
bool mLibraryLoaded ;
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
# if defined(__WXMSW__)
wxString mBladeVersion ;
# endif
bool mEncoding ;
int mMode ;
int mBitrate ;
int mQuality ;
int mRoutine ;
int mChannel ;
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
/* function pointers to the symbols we get from the library */
lame_init_t * lame_init ;
lame_init_params_t * lame_init_params ;
lame_encode_buffer_t * lame_encode_buffer ;
lame_encode_buffer_interleaved_t * lame_encode_buffer_interleaved ;
lame_encode_flush_t * lame_encode_flush ;
lame_close_t * lame_close ;
get_lame_version_t * get_lame_version ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
lame_set_in_samplerate_t * lame_set_in_samplerate ;
lame_set_out_samplerate_t * lame_set_out_samplerate ;
lame_set_num_channels_t * lame_set_num_channels ;
lame_set_quality_t * lame_set_quality ;
lame_set_brate_t * lame_set_brate ;
lame_set_VBR_t * lame_set_VBR ;
lame_set_VBR_q_t * lame_set_VBR_q ;
lame_set_VBR_min_bitrate_kbps_t * lame_set_VBR_min_bitrate_kbps ;
lame_set_mode_t * lame_set_mode ;
lame_set_preset_t * lame_set_preset ;
lame_set_error_protection_t * lame_set_error_protection ;
lame_set_disable_reservoir_t * lame_set_disable_reservoir ;
lame_set_padding_type_t * lame_set_padding_type ;
lame_set_bWriteVbrTag_t * lame_set_bWriteVbrTag ;
lame_get_lametag_frame_t * lame_get_lametag_frame ;
lame_mp3_tags_fid_t * lame_mp3_tags_fid ;
# if defined(__WXMSW__)
beWriteInfoTag_t * beWriteInfoTag ;
beVersion_t * beVersion ;
# endif
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
lame_global_flags * mGF ;
static const int mSamplesPerChunk = 220500 ;
// See lame.h/lame_encode_buffer() for further explanation
// As coded here, this should be the worst case.
2014-06-03 20:30:19 +00:00
static const int mOutBufferSize =
2010-01-23 19:44:49 +00:00
mSamplesPerChunk * ( 320 / 8 ) / 8 + 4 * 1152 * ( 320 / 8 ) / 8 + 512 ;
// See MAXFRAMESIZE in libmp3lame/VbrTag.c for explanation of 2880.
unsigned char mInfoTagBuf [ 2880 ] ;
size_t mInfoTagLen ;
} ;
MP3Exporter : : MP3Exporter ( )
{
2019-03-26 17:47:41 +00:00
// We could use #defines rather than this variable.
// The idea of the variable is that if we wanted, we could allow
// a dynamic override of the library, e.g. with a newer faster version,
// or to fix CVEs in the underlying librray.
// for now though the 'variable' is a constant.
# ifdef MP3_EXPORT_BUILT_IN
mLibIsExternal = false ;
# else
mLibIsExternal = true ;
# endif
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
mLibraryLoaded = false ;
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
mEncoding = false ;
mGF = NULL ;
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
if ( gPrefs ) {
mLibPath = gPrefs - > Read ( wxT ( " /MP3/MP3LibPath " ) , wxT ( " " ) ) ;
}
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
mBitrate = 128 ;
mQuality = QUALITY_2 ;
mChannel = CHANNEL_STEREO ;
mMode = MODE_CBR ;
mRoutine = ROUTINE_FAST ;
}
MP3Exporter : : ~ MP3Exporter ( )
{
FreeLibrary ( ) ;
}
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
bool MP3Exporter : : FindLibrary ( wxWindow * parent )
{
wxString path ;
wxString name ;
2019-02-12 00:10:48 +00:00
if ( ! mLibPath . empty ( ) ) {
2010-01-23 19:44:49 +00:00
wxFileName fn = mLibPath ;
path = fn . GetPath ( ) ;
name = fn . GetFullName ( ) ;
}
else {
path = GetLibraryPath ( ) ;
name = GetLibraryName ( ) ;
}
FindDialog fd ( parent ,
path ,
name ,
GetLibraryTypeString ( ) ) ;
if ( fd . ShowModal ( ) = = wxID_CANCEL ) {
return false ;
}
path = fd . GetLibPath ( ) ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
if ( ! : : wxFileExists ( path ) ) {
return false ;
}
mLibPath = path ;
2012-08-02 06:03:19 +00:00
return ( gPrefs - > Write ( wxT ( " /MP3/MP3LibPath " ) , mLibPath ) & & gPrefs - > Flush ( ) ) ;
2010-01-23 19:44:49 +00:00
}
bool MP3Exporter : : LoadLibrary ( wxWindow * parent , AskUser askuser )
{
2019-03-26 17:47:41 +00:00
2010-01-23 19:44:49 +00:00
if ( ValidLibraryLoaded ( ) ) {
FreeLibrary ( ) ;
mLibraryLoaded = false ;
}
# if defined(__WXMSW__)
mBladeVersion . Empty ( ) ;
# endif
2019-03-26 17:47:41 +00:00
if ( ! mLibIsExternal ) {
mLibraryLoaded = InitLibraryInternal ( ) ;
return mLibraryLoaded ;
}
2010-01-23 19:44:49 +00:00
// First try loading it from a previously located path
2019-02-12 00:10:48 +00:00
if ( ! mLibPath . empty ( ) ) {
2011-03-06 20:58:33 +00:00
wxLogMessage ( wxT ( " Attempting to load LAME from previously defined path " ) ) ;
2010-01-23 19:44:49 +00:00
mLibraryLoaded = InitLibrary ( mLibPath ) ;
}
// If not successful, try loading using system search paths
if ( ! ValidLibraryLoaded ( ) ) {
2011-03-06 20:58:33 +00:00
wxLogMessage ( wxT ( " Attempting to load LAME from system search paths " ) ) ;
2010-01-23 19:44:49 +00:00
mLibPath = GetLibraryName ( ) ;
mLibraryLoaded = InitLibrary ( mLibPath ) ;
}
// If not successful, try loading using compiled in path
if ( ! ValidLibraryLoaded ( ) ) {
2011-03-06 20:58:33 +00:00
wxLogMessage ( wxT ( " Attempting to load LAME from builtin path " ) ) ;
2010-01-23 19:44:49 +00:00
wxFileName fn ( GetLibraryPath ( ) , GetLibraryName ( ) ) ;
mLibPath = fn . GetFullPath ( ) ;
mLibraryLoaded = InitLibrary ( mLibPath ) ;
}
// If not successful, must ask the user
if ( ! ValidLibraryLoaded ( ) ) {
2011-03-06 20:58:33 +00:00
wxLogMessage ( wxT ( " (Maybe) ask user for library " ) ) ;
2010-01-23 19:44:49 +00:00
if ( askuser = = MP3Exporter : : Maybe & & FindLibrary ( parent ) ) {
mLibraryLoaded = InitLibrary ( mLibPath ) ;
}
}
// Oh well, just give up
if ( ! ValidLibraryLoaded ( ) ) {
# if defined(__WXMSW__)
2019-02-12 00:10:48 +00:00
if ( askuser & & ! mBladeVersion . empty ( ) ) {
2017-09-06 21:39:33 +00:00
AudacityMessageBox ( mBladeVersion ) ;
2010-01-23 19:44:49 +00:00
}
# endif
2011-03-06 20:58:33 +00:00
wxLogMessage ( wxT ( " Failed to locate LAME library " ) ) ;
2010-01-23 19:44:49 +00:00
return false ;
}
2011-03-06 20:58:33 +00:00
wxLogMessage ( wxT ( " LAME library successfully loaded " ) ) ;
2010-01-23 19:44:49 +00:00
return true ;
}
bool MP3Exporter : : ValidLibraryLoaded ( )
{
return mLibraryLoaded ;
}
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
void MP3Exporter : : SetMode ( int mode )
{
mMode = mode ;
}
void MP3Exporter : : SetBitrate ( int rate )
{
mBitrate = rate ;
}
void MP3Exporter : : SetQuality ( int q , int r )
{
mQuality = q ;
mRoutine = r ;
}
void MP3Exporter : : SetChannel ( int mode )
{
mChannel = mode ;
}
bool MP3Exporter : : InitLibrary ( wxString libpath )
2019-03-26 17:47:41 +00:00
{
return mLibIsExternal ? InitLibraryExternal ( libpath ) : InitLibraryInternal ( ) ;
}
bool MP3Exporter : : InitLibraryInternal ( )
{
wxLogMessage ( wxT ( " Using internal LAME " ) ) ;
// The global ::lame_something symbols only exist if LAME is built in.
// So we don't reference them unless they are.
# ifdef MP3_EXPORT_BUILT_IN
lame_init = : : lame_init ;
get_lame_version = : : get_lame_version ;
lame_init_params = : : lame_init_params ;
lame_encode_buffer = : : lame_encode_buffer ;
lame_encode_buffer_interleaved = : : lame_encode_buffer_interleaved ;
lame_encode_flush = : : lame_encode_flush ;
lame_close = : : lame_close ;
lame_set_in_samplerate = : : lame_set_in_samplerate ;
lame_set_out_samplerate = : : lame_set_out_samplerate ;
lame_set_num_channels = : : lame_set_num_channels ;
lame_set_quality = : : lame_set_quality ;
lame_set_brate = : : lame_set_brate ;
lame_set_VBR = : : lame_set_VBR ;
lame_set_VBR_q = : : lame_set_VBR_q ;
lame_set_VBR_min_bitrate_kbps = : : lame_set_VBR_min_bitrate_kbps ;
lame_set_mode = : : lame_set_mode ;
lame_set_preset = : : lame_set_preset ;
lame_set_error_protection = : : lame_set_error_protection ;
lame_set_disable_reservoir = : : lame_set_disable_reservoir ;
lame_set_padding_type = : : lame_set_padding_type ;
lame_set_bWriteVbrTag = : : lame_set_bWriteVbrTag ;
// These are optional
//lame_get_lametag_frame = ::lame_get_lametag_frame;
lame_get_lametag_frame = NULL ;
lame_mp3_tags_fid = : : lame_mp3_tags_fid ;
# if defined(__WXMSW__)
//beWriteInfoTag = ::beWriteInfoTag;
//beVersion = ::beVersion;
beWriteInfoTag = NULL ;
beVersion = NULL ;
# endif
mGF = lame_init ( ) ;
if ( mGF = = NULL ) {
return false ;
}
# endif
return true ;
}
bool MP3Exporter : : InitLibraryExternal ( wxString libpath )
2010-01-23 19:44:49 +00:00
{
2017-10-09 05:03:14 +00:00
wxLogMessage ( wxT ( " Loading LAME from %s " ) , libpath ) ;
2011-03-06 20:58:33 +00:00
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
if ( ! lame_lib . Load ( libpath , wxDL_LAZY ) ) {
2011-03-06 20:58:33 +00:00
wxLogMessage ( wxT ( " load failed " ) ) ;
2010-01-23 19:44:49 +00:00
return false ;
}
2011-03-06 20:58:33 +00:00
wxLogMessage ( wxT ( " Actual LAME path %s " ) ,
2017-10-09 05:03:14 +00:00
FileNames : : PathFromAddr ( lame_lib . GetSymbol ( wxT ( " lame_init " ) ) ) ) ;
2011-03-06 20:58:33 +00:00
2010-01-23 19:44:49 +00:00
lame_init = ( lame_init_t * )
lame_lib . GetSymbol ( wxT ( " lame_init " ) ) ;
get_lame_version = ( get_lame_version_t * )
lame_lib . GetSymbol ( wxT ( " get_lame_version " ) ) ;
lame_init_params = ( lame_init_params_t * )
lame_lib . GetSymbol ( wxT ( " lame_init_params " ) ) ;
lame_encode_buffer = ( lame_encode_buffer_t * )
lame_lib . GetSymbol ( wxT ( " lame_encode_buffer " ) ) ;
lame_encode_buffer_interleaved = ( lame_encode_buffer_interleaved_t * )
lame_lib . GetSymbol ( wxT ( " lame_encode_buffer_interleaved " ) ) ;
lame_encode_flush = ( lame_encode_flush_t * )
lame_lib . GetSymbol ( wxT ( " lame_encode_flush " ) ) ;
lame_close = ( lame_close_t * )
lame_lib . GetSymbol ( wxT ( " lame_close " ) ) ;
lame_set_in_samplerate = ( lame_set_in_samplerate_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_in_samplerate " ) ) ;
lame_set_out_samplerate = ( lame_set_out_samplerate_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_out_samplerate " ) ) ;
lame_set_num_channels = ( lame_set_num_channels_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_num_channels " ) ) ;
lame_set_quality = ( lame_set_quality_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_quality " ) ) ;
lame_set_brate = ( lame_set_brate_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_brate " ) ) ;
lame_set_VBR = ( lame_set_VBR_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_VBR " ) ) ;
lame_set_VBR_q = ( lame_set_VBR_q_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_VBR_q " ) ) ;
lame_set_VBR_min_bitrate_kbps = ( lame_set_VBR_min_bitrate_kbps_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_VBR_min_bitrate_kbps " ) ) ;
2014-06-03 20:30:19 +00:00
lame_set_mode = ( lame_set_mode_t * )
2010-01-23 19:44:49 +00:00
lame_lib . GetSymbol ( wxT ( " lame_set_mode " ) ) ;
lame_set_preset = ( lame_set_preset_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_preset " ) ) ;
lame_set_error_protection = ( lame_set_error_protection_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_error_protection " ) ) ;
lame_set_disable_reservoir = ( lame_set_disable_reservoir_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_disable_reservoir " ) ) ;
lame_set_padding_type = ( lame_set_padding_type_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_padding_type " ) ) ;
lame_set_bWriteVbrTag = ( lame_set_bWriteVbrTag_t * )
lame_lib . GetSymbol ( wxT ( " lame_set_bWriteVbrTag " ) ) ;
// These are optional
lame_get_lametag_frame = ( lame_get_lametag_frame_t * )
lame_lib . GetSymbol ( wxT ( " lame_get_lametag_frame " ) ) ;
lame_mp3_tags_fid = ( lame_mp3_tags_fid_t * )
lame_lib . GetSymbol ( wxT ( " lame_mp3_tags_fid " ) ) ;
# if defined(__WXMSW__)
beWriteInfoTag = ( beWriteInfoTag_t * )
lame_lib . GetSymbol ( wxT ( " beWriteInfoTag " ) ) ;
beVersion = ( beVersion_t * )
lame_lib . GetSymbol ( wxT ( " beVersion " ) ) ;
# endif
if ( ! lame_init | |
! get_lame_version | |
! lame_init_params | |
! lame_encode_buffer | |
! lame_encode_buffer_interleaved | |
! lame_encode_flush | |
! lame_close | |
! lame_set_in_samplerate | |
! lame_set_out_samplerate | |
! lame_set_num_channels | |
! lame_set_quality | |
! lame_set_brate | |
! lame_set_VBR | |
! lame_set_VBR_q | |
! lame_set_mode | |
! lame_set_preset | |
! lame_set_error_protection | |
! lame_set_disable_reservoir | |
! lame_set_padding_type | |
! lame_set_bWriteVbrTag )
{
2011-10-09 21:14:03 +00:00
wxLogMessage ( wxT ( " Failed to find a required symbol in the LAME library. " ) ) ;
2010-01-23 19:44:49 +00:00
# if defined(__WXMSW__)
if ( beVersion ) {
be_version v ;
beVersion ( & v ) ;
2019-03-10 17:44:44 +00:00
mBladeVersion . Printf ( _ ( " You are linking to lame_enc.dll v%d.%d. This version is not compatible with Audacity %d.%d.%d. \n Please download the latest version of 'LAME for Audacity'. " ) ,
2010-01-23 19:44:49 +00:00
v . byMajorVersion ,
v . byMinorVersion ,
AUDACITY_VERSION ,
AUDACITY_RELEASE ,
AUDACITY_REVISION ) ;
}
# endif
lame_lib . Unload ( ) ;
return false ;
}
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
mGF = lame_init ( ) ;
if ( mGF = = NULL ) {
return false ;
}
return true ;
}
void MP3Exporter : : FreeLibrary ( )
{
if ( mGF ) {
lame_close ( mGF ) ;
mGF = NULL ;
}
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
lame_lib . Unload ( ) ;
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
return ;
}
wxString MP3Exporter : : GetLibraryVersion ( )
{
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
if ( ! mLibraryLoaded ) {
return wxT ( " " ) ;
}
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
return wxString : : Format ( wxT ( " LAME %hs " ) , get_lame_version ( ) ) ;
}
2016-09-02 19:53:09 +00:00
int MP3Exporter : : InitializeStream ( unsigned channels , int sampleRate )
2010-01-23 19:44:49 +00:00
{
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
if ( ! mLibraryLoaded ) {
return - 1 ;
}
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
if ( channels > 2 ) {
return - 1 ;
}
lame_set_error_protection ( mGF , false ) ;
lame_set_num_channels ( mGF , channels ) ;
lame_set_in_samplerate ( mGF , sampleRate ) ;
lame_set_out_samplerate ( mGF , sampleRate ) ;
2011-03-31 22:44:44 +00:00
lame_set_disable_reservoir ( mGF , false ) ;
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
// TODO: Make this configurable (detect the existance of this function)
2010-01-23 19:44:49 +00:00
lame_set_padding_type ( mGF , PAD_NO ) ;
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
// Add the VbrTag for all types. For ABR/VBR, a Xing tag will be created.
// For CBR, it will be a Lame Info tag.
lame_set_bWriteVbrTag ( mGF , true ) ;
// Set the VBR quality or ABR/CBR bitrate
switch ( mMode ) {
case MODE_SET :
{
int preset ;
if ( mQuality = = PRESET_INSANE ) {
preset = INSANE ;
}
else if ( mRoutine = = ROUTINE_FAST ) {
if ( mQuality = = PRESET_EXTREME ) {
preset = EXTREME_FAST ;
}
else if ( mQuality = = PRESET_STANDARD ) {
preset = STANDARD_FAST ;
}
else {
preset = 1007 ; // Not defined until 3.96
}
}
else {
if ( mQuality = = PRESET_EXTREME ) {
preset = EXTREME ;
}
else if ( mQuality = = PRESET_STANDARD ) {
preset = STANDARD ;
}
else {
preset = 1006 ; // Not defined until 3.96
}
}
lame_set_preset ( mGF , preset ) ;
}
break ;
case MODE_VBR :
lame_set_VBR ( mGF , ( mRoutine = = ROUTINE_STANDARD ? vbr_rh : vbr_mtrh ) ) ;
lame_set_VBR_q ( mGF , mQuality ) ;
break ;
case MODE_ABR :
lame_set_preset ( mGF , mBitrate ) ;
break ;
default :
lame_set_VBR ( mGF , vbr_off ) ;
lame_set_brate ( mGF , mBitrate ) ;
break ;
}
// Set the channel mode
MPEG_mode mode ;
2016-04-01 20:46:32 +00:00
if ( channels = = 1 | | mChannel = = CHANNEL_MONO ) {
2010-01-23 19:44:49 +00:00
mode = MONO ;
}
else if ( mChannel = = CHANNEL_JOINT ) {
mode = JOINT_STEREO ;
}
else {
mode = STEREO ;
}
lame_set_mode ( mGF , mode ) ;
int rc = lame_init_params ( mGF ) ;
if ( rc < 0 ) {
return rc ;
}
#if 0
dump_config ( mGF ) ;
# endif
mInfoTagLen = 0 ;
mEncoding = true ;
return mSamplesPerChunk ;
}
int MP3Exporter : : GetOutBufferSize ( )
{
if ( ! mEncoding )
return - 1 ;
return mOutBufferSize ;
}
int MP3Exporter : : EncodeBuffer ( short int inbuffer [ ] , unsigned char outbuffer [ ] )
{
if ( ! mEncoding ) {
return - 1 ;
}
return lame_encode_buffer_interleaved ( mGF , inbuffer , mSamplesPerChunk ,
outbuffer , mOutBufferSize ) ;
}
int MP3Exporter : : EncodeRemainder ( short int inbuffer [ ] , int nSamples ,
unsigned char outbuffer [ ] )
{
if ( ! mEncoding ) {
return - 1 ;
}
return lame_encode_buffer_interleaved ( mGF , inbuffer , nSamples , outbuffer ,
mOutBufferSize ) ;
}
int MP3Exporter : : EncodeBufferMono ( short int inbuffer [ ] , unsigned char outbuffer [ ] )
{
if ( ! mEncoding ) {
return - 1 ;
}
return lame_encode_buffer ( mGF , inbuffer , inbuffer , mSamplesPerChunk ,
outbuffer , mOutBufferSize ) ;
}
int MP3Exporter : : EncodeRemainderMono ( short int inbuffer [ ] , int nSamples ,
unsigned char outbuffer [ ] )
{
if ( ! mEncoding ) {
return - 1 ;
}
return lame_encode_buffer ( mGF , inbuffer , inbuffer , nSamples , outbuffer ,
mOutBufferSize ) ;
}
int MP3Exporter : : FinishStream ( unsigned char outbuffer [ ] )
{
if ( ! mEncoding ) {
return - 1 ;
}
mEncoding = false ;
int result = lame_encode_flush ( mGF , outbuffer , mOutBufferSize ) ;
2012-06-25 01:41:57 +00:00
# if defined(DISABLE_DYNAMIC_LOADING_LAME)
mInfoTagLen = lame_get_lametag_frame ( mGF , mInfoTagBuf , sizeof ( mInfoTagBuf ) ) ;
# else
2010-01-23 19:44:49 +00:00
if ( lame_get_lametag_frame ) {
mInfoTagLen = lame_get_lametag_frame ( mGF , mInfoTagBuf , sizeof ( mInfoTagBuf ) ) ;
}
2012-06-25 01:41:57 +00:00
# endif
2010-01-23 19:44:49 +00:00
return result ;
}
void MP3Exporter : : CancelEncoding ( )
{
mEncoding = false ;
}
2018-01-22 19:10:03 +00:00
bool MP3Exporter : : PutInfoTag ( wxFFile & f , wxFileOffset off )
2010-01-23 19:44:49 +00:00
{
if ( mGF ) {
if ( mInfoTagLen > 0 ) {
2016-07-09 20:20:35 +00:00
// FIXME: TRAP_ERR Seek and writ ein MP3 exporter could fail.
2018-01-22 19:10:03 +00:00
if ( ! f . Seek ( off , wxFromStart ) )
return false ;
if ( mInfoTagLen > f . Write ( mInfoTagBuf , mInfoTagLen ) )
return false ;
2010-01-23 19:44:49 +00:00
}
# if defined(__WXMSW__)
else if ( beWriteInfoTag ) {
2018-01-22 19:10:03 +00:00
if ( ! f . Flush ( ) )
return false ;
// PRL: What is the correct error check on the return value?
2010-01-23 19:44:49 +00:00
beWriteInfoTag ( mGF , OSOUTPUT ( f . GetName ( ) ) ) ;
mGF = NULL ;
}
# endif
2014-05-29 15:38:54 +00:00
else if ( lame_mp3_tags_fid ! = NULL ) {
2010-01-23 19:44:49 +00:00
lame_mp3_tags_fid ( mGF , f . fp ( ) ) ;
}
}
2018-01-22 19:10:03 +00:00
if ( ! f . SeekEnd ( ) )
return false ;
return true ;
2010-01-23 19:44:49 +00:00
}
# if defined(__WXMSW__)
/* values for Windows */
wxString MP3Exporter : : GetLibraryPath ( )
{
wxRegKey reg ( wxT ( " HKEY_LOCAL_MACHINE \\ Software \\ Lame for Audacity " ) ) ;
wxString path ;
if ( reg . Exists ( ) ) {
2011-03-07 01:46:05 +00:00
wxLogMessage ( wxT ( " LAME registry key exists. " ) ) ;
2010-01-23 19:44:49 +00:00
reg . QueryValue ( wxT ( " InstallPath " ) , path ) ;
}
2011-03-07 01:46:05 +00:00
else {
wxLogMessage ( wxT ( " LAME registry key does not exist. " ) ) ;
}
wxLogMessage ( wxT ( " Library path is: " ) + path ) ;
2010-01-23 19:44:49 +00:00
return path ;
}
wxString MP3Exporter : : GetLibraryName ( )
{
return wxT ( " lame_enc.dll " ) ;
}
wxString MP3Exporter : : GetLibraryTypeString ( )
{
2014-10-02 21:34:01 +00:00
return _ ( " Only lame_enc.dll|lame_enc.dll|Dynamically Linked Libraries (*.dll) | * . dll | All Files | * " ) ;
2010-01-23 19:44:49 +00:00
}
# elif defined(__WXMAC__)
/* values for Mac OS X */
wxString MP3Exporter : : GetLibraryPath ( )
{
2017-03-03 19:27:17 +00:00
wxString path ;
path = wxT ( " /Library/Application Support/audacity/libs " ) ;
if ( wxFileExists ( path + wxT ( " / " ) + GetLibraryName ( ) ) )
{
return path ;
}
path = wxT ( " /usr/local/lib/audacity " ) ;
if ( wxFileExists ( path + wxT ( " / " ) + GetLibraryName ( ) ) )
{
return path ;
}
return wxT ( " /Library/Application Support/audacity/libs " ) ;
2010-01-23 19:44:49 +00:00
}
wxString MP3Exporter : : GetLibraryName ( )
{
2019-02-09 22:53:47 +00:00
if ( sizeof ( void * ) = = 8 )
return wxT ( " libmp3lame64bit.dylib " ) ;
2010-01-23 19:44:49 +00:00
return wxT ( " libmp3lame.dylib " ) ;
}
wxString MP3Exporter : : GetLibraryTypeString ( )
{
2019-02-09 22:53:47 +00:00
if ( sizeof ( void * ) = = 8 )
return wxString ( _ ( " Only libmp3lame64bit.dylib|libmp3lame64bit.dylib|Dynamic Libraries (*.dylib) | * . dylib | All Files ( * ) | * " )) ;
2010-01-23 19:44:49 +00:00
return wxString ( _ ( " Only libmp3lame.dylib|libmp3lame.dylib|Dynamic Libraries (*.dylib) | * . dylib | All Files ( * ) | * " )) ;
}
# else //!__WXMAC__
/* Values for Linux / Unix systems */
wxString MP3Exporter : : GetLibraryPath ( )
{
return wxT ( LIBDIR ) ;
}
wxString MP3Exporter : : GetLibraryName ( )
{
return wxT ( " libmp3lame.so.0 " ) ;
}
wxString MP3Exporter : : GetLibraryTypeString ( )
{
return wxString ( _ ( " Only libmp3lame.so.0|libmp3lame.so.0|Primary Shared Object files (*.so) | * . so | Extended Libraries ( * . so * ) | * . so * | All Files ( * ) | * " )) ;
}
# endif
#if 0
// Debug routine from BladeMP3EncDLL.c in the libmp3lame distro
static void dump_config ( lame_global_flags * gfp )
{
2013-02-23 04:33:20 +00:00
wxPrintf ( wxT ( " \n \n Lame_enc configuration options: \n " ) ) ;
wxPrintf ( wxT ( " ========================================================== \n " ) ) ;
wxPrintf ( wxT ( " version =%d \n " ) , lame_get_version ( gfp ) ) ;
wxPrintf ( wxT ( " Layer =3 \n " ) ) ;
wxPrintf ( wxT ( " mode = " ) ) ;
switch ( lame_get_mode ( gfp ) )
{
case STEREO : wxPrintf ( wxT ( " Stereo \n " ) ) ; break ;
case JOINT_STEREO : wxPrintf ( wxT ( " Joint-Stereo \n " ) ) ; break ;
case DUAL_CHANNEL : wxPrintf ( wxT ( " Forced Stereo \n " ) ) ; break ;
case MONO : wxPrintf ( wxT ( " Mono \n " ) ) ; break ;
case NOT_SET : /* FALLTROUGH */
default : wxPrintf ( wxT ( " Error (unknown) \n " ) ) ; break ;
}
wxPrintf ( wxT ( " Input sample rate =%.1f kHz \n " ) , lame_get_in_samplerate ( gfp ) / 1000.0 ) ;
wxPrintf ( wxT ( " Output sample rate =%.1f kHz \n " ) , lame_get_out_samplerate ( gfp ) / 1000.0 ) ;
wxPrintf ( wxT ( " bitrate =%d kbps \n " ) , lame_get_brate ( gfp ) ) ;
wxPrintf ( wxT ( " Quality Setting =%d \n " ) , lame_get_quality ( gfp ) ) ;
wxPrintf ( wxT ( " Low pass frequency =%d \n " ) , lame_get_lowpassfreq ( gfp ) ) ;
wxPrintf ( wxT ( " Low pass width =%d \n " ) , lame_get_lowpasswidth ( gfp ) ) ;
wxPrintf ( wxT ( " High pass frequency =%d \n " ) , lame_get_highpassfreq ( gfp ) ) ;
wxPrintf ( wxT ( " High pass width =%d \n " ) , lame_get_highpasswidth ( gfp ) ) ;
wxPrintf ( wxT ( " No short blocks =%d \n " ) , lame_get_no_short_blocks ( gfp ) ) ;
wxPrintf ( wxT ( " Force short blocks =%d \n " ) , lame_get_force_short_blocks ( gfp ) ) ;
wxPrintf ( wxT ( " de-emphasis =%d \n " ) , lame_get_emphasis ( gfp ) ) ;
wxPrintf ( wxT ( " private flag =%d \n " ) , lame_get_extension ( gfp ) ) ;
wxPrintf ( wxT ( " copyright flag =%d \n " ) , lame_get_copyright ( gfp ) ) ;
wxPrintf ( wxT ( " original flag =%d \n " ) , lame_get_original ( gfp ) ) ;
wxPrintf ( wxT ( " CRC =%s \n " ) , lame_get_error_protection ( gfp ) ? wxT ( " on " ) : wxT ( " off " ) ) ;
wxPrintf ( wxT ( " Fast mode =%s \n " ) , ( lame_get_quality ( gfp ) ) ? wxT ( " enabled " ) : wxT ( " disabled " ) ) ;
wxPrintf ( wxT ( " Force mid/side stereo =%s \n " ) , ( lame_get_force_ms ( gfp ) ) ? wxT ( " enabled " ) : wxT ( " disabled " ) ) ;
2014-11-08 16:42:34 +00:00
wxPrintf ( wxT ( " Padding Type =%d \n " ) , ( int ) lame_get_padding_type ( gfp ) ) ;
2013-02-23 04:33:20 +00:00
wxPrintf ( wxT ( " Disable Reservoir =%d \n " ) , lame_get_disable_reservoir ( gfp ) ) ;
wxPrintf ( wxT ( " Allow diff-short =%d \n " ) , lame_get_allow_diff_short ( gfp ) ) ;
2014-11-08 16:42:34 +00:00
wxPrintf ( wxT ( " Interchannel masking =%d \n " ) , lame_get_interChRatio ( gfp ) ) ; // supposed to be a float, but in lib-src/lame/lame/lame.h it's int
2013-02-23 04:33:20 +00:00
wxPrintf ( wxT ( " Strict ISO Encoding =%s \n " ) , ( lame_get_strict_ISO ( gfp ) ) ? wxT ( " Yes " ) : wxT ( " No " ) ) ;
wxPrintf ( wxT ( " Scale =%5.2f \n " ) , lame_get_scale ( gfp ) ) ;
wxPrintf ( wxT ( " VBR =%s, VBR_q =%d, VBR method = " ) ,
( lame_get_VBR ( gfp ) ! = vbr_off ) ? wxT ( " enabled " ) : wxT ( " disabled " ) ,
lame_get_VBR_q ( gfp ) ) ;
switch ( lame_get_VBR ( gfp ) )
{
case vbr_off : wxPrintf ( wxT ( " vbr_off \n " ) ) ; break ;
case vbr_mt : wxPrintf ( wxT ( " vbr_mt \n " ) ) ; break ;
case vbr_rh : wxPrintf ( wxT ( " vbr_rh \n " ) ) ; break ;
case vbr_mtrh : wxPrintf ( wxT ( " vbr_mtrh \n " ) ) ; break ;
case vbr_abr :
wxPrintf ( wxT ( " vbr_abr (average bitrate %d kbps) \n " ) , lame_get_VBR_mean_bitrate_kbps ( gfp ) ) ;
break ;
default :
wxPrintf ( wxT ( " error, unknown VBR setting \n " ) ) ;
break ;
}
wxPrintf ( wxT ( " Vbr Min bitrate =%d kbps \n " ) , lame_get_VBR_min_bitrate_kbps ( gfp ) ) ;
wxPrintf ( wxT ( " Vbr Max bitrate =%d kbps \n " ) , lame_get_VBR_max_bitrate_kbps ( gfp ) ) ;
wxPrintf ( wxT ( " Write VBR Header =%s \n " ) , ( lame_get_bWriteVbrTag ( gfp ) ) ? wxT ( " Yes " ) : wxT ( " No " ) ) ;
wxPrintf ( wxT ( " VBR Hard min =%d \n " ) , lame_get_VBR_hard_min ( gfp ) ) ;
wxPrintf ( wxT ( " ATH Only =%d \n " ) , lame_get_ATHonly ( gfp ) ) ;
wxPrintf ( wxT ( " ATH short =%d \n " ) , lame_get_ATHshort ( gfp ) ) ;
wxPrintf ( wxT ( " ATH no =%d \n " ) , lame_get_noATH ( gfp ) ) ;
wxPrintf ( wxT ( " ATH type =%d \n " ) , lame_get_ATHtype ( gfp ) ) ;
wxPrintf ( wxT ( " ATH lower =%f \n " ) , lame_get_ATHlower ( gfp ) ) ;
wxPrintf ( wxT ( " ATH aa =%d \n " ) , lame_get_athaa_type ( gfp ) ) ;
wxPrintf ( wxT ( " ATH aa loudapprox =%d \n " ) , lame_get_athaa_loudapprox ( gfp ) ) ;
wxPrintf ( wxT ( " ATH aa sensitivity =%f \n " ) , lame_get_athaa_sensitivity ( gfp ) ) ;
wxPrintf ( wxT ( " Experimental nspsytune =%d \n " ) , lame_get_exp_nspsytune ( gfp ) ) ;
wxPrintf ( wxT ( " Experimental X =%d \n " ) , lame_get_experimentalX ( gfp ) ) ;
wxPrintf ( wxT ( " Experimental Y =%d \n " ) , lame_get_experimentalY ( gfp ) ) ;
wxPrintf ( wxT ( " Experimental Z =%d \n " ) , lame_get_experimentalZ ( gfp ) ) ;
2010-01-23 19:44:49 +00:00
}
# endif
//----------------------------------------------------------------------------
// ExportMP3
//----------------------------------------------------------------------------
2016-02-24 06:06:39 +00:00
class ExportMP3 final : public ExportPlugin
2010-01-23 19:44:49 +00:00
{
public :
ExportMP3 ( ) ;
2018-04-07 19:28:27 +00:00
bool CheckFileName ( wxFileName & filename , int format ) override ;
2010-01-23 19:44:49 +00:00
// Required
2017-10-01 17:28:04 +00:00
wxWindow * OptionsCreate ( wxWindow * parent , int format ) override ;
2016-12-24 15:43:25 +00:00
ProgressResult Export ( AudacityProject * project ,
2018-01-25 20:58:37 +00:00
std : : unique_ptr < ProgressDialog > & pDialog ,
2016-09-02 19:53:09 +00:00
unsigned channels ,
2016-02-23 02:17:04 +00:00
const wxString & fName ,
2010-01-23 19:44:49 +00:00
bool selectedOnly ,
double t0 ,
double t1 ,
MixerSpec * mixerSpec = NULL ,
2016-02-08 20:59:50 +00:00
const Tags * metadata = NULL ,
2016-02-23 02:17:04 +00:00
int subformat = 0 ) override ;
2010-01-23 19:44:49 +00:00
2019-07-29 19:43:41 +00:00
virtual unsigned SequenceNumber ( ) const override { return 20 ; }
2010-01-23 19:44:49 +00:00
private :
int FindValue ( CHOICES * choices , int cnt , int needle , int def ) ;
wxString FindName ( CHOICES * choices , int cnt , int needle ) ;
int AskResample ( int bitrate , int rate , int lowrate , int highrate ) ;
2019-03-10 17:35:52 +00:00
unsigned long AddTags ( AudacityProject * project , ArrayOf < char > & buffer , bool * endOfFile , const Tags * tags ) ;
2014-06-03 20:30:19 +00:00
# ifdef USE_LIBID3TAG
2011-03-01 07:06:58 +00:00
void AddFrame ( struct id3_tag * tp , const wxString & n , const wxString & v , const char * name ) ;
2011-02-27 03:52:36 +00:00
# endif
2016-04-12 20:58:08 +00:00
int SetNumExportChannels ( ) override ;
2010-01-23 19:44:49 +00:00
} ;
ExportMP3 : : ExportMP3 ( )
: ExportPlugin ( )
{
InitMP3_Statics ( ) ;
AddFormat ( ) ;
SetFormat ( wxT ( " MP3 " ) , 0 ) ;
AddExtension ( wxT ( " mp3 " ) , 0 ) ;
SetMaxChannels ( 2 , 0 ) ;
SetCanMetaData ( true , 0 ) ;
SetDescription ( _ ( " MP3 Files " ) , 0 ) ;
}
2015-08-28 03:29:02 +00:00
bool ExportMP3 : : CheckFileName ( wxFileName & WXUNUSED ( filename ) , int WXUNUSED ( format ) )
{
2015-10-15 22:36:26 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2015-08-28 03:29:02 +00:00
MP3Exporter exporter ;
if ( ! exporter . LoadLibrary ( wxTheApp - > GetTopWindow ( ) , MP3Exporter : : Maybe ) ) {
2017-09-06 21:39:33 +00:00
AudacityMessageBox ( _ ( " Could not open MP3 encoding library! " ) ) ;
2015-08-28 03:29:02 +00:00
gPrefs - > Write ( wxT ( " /MP3/MP3LibPath " ) , wxString ( wxT ( " " ) ) ) ;
gPrefs - > Flush ( ) ;
return false ;
}
2015-10-15 22:36:26 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2015-08-28 03:29:02 +00:00
return true ;
}
2016-04-12 20:58:08 +00:00
int ExportMP3 : : SetNumExportChannels ( )
{
bool mono ;
gPrefs - > Read ( wxT ( " /FileFormats/MP3ForceMono " ) , & mono , 0 ) ;
return ( mono ) ? 1 : - 1 ;
}
2016-12-24 15:43:25 +00:00
ProgressResult ExportMP3 : : Export ( AudacityProject * project ,
2018-01-25 20:58:37 +00:00
std : : unique_ptr < ProgressDialog > & pDialog ,
2016-09-02 19:53:09 +00:00
unsigned channels ,
2016-02-23 02:17:04 +00:00
const wxString & fName ,
2010-01-23 19:44:49 +00:00
bool selectionOnly ,
double t0 ,
double t1 ,
MixerSpec * mixerSpec ,
2016-02-08 20:59:50 +00:00
const Tags * metadata ,
2013-08-25 21:51:26 +00:00
int WXUNUSED ( subformat ) )
2010-01-23 19:44:49 +00:00
{
2019-05-27 14:17:16 +00:00
int rate = lrint ( ProjectSettings : : Get ( * project ) . GetRate ( ) ) ;
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2019-05-28 17:12:56 +00:00
wxWindow * parent = ProjectWindow : : Find ( project ) ;
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2019-05-06 23:00:10 +00:00
const auto & tracks = TrackList : : Get ( * project ) ;
2010-01-23 19:44:49 +00:00
MP3Exporter exporter ;
2012-06-25 01:41:57 +00:00
# ifdef DISABLE_DYNAMIC_LOADING_LAME
if ( ! exporter . InitLibrary ( wxT ( " " ) ) ) {
2017-09-06 21:39:33 +00:00
AudacityMessageBox ( _ ( " Could not initialize MP3 encoding library! " ) ) ;
2012-06-25 01:41:57 +00:00
gPrefs - > Write ( wxT ( " /MP3/MP3LibPath " ) , wxString ( wxT ( " " ) ) ) ;
2012-08-02 06:03:19 +00:00
gPrefs - > Flush ( ) ;
2012-06-25 01:41:57 +00:00
2017-03-22 20:25:49 +00:00
return ProgressResult : : Cancelled ;
2012-06-25 01:41:57 +00:00
}
# else
2010-01-23 19:44:49 +00:00
if ( ! exporter . LoadLibrary ( parent , MP3Exporter : : Maybe ) ) {
2017-09-06 21:39:33 +00:00
AudacityMessageBox ( _ ( " Could not open MP3 encoding library! " ) ) ;
2010-01-23 19:44:49 +00:00
gPrefs - > Write ( wxT ( " /MP3/MP3LibPath " ) , wxString ( wxT ( " " ) ) ) ;
2012-08-02 06:03:19 +00:00
gPrefs - > Flush ( ) ;
2010-01-23 19:44:49 +00:00
2016-12-24 15:43:25 +00:00
return ProgressResult : : Cancelled ;
2010-01-23 19:44:49 +00:00
}
if ( ! exporter . ValidLibraryLoaded ( ) ) {
2017-09-06 21:39:33 +00:00
AudacityMessageBox ( _ ( " Not a valid or supported MP3 encoding library! " ) ) ;
2010-01-23 19:44:49 +00:00
gPrefs - > Write ( wxT ( " /MP3/MP3LibPath " ) , wxString ( wxT ( " " ) ) ) ;
2012-08-02 06:03:19 +00:00
gPrefs - > Flush ( ) ;
2014-06-03 20:30:19 +00:00
2016-12-24 15:43:25 +00:00
return ProgressResult : : Cancelled ;
2010-01-23 19:44:49 +00:00
}
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
// Retrieve preferences
int highrate = 48000 ;
int lowrate = 8000 ;
int bitrate = 0 ;
int brate ;
int vmode ;
2016-04-01 20:46:32 +00:00
bool forceMono ;
2010-01-23 19:44:49 +00:00
gPrefs - > Read ( wxT ( " /FileFormats/MP3Bitrate " ) , & brate , 128 ) ;
2019-03-19 16:06:57 +00:00
auto rmode = MP3RateModeSetting . ReadEnumWithDefault ( MODE_CBR ) ;
2010-01-23 19:44:49 +00:00
gPrefs - > Read ( wxT ( " /FileFormats/MP3VarMode " ) , & vmode , ROUTINE_FAST ) ;
2019-03-19 16:06:57 +00:00
auto cmode = MP3ChannelModeSetting . ReadEnumWithDefault ( CHANNEL_STEREO ) ;
2016-04-01 20:46:32 +00:00
gPrefs - > Read ( wxT ( " /FileFormats/MP3ForceMono " ) , & forceMono , 0 ) ;
2010-01-23 19:44:49 +00:00
// Set the bitrate/quality and mode
if ( rmode = = MODE_SET ) {
int q = FindValue ( setRates , WXSIZEOF ( setRates ) , brate , PRESET_STANDARD ) ;
int r = FindValue ( varModes , WXSIZEOF ( varModes ) , vmode , ROUTINE_FAST ) ;
exporter . SetMode ( MODE_SET ) ;
exporter . SetQuality ( q , r ) ;
}
else if ( rmode = = MODE_VBR ) {
int q = FindValue ( varRates , WXSIZEOF ( varRates ) , brate , QUALITY_2 ) ;
int r = FindValue ( varModes , WXSIZEOF ( varModes ) , vmode , ROUTINE_FAST ) ;
exporter . SetMode ( MODE_VBR ) ;
exporter . SetQuality ( q , r ) ;
}
else if ( rmode = = MODE_ABR ) {
bitrate = FindValue ( fixRates , WXSIZEOF ( fixRates ) , brate , 128 ) ;
exporter . SetMode ( MODE_ABR ) ;
exporter . SetBitrate ( bitrate ) ;
if ( bitrate > 160 ) {
lowrate = 32000 ;
}
else if ( bitrate < 32 | | bitrate = = 144 ) {
highrate = 24000 ;
}
}
else {
bitrate = FindValue ( fixRates , WXSIZEOF ( fixRates ) , brate , 128 ) ;
exporter . SetMode ( MODE_CBR ) ;
exporter . SetBitrate ( bitrate ) ;
if ( bitrate > 160 ) {
lowrate = 32000 ;
}
else if ( bitrate < 32 | | bitrate = = 144 ) {
highrate = 24000 ;
}
}
// Verify sample rate
2019-02-12 00:10:48 +00:00
if ( FindName ( sampRates , WXSIZEOF ( sampRates ) , rate ) . empty ( ) | |
2010-01-23 19:44:49 +00:00
( rate < lowrate ) | | ( rate > highrate ) ) {
rate = AskResample ( bitrate , rate , lowrate , highrate ) ;
if ( rate = = 0 ) {
2016-12-24 15:43:25 +00:00
return ProgressResult : : Cancelled ;
2010-01-23 19:44:49 +00:00
}
}
// Set the channel mode
2016-04-01 20:46:32 +00:00
if ( forceMono ) {
exporter . SetChannel ( CHANNEL_MONO ) ;
}
else if ( cmode = = CHANNEL_JOINT ) {
2010-01-23 19:44:49 +00:00
exporter . SetChannel ( CHANNEL_JOINT ) ;
}
else {
exporter . SetChannel ( CHANNEL_STEREO ) ;
}
2016-08-24 15:24:26 +00:00
auto inSamples = exporter . InitializeStream ( channels , rate ) ;
2010-01-23 19:44:49 +00:00
if ( ( ( int ) inSamples ) < 0 ) {
2017-09-06 21:39:33 +00:00
AudacityMessageBox ( _ ( " Unable to initialize MP3 stream " ) ) ;
2016-12-24 15:43:25 +00:00
return ProgressResult : : Cancelled ;
2010-01-23 19:44:49 +00:00
}
// Put ID3 tags at beginning of file
if ( metadata = = NULL )
2019-01-22 21:32:14 +00:00
metadata = & Tags : : Get ( * project ) ;
2010-01-23 19:44:49 +00:00
// Open file for writing
wxFFile outFile ( fName , wxT ( " w+b " ) ) ;
if ( ! outFile . IsOpened ( ) ) {
2017-09-06 21:39:33 +00:00
AudacityMessageBox ( _ ( " Unable to open target file for writing " ) ) ;
2016-12-24 15:43:25 +00:00
return ProgressResult : : Cancelled ;
2010-01-23 19:44:49 +00:00
}
2017-02-25 23:12:04 +00:00
ArrayOf < char > id3buffer ;
2010-01-23 19:44:49 +00:00
bool endOfFile ;
2019-03-10 17:35:52 +00:00
unsigned long id3len = AddTags ( project , id3buffer , & endOfFile , metadata ) ;
2010-01-23 19:44:49 +00:00
if ( id3len & & ! endOfFile ) {
2018-03-06 09:06:37 +00:00
if ( id3len > outFile . Write ( id3buffer . get ( ) , id3len ) ) {
2018-01-20 20:19:20 +00:00
// TODO: more precise message
AudacityMessageBox ( _ ( " Unable to export " ) ) ;
return ProgressResult : : Cancelled ;
}
2010-01-23 19:44:49 +00:00
}
wxFileOffset pos = outFile . Tell ( ) ;
2016-12-24 15:43:25 +00:00
auto updateResult = ProgressResult : : Success ;
2018-02-27 09:13:54 +00:00
int bytes = 0 ;
2010-01-23 19:44:49 +00:00
2016-04-14 15:56:09 +00:00
size_t bufferSize = std : : max ( 0 , exporter . GetOutBufferSize ( ) ) ;
2018-01-20 20:19:20 +00:00
if ( bufferSize < = 0 ) {
// TODO: more precise message
AudacityMessageBox ( _ ( " Unable to export " ) ) ;
2016-12-24 13:57:27 +00:00
return ProgressResult : : Cancelled ;
2018-01-20 20:19:20 +00:00
}
2016-12-24 13:57:27 +00:00
2016-04-14 15:56:09 +00:00
ArrayOf < unsigned char > buffer { bufferSize } ;
2010-01-23 19:44:49 +00:00
wxASSERT ( buffer ) ;
2016-02-01 01:39:24 +00:00
{
2019-05-24 14:11:52 +00:00
auto mixer = CreateMixer ( tracks , selectionOnly ,
2016-03-31 05:33:17 +00:00
t0 , t1 ,
channels , inSamples , true ,
rate , int16Sample , true , mixerSpec ) ;
wxString title ;
if ( rmode = = MODE_SET ) {
title . Printf ( selectionOnly ?
_ ( " Exporting selected audio with %s preset " ) :
2017-12-17 17:34:28 +00:00
_ ( " Exporting the audio with %s preset " ) ,
2017-10-09 05:03:14 +00:00
FindName ( setRates , WXSIZEOF ( setRates ) , brate ) ) ;
2016-03-31 05:33:17 +00:00
}
else if ( rmode = = MODE_VBR ) {
title . Printf ( selectionOnly ?
_ ( " Exporting selected audio with VBR quality %s " ) :
2017-12-17 17:34:28 +00:00
_ ( " Exporting the audio with VBR quality %s " ) ,
2017-10-09 05:03:14 +00:00
FindName ( varRates , WXSIZEOF ( varRates ) , brate ) ) ;
2016-03-31 05:33:17 +00:00
}
else {
title . Printf ( selectionOnly ?
_ ( " Exporting selected audio at %d Kbps " ) :
2017-12-17 17:34:28 +00:00
_ ( " Exporting the audio at %d Kbps " ) ,
2016-03-31 05:33:17 +00:00
brate ) ;
}
2018-01-25 20:58:37 +00:00
InitProgress ( pDialog , wxFileName ( fName ) . GetName ( ) , title ) ;
auto & progress = * pDialog ;
2010-01-23 19:44:49 +00:00
2016-12-24 15:43:25 +00:00
while ( updateResult = = ProgressResult : : Success ) {
2016-08-24 15:24:26 +00:00
auto blockLen = mixer - > Process ( inSamples ) ;
2010-01-23 19:44:49 +00:00
2016-02-01 01:39:24 +00:00
if ( blockLen = = 0 ) {
break ;
}
2014-06-03 20:30:19 +00:00
2016-02-01 01:39:24 +00:00
short * mixed = ( short * ) mixer - > GetBuffer ( ) ;
2010-01-23 19:44:49 +00:00
2018-01-23 11:49:15 +00:00
if ( ( int ) blockLen < inSamples ) {
2016-02-01 01:39:24 +00:00
if ( channels > 1 ) {
2016-04-14 15:56:09 +00:00
bytes = exporter . EncodeRemainder ( mixed , blockLen , buffer . get ( ) ) ;
2016-02-01 01:39:24 +00:00
}
else {
2016-04-14 15:56:09 +00:00
bytes = exporter . EncodeRemainderMono ( mixed , blockLen , buffer . get ( ) ) ;
2016-02-01 01:39:24 +00:00
}
2010-01-23 19:44:49 +00:00
}
else {
2016-02-01 01:39:24 +00:00
if ( channels > 1 ) {
2016-04-14 15:56:09 +00:00
bytes = exporter . EncodeBuffer ( mixed , buffer . get ( ) ) ;
2016-02-01 01:39:24 +00:00
}
else {
2016-04-14 15:56:09 +00:00
bytes = exporter . EncodeBufferMono ( mixed , buffer . get ( ) ) ;
2016-02-01 01:39:24 +00:00
}
2010-01-23 19:44:49 +00:00
}
2016-02-01 01:39:24 +00:00
if ( bytes < 0 ) {
wxString msg ;
msg . Printf ( _ ( " Error %ld returned from MP3 encoder " ) , bytes ) ;
2017-09-06 21:39:33 +00:00
AudacityMessageBox ( msg ) ;
2016-12-24 13:57:27 +00:00
updateResult = ProgressResult : : Cancelled ;
2016-02-01 01:39:24 +00:00
break ;
}
2010-01-23 19:44:49 +00:00
2018-03-02 12:02:23 +00:00
if ( bytes > ( int ) outFile . Write ( buffer . get ( ) , bytes ) ) {
2018-01-20 20:19:20 +00:00
// TODO: more precise message
AudacityMessageBox ( _ ( " Unable to export " ) ) ;
updateResult = ProgressResult : : Cancelled ;
break ;
}
2010-01-23 19:44:49 +00:00
2016-02-01 01:39:24 +00:00
updateResult = progress . Update ( mixer - > MixGetCurrentTime ( ) - t0 , t1 - t0 ) ;
}
2010-01-23 19:44:49 +00:00
}
2018-01-20 20:19:20 +00:00
if ( updateResult = = ProgressResult : : Success | |
updateResult = = ProgressResult : : Stopped ) {
2016-12-24 13:57:27 +00:00
bytes = exporter . FinishStream ( buffer . get ( ) ) ;
2010-01-23 19:44:49 +00:00
2018-01-20 20:19:20 +00:00
if ( bytes < 0 ) {
// TODO: more precise message
AudacityMessageBox ( _ ( " Unable to export " ) ) ;
return ProgressResult : : Cancelled ;
}
2016-12-24 13:57:27 +00:00
if ( bytes > 0 ) {
2018-03-02 12:02:23 +00:00
if ( bytes > ( int ) outFile . Write ( buffer . get ( ) , bytes ) ) {
2018-01-20 20:19:20 +00:00
// TODO: more precise message
AudacityMessageBox ( _ ( " Unable to export " ) ) ;
return ProgressResult : : Cancelled ;
}
2016-12-24 13:57:27 +00:00
}
2010-01-23 19:44:49 +00:00
2016-12-24 13:57:27 +00:00
// Write ID3 tag if it was supposed to be at the end of the file
if ( id3len > 0 & & endOfFile ) {
2018-03-02 12:02:23 +00:00
if ( bytes > ( int ) outFile . Write ( id3buffer . get ( ) , id3len ) ) {
2018-01-20 20:19:20 +00:00
// TODO: more precise message
AudacityMessageBox ( _ ( " Unable to export " ) ) ;
return ProgressResult : : Cancelled ;
}
2016-12-24 13:57:27 +00:00
}
2010-01-23 19:44:49 +00:00
2016-12-24 13:57:27 +00:00
// Always write the info (Xing/Lame) tag. Until we stop supporting Lame
// versions before 3.98, we must do this after the MP3 file has been
// closed.
//
// Also, if beWriteInfoTag() is used, mGF will no longer be valid after
// this call, so do not use it.
2018-01-22 19:10:03 +00:00
if ( ! exporter . PutInfoTag ( outFile , pos ) | |
! outFile . Flush ( ) | |
! outFile . Close ( ) ) {
2018-01-20 20:19:20 +00:00
// TODO: more precise message
AudacityMessageBox ( _ ( " Unable to export " ) ) ;
return ProgressResult : : Cancelled ;
}
2016-12-24 13:57:27 +00:00
}
2010-01-23 19:44:49 +00:00
return updateResult ;
}
2015-07-13 17:36:40 +00:00
wxWindow * ExportMP3 : : OptionsCreate ( wxWindow * parent , int format )
2010-01-23 19:44:49 +00:00
{
2016-02-14 07:54:25 +00:00
wxASSERT ( parent ) ; // to justify safenew
return safenew ExportMP3Options ( parent , format ) ;
2010-01-23 19:44:49 +00:00
}
int ExportMP3 : : FindValue ( CHOICES * choices , int cnt , int needle , int def )
{
for ( int i = 0 ; i < cnt ; i + + ) {
if ( choices [ i ] . label = = needle ) {
return needle ;
}
}
return def ;
}
wxString ExportMP3 : : FindName ( CHOICES * choices , int cnt , int needle )
{
for ( int i = 0 ; i < cnt ; i + + ) {
if ( choices [ i ] . label = = needle ) {
return choices [ i ] . name . BeforeFirst ( wxT ( ' , ' ) ) ;
}
}
return wxT ( " " ) ;
}
int ExportMP3 : : AskResample ( int bitrate , int rate , int lowrate , int highrate )
{
2016-07-10 21:10:50 +00:00
wxDialogWrapper d ( nullptr , wxID_ANY , wxString ( _ ( " Invalid sample rate " ) ) ) ;
2015-05-18 12:57:05 +00:00
d . SetName ( d . GetTitle ( ) ) ;
2010-01-23 19:44:49 +00:00
wxChoice * choice ;
ShuttleGui S ( & d , eIsCreating ) ;
wxString text ;
S . StartVerticalLay ( ) ;
{
S . SetBorder ( 10 ) ;
S . StartStatic ( _ ( " Resample " ) ) ;
{
S . StartHorizontalLay ( wxALIGN_CENTER , false ) ;
{
if ( bitrate = = 0 ) {
2018-10-15 16:54:44 +00:00
text . Printf ( _ ( " The project sample rate (%d) is not supported by the MP3 \n file format. " ) , rate ) ;
2010-01-23 19:44:49 +00:00
}
else {
2018-10-15 16:54:44 +00:00
text . Printf ( _ ( " The project sample rate (%d) and bit rate (%d kbps) combination is not \n supported by the MP3 file format. " ) , rate , bitrate ) ;
2010-01-23 19:44:49 +00:00
}
text + = _ ( " You may resample to one of the rates below. " ) ;
S . AddTitle ( text ) ;
}
S . EndHorizontalLay ( ) ;
2018-02-02 00:23:02 +00:00
wxArrayStringEx choices ;
2019-02-12 21:30:22 +00:00
int selected = - 1 ;
2010-01-23 19:44:49 +00:00
for ( size_t i = 0 ; i < WXSIZEOF ( sampRates ) ; i + + ) {
int label = sampRates [ i ] . label ;
if ( label > = lowrate & & label < = highrate ) {
2019-02-12 00:10:48 +00:00
choices . push_back ( sampRates [ i ] . name ) ;
2010-01-23 19:44:49 +00:00
if ( label < = rate ) {
2019-02-12 21:30:22 +00:00
selected = i ;
2010-01-23 19:44:49 +00:00
}
}
}
2019-02-12 21:30:22 +00:00
if ( selected = = - 1 ) {
selected = 0 ;
2010-01-23 19:44:49 +00:00
}
S . StartHorizontalLay ( wxALIGN_CENTER , false ) ;
{
choice = S . AddChoice ( _ ( " Sample Rates " ) ,
2018-02-02 00:23:02 +00:00
choices ,
2019-02-12 21:30:22 +00:00
selected ) ;
2010-01-23 19:44:49 +00:00
}
S . EndHorizontalLay ( ) ;
}
S . EndStatic ( ) ;
S . AddStandardButtons ( ) ;
}
S . EndVerticalLay ( ) ;
d . Layout ( ) ;
d . Fit ( ) ;
d . SetMinSize ( d . GetSize ( ) ) ;
d . Center ( ) ;
if ( d . ShowModal ( ) = = wxID_CANCEL ) {
return 0 ;
}
return wxAtoi ( choice - > GetStringSelection ( ) ) ;
}
2018-01-07 17:06:33 +00:00
# ifdef USE_LIBID3TAG
2017-02-25 23:12:04 +00:00
struct id3_tag_deleter {
void operator ( ) ( id3_tag * p ) const { if ( p ) id3_tag_delete ( p ) ; }
} ;
using id3_tag_holder = std : : unique_ptr < id3_tag , id3_tag_deleter > ;
2018-01-07 17:06:33 +00:00
# endif
2017-02-25 23:12:04 +00:00
2010-01-23 19:44:49 +00:00
// returns buffer len; caller frees
2019-03-10 17:35:52 +00:00
unsigned long ExportMP3 : : AddTags ( AudacityProject * WXUNUSED ( project ) , ArrayOf < char > & buffer , bool * endOfFile , const Tags * tags )
2010-01-23 19:44:49 +00:00
{
2014-06-03 20:30:19 +00:00
# ifdef USE_LIBID3TAG
2017-02-25 23:12:04 +00:00
id3_tag_holder tp { id3_tag_new ( ) } ;
2010-01-23 19:44:49 +00:00
2016-02-11 17:53:16 +00:00
for ( const auto & pair : tags - > GetRange ( ) ) {
const auto & n = pair . first ;
const auto & v = pair . second ;
2010-01-23 19:44:49 +00:00
const char * name = " TXXX " ;
if ( n . CmpNoCase ( TAG_TITLE ) = = 0 ) {
name = ID3_FRAME_TITLE ;
}
else if ( n . CmpNoCase ( TAG_ARTIST ) = = 0 ) {
name = ID3_FRAME_ARTIST ;
}
else if ( n . CmpNoCase ( TAG_ALBUM ) = = 0 ) {
name = ID3_FRAME_ALBUM ;
}
else if ( n . CmpNoCase ( TAG_YEAR ) = = 0 ) {
2011-02-27 03:52:36 +00:00
// LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR),
// so we add old one as well.
2017-02-25 23:12:04 +00:00
AddFrame ( tp . get ( ) , n , v , " TYER " ) ;
2011-02-27 03:52:36 +00:00
name = ID3_FRAME_YEAR ;
2010-01-23 19:44:49 +00:00
}
else if ( n . CmpNoCase ( TAG_GENRE ) = = 0 ) {
name = ID3_FRAME_GENRE ;
}
else if ( n . CmpNoCase ( TAG_COMMENTS ) = = 0 ) {
name = ID3_FRAME_COMMENT ;
}
else if ( n . CmpNoCase ( TAG_TRACK ) = = 0 ) {
name = ID3_FRAME_TRACK ;
}
2017-02-25 23:12:04 +00:00
AddFrame ( tp . get ( ) , n , v , name ) ;
2010-01-23 19:44:49 +00:00
}
2011-03-01 07:06:58 +00:00
tp - > options & = ( ~ ID3_TAG_OPTION_COMPRESSION ) ; // No compression
2010-01-23 19:44:49 +00:00
2011-03-01 07:06:58 +00:00
// If this version of libid3tag supports it, use v2.3 ID3
// tags instead of the newer, but less well supported, v2.4
// that libid3tag uses by default.
# ifdef ID3_TAG_HAS_TAG_OPTION_ID3V2_3
tp - > options | = ID3_TAG_OPTION_ID3V2_3 ;
# endif
2010-01-23 19:44:49 +00:00
2011-03-01 07:06:58 +00:00
* endOfFile = false ;
2010-01-23 19:44:49 +00:00
2019-03-10 17:35:52 +00:00
unsigned long len ;
2014-06-03 20:30:19 +00:00
2017-02-25 23:12:04 +00:00
len = id3_tag_render ( tp . get ( ) , 0 ) ;
buffer . reinit ( len ) ;
len = id3_tag_render ( tp . get ( ) , ( id3_byte_t * ) buffer . get ( ) ) ;
2010-01-23 19:44:49 +00:00
return len ;
2014-06-03 20:30:19 +00:00
# else //ifdef USE_LIBID3TAG
2010-01-23 19:44:49 +00:00
return 0 ;
# endif
}
2014-06-03 20:30:19 +00:00
# ifdef USE_LIBID3TAG
2011-03-01 07:06:58 +00:00
void ExportMP3 : : AddFrame ( struct id3_tag * tp , const wxString & n , const wxString & v , const char * name )
2011-02-27 03:52:36 +00:00
{
struct id3_frame * frame = id3_frame_new ( name ) ;
2011-03-01 07:06:58 +00:00
if ( ! n . IsAscii ( ) | | ! v . IsAscii ( ) ) {
id3_field_settextencoding ( id3_frame_field ( frame , 0 ) , ID3_FIELD_TEXTENCODING_UTF_16 ) ;
}
else {
id3_field_settextencoding ( id3_frame_field ( frame , 0 ) , ID3_FIELD_TEXTENCODING_ISO_8859_1 ) ;
2011-02-27 03:52:36 +00:00
}
2017-02-25 23:12:04 +00:00
MallocString < id3_ucs4_t > ucs4 {
id3_utf8_ucs4duplicate ( ( id3_utf8_t * ) ( const char * ) v . mb_str ( wxConvUTF8 ) ) } ;
2011-02-27 03:52:36 +00:00
2013-08-31 02:44:10 +00:00
if ( strcmp ( name , ID3_FRAME_COMMENT ) = = 0 ) {
2011-02-27 03:52:36 +00:00
// A hack to get around iTunes not recognizing the comment. The
// language defaults to XXX and, since it's not a valid language,
// iTunes just ignores the tag. So, either set it to a valid language
// (which one???) or just clear it. Unfortunately, there's no supported
// way of clearing the field, so do it directly.
2013-08-31 02:42:26 +00:00
struct id3_frame * frame2 = id3_frame_new ( name ) ;
2017-02-25 23:12:04 +00:00
id3_field_setfullstring ( id3_frame_field ( frame2 , 3 ) , ucs4 . get ( ) ) ;
2013-08-31 02:42:26 +00:00
id3_field * f2 = id3_frame_field ( frame2 , 1 ) ;
memset ( f2 - > immediate . value , 0 , sizeof ( f2 - > immediate . value ) ) ;
id3_tag_attachframe ( tp , frame2 ) ;
// Now install a second frame with the standard default language = "XXX"
2017-02-25 23:12:04 +00:00
id3_field_setfullstring ( id3_frame_field ( frame , 3 ) , ucs4 . get ( ) ) ;
2011-02-27 03:52:36 +00:00
}
else if ( strcmp ( name , " TXXX " ) = = 0 ) {
2017-02-25 23:12:04 +00:00
id3_field_setstring ( id3_frame_field ( frame , 2 ) , ucs4 . get ( ) ) ;
2011-02-27 03:52:36 +00:00
2017-02-25 23:12:04 +00:00
ucs4 . reset ( id3_utf8_ucs4duplicate ( ( id3_utf8_t * ) ( const char * ) n . mb_str ( wxConvUTF8 ) ) ) ;
2014-06-03 20:30:19 +00:00
2017-02-25 23:12:04 +00:00
id3_field_setstring ( id3_frame_field ( frame , 1 ) , ucs4 . get ( ) ) ;
2011-02-27 03:52:36 +00:00
}
else {
2017-02-25 23:12:04 +00:00
auto addr = ucs4 . get ( ) ;
id3_field_setstrings ( id3_frame_field ( frame , 1 ) , 1 , & addr ) ;
2011-02-27 03:52:36 +00:00
}
id3_tag_attachframe ( tp , frame ) ;
}
# endif
2019-07-29 19:43:41 +00:00
static Exporter : : RegisteredExportPlugin
sRegisteredPlugin { [ ] { return std : : make_unique < ExportMP3 > ( ) ; } } ;
2010-01-23 19:44:49 +00:00
//----------------------------------------------------------------------------
// Return library version
//----------------------------------------------------------------------------
wxString GetMP3Version ( wxWindow * parent , bool prompt )
{
MP3Exporter exporter ;
wxString versionString = _ ( " MP3 export library not found " ) ;
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
if ( prompt ) {
exporter . FindLibrary ( parent ) ;
}
if ( exporter . LoadLibrary ( parent , prompt ? MP3Exporter : : Yes : MP3Exporter : : No ) ) {
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
versionString = exporter . GetLibraryVersion ( ) ;
2019-03-26 17:47:41 +00:00
# ifdef MP3_EXPORT_BUILT_IN
versionString + = " " ;
2019-03-27 10:46:53 +00:00
versionString + = _ ( " (Built-in) " ) ;
2019-03-26 17:47:41 +00:00
# endif
2012-06-25 01:41:57 +00:00
# ifndef DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
}
2012-06-25 01:41:57 +00:00
# endif // DISABLE_DYNAMIC_LOADING_LAME
2010-01-23 19:44:49 +00:00
return versionString ;
}