Audacity 3.2.0
ExportMP3.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 ExportMP3.cpp
6
7 Joshua Haberman
8
9 This just acts as an interface to LAME. A Lame dynamic library must
10 be present
11
12 The difficulty in our approach is that we are attempting to use LAME
13 in a way it was not designed to be used. LAME's API is reasonably
14 consistent, so if we were linking directly against it we could expect
15 this code to work with a variety of different LAME versions. However,
16 the data structures change from version to version, and so linking
17 with one version of the header and dynamically linking against a
18 different version of the dynamic library will not work correctly.
19
20 The solution is to find the lowest common denominator between versions.
21 The bare minimum of functionality we must use is this:
22 1. Initialize the library.
23 2. Set, at minimum, the following global options:
24 i. input sample rate
25 ii. input channels
26 3. Encode the stream
27 4. Call the finishing routine
28
29 Just so that it's clear that we're NOT free to use whatever features
30 of LAME we like, I'm not including lame.h, but instead enumerating
31 here the extent of functions and structures that we can rely on being
32 able to import and use from a dynamic library.
33
34 For the record, we aim to support LAME 3.70 on. Since LAME 3.70 was
35 released in April of 2000, that should be plenty.
36
37
38 Copyright 2002, 2003 Joshua Haberman.
39 Some portions may be Copyright 2003 Paolo Patruno.
40
41 This program is free software; you can redistribute it and/or modify
42 it under the terms of the GNU General Public License as published by
43 the Free Software Foundation; either version 2 of the License, or
44 (at your option) any later version.
45
46 This program is distributed in the hope that it will be useful,
47 but WITHOUT ANY WARRANTY; without even the implied warranty of
48 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49 GNU General Public License for more details.
50
51 You should have received a copy of the GNU General Public License
52 along with this program; if not, write to the Free Software
53 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
54
55*******************************************************************//********************************************************************/
61
62
63#include "ExportMP3.h"
64
65#include <wx/app.h>
66#include <wx/defs.h>
67
68#include <wx/choice.h>
69#include <wx/checkbox.h>
70#include <wx/dynlib.h>
71#include <wx/ffile.h>
72#include <wx/intl.h>
73#include <wx/log.h>
74#include <wx/mimetype.h>
75#include <wx/radiobut.h>
76#include <wx/stattext.h>
77#include <wx/textctrl.h>
78#include <wx/timer.h>
79#include <wx/utils.h>
80#include <wx/window.h>
81
82#include "FileNames.h"
83#include "float_cast.h"
84#include "Mix.h"
85#include "Prefs.h"
86#include "ProjectRate.h"
87#include "../ProjectSettings.h"
88#include "../ProjectWindow.h"
89#include "../SelectFile.h"
90#include "../ShuttleGui.h"
91#include "../Tags.h"
92#include "Track.h"
93#include "../widgets/HelpSystem.h"
94#include "../widgets/AudacityMessageBox.h"
95#include "../widgets/ProgressDialog.h"
96#include "wxFileNameWrapper.h"
97#include "Project.h"
98
99#include "Export.h"
100
101#include <lame/lame.h>
102
103#ifdef USE_LIBID3TAG
104#include <id3tag.h>
105#endif
106
107//----------------------------------------------------------------------------
108// ExportMP3Options
109//----------------------------------------------------------------------------
110
111enum MP3ChannelMode : unsigned {
115};
116
117enum : int {
119
120 //ROUTINE_FAST = 0,
121 //ROUTINE_STANDARD = 1,
122
127};
128
129/* i18n-hint: kbps is the bitrate of the MP3 file, kilobits per second*/
130inline TranslatableString n_kbps( int n ){ return XO("%d kbps").Format( n ); }
131
133 n_kbps(320),
134 n_kbps(256),
135 n_kbps(224),
136 n_kbps(192),
137 n_kbps(160),
138 n_kbps(144),
139 n_kbps(128),
140 n_kbps(112),
141 n_kbps(96),
142 n_kbps(80),
143 n_kbps(64),
144 n_kbps(56),
145 n_kbps(48),
146 n_kbps(40),
147 n_kbps(32),
148 n_kbps(24),
149 n_kbps(16),
150 n_kbps(8),
151};
152
153static const std::vector<int> fixRateValues {
154 320,
155 256,
156 224,
157 192,
158 160,
159 144,
160 128,
161 112,
162 96,
163 80,
164 64,
165 56,
166 48,
167 40,
168 32,
169 24,
170 16,
171 8,
172};
173
175 XO("220-260 kbps (Best Quality)"),
176 XO("200-250 kbps"),
177 XO("170-210 kbps"),
178 XO("155-195 kbps"),
179 XO("145-185 kbps"),
180 XO("110-150 kbps"),
181 XO("95-135 kbps"),
182 XO("80-120 kbps"),
183 XO("65-105 kbps"),
184 XO("45-85 kbps (Smaller files)"),
185};
186/*
187static const TranslatableStrings varModeNames {
188 XO("Fast"),
189 XO("Standard"),
190};
191*/
193 /* i18n-hint: Slightly humorous - as in use an insane precision with MP3.*/
194 XO("Insane, 320 kbps"),
195 XO("Extreme, 220-260 kbps"),
196 XO("Standard, 170-210 kbps"),
197 XO("Medium, 145-185 kbps"),
198};
199
201 /* i18n-hint: Slightly humorous - as in use an insane precision with MP3.*/
202 XO("Insane"),
203 XO("Extreme"),
204 XO("Standard"),
205 XO("Medium"),
206};
207
208static const std::vector< int > sampRates {
209 8000,
210 11025,
211 12000,
212 16000,
213 22050,
214 24000,
215 32000,
216 44100,
217 48000,
218};
219
220#define ID_SET 7000
221#define ID_VBR 7001
222#define ID_ABR 7002
223#define ID_CBR 7003
224#define ID_QUALITY 7004
225#define ID_MONO 7005
226
228{
229public:
230
231 ExportMP3Options(wxWindow *parent, int format);
232 virtual ~ExportMP3Options();
233
235 bool TransferDataToWindow() override;
236 bool TransferDataFromWindow() override;
237
238 void OnSET(wxCommandEvent& evt);
239 void OnVBR(wxCommandEvent& evt);
240 void OnABR(wxCommandEvent& evt);
241 void OnCBR(wxCommandEvent& evt);
242 void OnQuality(wxCommandEvent& evt);
243 void OnMono(wxCommandEvent& evt);
244
245 void LoadNames(const TranslatableStrings &choices);
246
247private:
248
249 wxRadioButton *mStereo;
250 wxRadioButton *mJoint;
251 wxCheckBox *mMono;
252 wxRadioButton *mSET;
253 wxRadioButton *mVBR;
254 wxRadioButton *mABR;
255 wxRadioButton *mCBR;
256 wxChoice *mRate;
257 //wxChoice *mMode;
258
263
264 DECLARE_EVENT_TABLE()
265};
266
267BEGIN_EVENT_TABLE(ExportMP3Options, wxPanelWrapper)
268 EVT_RADIOBUTTON(ID_SET, ExportMP3Options::OnSET)
269 EVT_RADIOBUTTON(ID_VBR, ExportMP3Options::OnVBR)
270 EVT_RADIOBUTTON(ID_ABR, ExportMP3Options::OnABR)
271 EVT_RADIOBUTTON(ID_CBR, ExportMP3Options::OnCBR)
272 EVT_CHOICE(wxID_ANY, ExportMP3Options::OnQuality)
273 EVT_CHECKBOX(ID_MONO, ExportMP3Options::OnMono)
275
276
278ExportMP3Options::ExportMP3Options(wxWindow *parent, int WXUNUSED(format))
279: wxPanelWrapper(parent, wxID_ANY)
280{
281 mSetRate = gPrefs->Read(wxT("/FileFormats/MP3SetRate"), PRESET_STANDARD);
282 mVbrRate = gPrefs->Read(wxT("/FileFormats/MP3VbrRate"), QUALITY_2);
283 mAbrRate = gPrefs->Read(wxT("/FileFormats/MP3AbrRate"), 192);
284 mCbrRate = gPrefs->Read(wxT("/FileFormats/MP3CbrRate"), 192);
285
287 PopulateOrExchange(S);
288
289 TransferDataToWindow();
290}
291
293{
295}
296
298 wxT("/FileFormats/MP3RateModeChoice"),
299 {
300 { wxT("SET"), XXO("Preset") },
301 { wxT("VBR"), XXO("Variable") },
302 { wxT("ABR"), XXO("Average") },
303 { wxT("CBR"), XXO("Constant") },
304 },
305 0, // MODE_SET
306
307 // for migrating old preferences:
308 {
310 },
311 wxT("/FileFormats/MP3RateMode"),
312};
313
315 wxT("/FileFormats/MP3ChannelModeChoice"),
316 {
317 EnumValueSymbol{ wxT("JOINT"), XXO("Joint Stereo") },
318 EnumValueSymbol{ wxT("STEREO"), XXO("Stereo") },
319 },
320 0, // CHANNEL_JOINT
321
322 // for migrating old preferences:
323 {
325 },
326 wxT("/FileFormats/MP3ChannelMode"),
327};
328
332{
333 bool mono = false;
334 gPrefs->Read(wxT("/FileFormats/MP3ForceMono"), &mono, 0);
335
336 const TranslatableStrings *choices = nullptr;
337 const std::vector< int > *codes = nullptr;
338 //bool enable;
339 int defrate;
340
341 S.StartVerticalLay();
342 {
343 S.StartHorizontalLay(wxCENTER);
344 {
345 S.StartMultiColumn(2, wxCENTER);
346 {
347 S.SetStretchyCol(1);
348 S.StartTwoColumn();
349 {
350 S.AddPrompt(XXO("Bit Rate Mode:"));
351
352 // Bug 2692: Place button group in panel so tabbing will work and,
353 // on the Mac, VoiceOver will announce as radio buttons.
354 S.StartPanel();
355 {
356 S.StartHorizontalLay();
357 {
358 S.StartRadioButtonGroup(MP3RateModeSetting);
359 {
360 mSET = S.Id(ID_SET).TieRadioButton();
361 mVBR = S.Id(ID_VBR).TieRadioButton();
362 mABR = S.Id(ID_ABR).TieRadioButton();
363 mCBR = S.Id(ID_CBR).TieRadioButton();
364 }
365 S.EndRadioButtonGroup();
366 }
367 S.EndHorizontalLay();
368 }
369 S.EndPanel();
370
371 /* PRL: unfortunately this bit of procedural code must
372 interrupt the mostly-declarative dialog description, until
373 we find a better solution. Because when shuttling values
374 from the dialog, we must shuttle out the MP3RateModeSetting
375 first. */
376
377 switch( MP3RateModeSetting.ReadEnum() ) {
378 case MODE_SET:
379 choices = &setRateNames;
380 //enable = true;
381 defrate = mSetRate;
382 break;
383
384 case MODE_VBR:
385 choices = &varRateNames;
386 //enable = true;
387 defrate = mVbrRate;
388 break;
389
390 case MODE_ABR:
391 choices = &fixRateNames;
392 codes = &fixRateValues;
393 //enable = false;
394 defrate = mAbrRate;
395 break;
396
397 case MODE_CBR:
398 default:
399 choices = &fixRateNames;
400 codes = &fixRateValues;
401 //enable = false;
402 defrate = mCbrRate;
403 break;
404 }
405
406 mRate = S.Id(ID_QUALITY).TieNumberAsChoice(
407 XXO("Quality"),
408 { wxT("/FileFormats/MP3Bitrate"), defrate },
409 *choices,
410 codes
411 );
412 /*
413 mMode = S.Disable(!enable)
414 .TieNumberAsChoice(
415 XXO("Variable Speed:"),
416 { wxT("/FileFormats/MP3VarMode"), ROUTINE_FAST },
417 varModeNames );
418 */
419 S.AddPrompt(XXO("Channel Mode:"));
420 S.StartMultiColumn(2, wxEXPAND);
421 {
422 // Bug 2692: Place button group in panel so tabbing will work and,
423 // on the Mac, VoiceOver will announce as radio buttons.
424 S.StartPanel();
425 {
426 S.StartHorizontalLay();
427 {
428 S.StartRadioButtonGroup(MP3ChannelModeSetting);
429 {
430 mJoint = S.Disable(mono)
431 .TieRadioButton();
432 mStereo = S.Disable(mono)
433 .TieRadioButton();
434 }
435 S.EndRadioButtonGroup();
436 }
437 S.EndHorizontalLay();
438 }
439 S.EndPanel();
440
441 mMono = S.Id(ID_MONO).AddCheckBox(XXO("Force export to mono"), mono);
442 }
443 S.EndMultiColumn();
444 }
445 S.EndTwoColumn();
446 }
447 S.EndMultiColumn();
448 }
449 S.EndHorizontalLay();
450 }
451 S.EndVerticalLay();
452}
453
457{
458 return true;
459}
460
462{
465
466 gPrefs->Write(wxT("/FileFormats/MP3SetRate"), mSetRate);
467 gPrefs->Write(wxT("/FileFormats/MP3VbrRate"), mVbrRate);
468 gPrefs->Write(wxT("/FileFormats/MP3AbrRate"), mAbrRate);
469 gPrefs->Write(wxT("/FileFormats/MP3CbrRate"), mCbrRate);
470 gPrefs->Flush();
471
472 return true;
473}
474
475namespace {
476
477int ValidateValue( int nValues, int value, int defaultValue )
478{
479 return (value >= 0 && value < nValues) ? value : defaultValue;
480}
481
482int ValidateValue( const std::vector<int> &values, int value, int defaultValue )
483{
484 auto start = values.begin(), finish = values.end(),
485 iter = std::find( start, finish, value );
486 return ( iter != finish ) ? value : defaultValue;
487}
488
489int ValidateIndex( const std::vector<int> &values, int value, int defaultIndex )
490{
491 auto start = values.begin(), finish = values.end(),
492 iter = std::find( start, finish, value );
493 return ( iter != finish ) ? static_cast<int>( iter - start ) : defaultIndex;
494}
495
496}
497
500void ExportMP3Options::OnSET(wxCommandEvent& WXUNUSED(event))
501{
503
504 mRate->SetSelection(ValidateValue(setRateNames.size(), mSetRate, 2));
505 mRate->Refresh();
506 //mMode->Enable(true);
507}
508
511void ExportMP3Options::OnVBR(wxCommandEvent& WXUNUSED(event))
512{
514
515 mRate->SetSelection(ValidateValue(varRateNames.size(), mVbrRate, 2));
516 mRate->Refresh();
517 //mMode->Enable(true);
518}
519
522void ExportMP3Options::OnABR(wxCommandEvent& WXUNUSED(event))
523{
525
526 mRate->SetSelection(ValidateIndex(fixRateValues, mAbrRate, 10));
527 mRate->Refresh();
528 //mMode->Enable(false);
529}
530
533void ExportMP3Options::OnCBR(wxCommandEvent& WXUNUSED(event))
534{
536
537 mRate->SetSelection(ValidateIndex(fixRateValues, mCbrRate, 10));
538 mRate->Refresh();
539 //mMode->Enable(false);
540}
541
542void ExportMP3Options::OnQuality(wxCommandEvent& WXUNUSED(event))
543{
544 int sel = mRate->GetSelection();
545
546 if (mSET->GetValue()) {
547 mSetRate = sel;
548 }
549 else if (mVBR->GetValue()) {
550 mVbrRate = sel;
551 }
552 else if (mABR->GetValue()) {
553 mAbrRate = fixRateValues[ sel ];
554 }
555 else {
556 mCbrRate = fixRateValues[ sel ];
557 }
558}
559
560void ExportMP3Options::OnMono(wxCommandEvent& /*evt*/)
561{
562 bool mono = false;
563 mono = mMono->GetValue();
564 mJoint->Enable(!mono);
565 mStereo->Enable(!mono);
566
567 gPrefs->Write(wxT("/FileFormats/MP3ForceMono"), mono);
568 gPrefs->Flush();
569}
570
572{
573 mRate->Clear();
574 for (const auto &name : names)
575 mRate->Append( name.Translation() );
576}
577
578//----------------------------------------------------------------------------
579// FindDialog
580//----------------------------------------------------------------------------
581
582#define ID_BROWSE 5000
583#define ID_DLOAD 5001
584
585class FindDialog final : public wxDialogWrapper
586{
587public:
588
589#ifndef DISABLE_DYNAMIC_LOADING_LAME
590
591 FindDialog(wxWindow *parent, wxString path, wxString name,
593 : wxDialogWrapper(parent, wxID_ANY,
594 /* i18n-hint: LAME is the name of an MP3 converter and should not be translated*/
595 XO("Locate LAME"))
596 {
597 SetName();
598 ShuttleGui S(this, eIsCreating);
599
600 mPath = path;
601 mName = name;
602 mTypes = std::move( types );
603
604 mLibPath.Assign(mPath, mName);
605
607 }
608
610 {
611 S.SetBorder(10);
612 S.StartVerticalLay(true);
613 {
614 S.AddTitle(
615 XO("Audacity needs the file %s to create MP3s.")
616 .Format( mName ) );
617
618 S.SetBorder(3);
619 S.StartHorizontalLay(wxALIGN_LEFT, true);
620 {
621 S.AddTitle( XO("Location of %s:").Format( mName ) );
622 }
623 S.EndHorizontalLay();
624
625 S.StartMultiColumn(2, wxEXPAND);
626 S.SetStretchyCol(0);
627 {
628 if (mLibPath.GetFullPath().empty()) {
629 mPathText = S.AddTextBox( {},
630 /* i18n-hint: There is a button to the right of the arrow.*/
631 wxString::Format(_("To find %s, click here -->"), mName), 0);
632 }
633 else {
634 mPathText = S.AddTextBox( {}, mLibPath.GetFullPath(), 0);
635 }
636 S.Id(ID_BROWSE).AddButton(XXO("Browse..."), wxALIGN_RIGHT);
637 S.AddVariableText(
638 /* i18n-hint: There is a button to the right of the arrow.*/
639 XO("To get a free copy of LAME, click here -->"), true);
640 /* i18n-hint: (verb)*/
641 S.Id(ID_DLOAD).AddButton(XXO("Download"), wxALIGN_RIGHT);
642 }
643 S.EndMultiColumn();
644
645 S.AddStandardButtons();
646 }
647 S.EndVerticalLay();
648
649 Layout();
650 Fit();
651 SetMinSize(GetSize());
652 Center();
653
654 return;
655 }
656
657 void OnBrowse(wxCommandEvent & WXUNUSED(event))
658 {
659 /* i18n-hint: It's asking for the location of a file, for
660 * example, "Where is lame_enc.dll?" - you could translate
661 * "Where would I find the file %s" instead if you want. */
662 auto question = XO("Where is %s?").Format( mName );
663
664 wxString path = SelectFile(FileNames::Operation::_None,
665 question,
666 mLibPath.GetPath(),
667 mLibPath.GetName(),
668 wxT(""),
669 mTypes,
670 wxFD_OPEN | wxRESIZE_BORDER,
671 this);
672 if (!path.empty()) {
673 mLibPath = path;
674 mPathText->SetValue(path);
675 }
676 }
677
678 void OnDownload(wxCommandEvent & WXUNUSED(event))
679 {
680 HelpSystem::ShowHelp(this, L"FAQ:Installing_the_LAME_MP3_Encoder");
681 }
682
683 wxString GetLibPath()
684 {
685 return mLibPath.GetFullPath();
686 }
687
688#endif // DISABLE_DYNAMIC_LOADING_LAME
689
690private:
691
692#ifndef DISABLE_DYNAMIC_LOADING_LAME
693 wxFileName mLibPath;
694
695 wxString mPath;
696 wxString mName;
698#endif // DISABLE_DYNAMIC_LOADING_LAME
699
700 wxTextCtrl *mPathText;
701
702 DECLARE_EVENT_TABLE()
703};
704
705#ifndef DISABLE_DYNAMIC_LOADING_LAME
706BEGIN_EVENT_TABLE(FindDialog, wxDialogWrapper)
710#endif // DISABLE_DYNAMIC_LOADING_LAME
711
712//----------------------------------------------------------------------------
713// MP3Exporter
714//----------------------------------------------------------------------------
715
716#ifndef DISABLE_DYNAMIC_LOADING_LAME
717
720typedef const char* get_lame_version_t(void);
721
723 lame_t gfp,
724 const float pcm_l[],
725 const float pcm_r[],
726 const int nsamples,
727 unsigned char * mp3buf,
728 const int mp3buf_size);
729
731 lame_t gfp,
732 const float pcm[],
733 const int nsamples,
734 unsigned char * mp3buf,
735 const int mp3buf_size);
736
739 unsigned char* mp3buf,
740 int size );
741
743
749typedef int lame_set_VBR_t(lame_global_flags *, vbr_mode);
752typedef int lame_set_mode_t(lame_global_flags *, MPEG_mode);
757typedef size_t lame_get_lametag_frame_t(const lame_global_flags *, unsigned char* buffer, size_t size);
759
760#endif // DISABLE_DYNAMIC_LOADING_LAME
761
762#if defined(__WXMSW__)
763// An alternative solution to give Windows an additional chance of writing the tag before
764// falling bato to lame_mp3_tag_fid(). The latter can have DLL sharing issues when mixing
765// Debug/Release builds of Audacity and the lame DLL.
766typedef unsigned long beWriteInfoTag_t(lame_global_flags *, char *);
767
768// We use this to determine if the user has selected an older, Blade API only, lame_enc.dll
769// so we can be more specific about why their library isn't acceptable.
770typedef struct {
771
772 // BladeEnc DLL Version number
773
776
777 // BladeEnc Engine Version Number
778
781
782 // DLL Release date
783
784 BYTE byDay;
786 WORD wYear;
787
788 // BladeEnc Homepage URL
789
790 CHAR zHomepage[129];
791
795
796 BYTE btReserved[125];
797} be_version;
798typedef void beVersion_t(be_version *);
799#endif
800
802{
803public:
805 {
808 Yes
809 };
810
811 MP3Exporter();
812 ~MP3Exporter();
813
814#ifndef DISABLE_DYNAMIC_LOADING_LAME
815 bool FindLibrary(wxWindow *parent);
816 bool LoadLibrary(wxWindow *parent, AskUser askuser);
817 bool ValidLibraryLoaded();
818#endif // DISABLE_DYNAMIC_LOADING_LAME
819
820 /* These global settings keep state over the life of the object */
821 void SetMode(int mode);
822 void SetBitrate(int rate);
823 void SetQuality(int q/*, int r*/);
824 void SetChannel(int mode);
825
826 /* Virtual methods that must be supplied by library interfaces */
827
828 /* initialize the library interface */
829 bool InitLibrary(wxString libpath);
830 bool InitLibraryInternal();
831 bool InitLibraryExternal(wxString libpath);
832 void FreeLibrary();
833
834 /* get library info */
835 wxString GetLibraryVersion();
836 wxString GetLibraryName();
837 wxString GetLibraryPath();
839
840 /* returns the number of samples PER CHANNEL to send for each call to EncodeBuffer */
841 int InitializeStream(unsigned channels, int sampleRate);
842
843 /* In bytes. must be called AFTER InitializeStream */
844 int GetOutBufferSize();
845
846 /* returns the number of bytes written. input is interleaved if stereo*/
847 int EncodeBuffer(float inbuffer[], unsigned char outbuffer[]);
848 int EncodeRemainder(float inbuffer[], int nSamples,
849 unsigned char outbuffer[]);
850
851 int EncodeBufferMono(float inbuffer[], unsigned char outbuffer[]);
852 int EncodeRemainderMono(float inbuffer[], int nSamples,
853 unsigned char outbuffer[]);
854
855 int FinishStream(unsigned char outbuffer[]);
856 void CancelEncoding();
857
858 bool PutInfoTag(wxFFile & f, wxFileOffset off);
859
860private:
862
863#ifndef DISABLE_DYNAMIC_LOADING_LAME
864 wxString mLibPath;
865 wxDynamicLibrary lame_lib;
867#endif // DISABLE_DYNAMIC_LOADING_LAME
868
869#if defined(__WXMSW__)
871#endif
872
874 int mMode;
877 //int mRoutine;
879
880#ifndef DISABLE_DYNAMIC_LOADING_LAME
881 /* function pointers to the symbols we get from the library */
889
905#if defined(__WXMSW__)
908#endif
909#endif // DISABLE_DYNAMIC_LOADING_LAME
910
912
913 static const int mSamplesPerChunk = 220500;
914 // See lame.h/lame_encode_buffer() for further explanation
915 // As coded here, this should be the worst case.
916 static const int mOutBufferSize =
917 mSamplesPerChunk * (320 / 8) / 8 + 4 * 1152 * (320 / 8) / 8 + 512;
918
919 // See MAXFRAMESIZE in libmp3lame/VbrTag.c for explanation of 2880.
920 unsigned char mInfoTagBuf[2880];
922};
923
925{
926// We could use #defines rather than this variable.
927// The idea of the variable is that if we wanted, we could allow
928// a dynamic override of the library, e.g. with a newer faster version,
929// or to fix CVEs in the underlying library.
930// for now though the 'variable' is a constant.
931#ifdef MP3_EXPORT_BUILT_IN
932 mLibIsExternal = false;
933#else
934 mLibIsExternal = true;
935#endif
936
937#ifndef DISABLE_DYNAMIC_LOADING_LAME
938 mLibraryLoaded = false;
939#endif // DISABLE_DYNAMIC_LOADING_LAME
940 mEncoding = false;
941 mGF = NULL;
942
943#ifndef DISABLE_DYNAMIC_LOADING_LAME
944 if (gPrefs) {
945 mLibPath = gPrefs->Read(wxT("/MP3/MP3LibPath"), wxT(""));
946 }
947#endif // DISABLE_DYNAMIC_LOADING_LAME
948
949 mBitrate = 128;
952 mMode = MODE_CBR;
953 //mRoutine = ROUTINE_FAST;
954}
955
957{
958 FreeLibrary();
959}
960
961#ifndef DISABLE_DYNAMIC_LOADING_LAME
962
963bool MP3Exporter::FindLibrary(wxWindow *parent)
964{
965 wxString path;
966 wxString name;
967
968 if (!mLibPath.empty()) {
969 wxFileName fn = mLibPath;
970 path = fn.GetPath();
971 name = fn.GetFullName();
972 }
973 else {
974 path = GetLibraryPath();
976 }
977
978 FindDialog fd(parent,
979 path,
980 name,
982
983 if (fd.ShowModal() == wxID_CANCEL) {
984 return false;
985 }
986
987 path = fd.GetLibPath();
988
989 if (!::wxFileExists(path)) {
990 return false;
991 }
992
993 mLibPath = path;
994
995 return (gPrefs->Write(wxT("/MP3/MP3LibPath"), mLibPath) && gPrefs->Flush());
996}
997
998bool MP3Exporter::LoadLibrary(wxWindow *parent, AskUser askuser)
999{
1000
1001 if (ValidLibraryLoaded()) {
1002 FreeLibrary();
1003 mLibraryLoaded = false;
1004 }
1005
1006#if defined(__WXMSW__)
1007 mBladeVersion = {};
1008#endif
1009
1010 if( !mLibIsExternal ){
1012 return mLibraryLoaded;
1013 }
1014
1015 // First try loading it from a previously located path
1016 if (!mLibPath.empty()) {
1017 wxLogMessage(wxT("Attempting to load LAME from previously defined path"));
1019 }
1020
1021 // If not successful, try loading using system search paths
1022 if (!ValidLibraryLoaded()) {
1023 wxLogMessage(wxT("Attempting to load LAME from system search paths"));
1026 }
1027
1028 // If not successful, try loading using compiled in path
1029 if (!ValidLibraryLoaded()) {
1030 wxLogMessage(wxT("Attempting to load LAME from builtin path"));
1031 wxFileName fn(GetLibraryPath(), GetLibraryName());
1032 mLibPath = fn.GetFullPath();
1034 }
1035
1036 // If not successful, must ask the user
1037 if (!ValidLibraryLoaded()) {
1038 wxLogMessage(wxT("(Maybe) ask user for library"));
1039 if (askuser == MP3Exporter::Maybe && FindLibrary(parent)) {
1041 }
1042 }
1043
1044 // Oh well, just give up
1045 if (!ValidLibraryLoaded()) {
1046#if defined(__WXMSW__)
1047 if (askuser && !mBladeVersion.empty()) {
1049 }
1050#endif
1051 wxLogMessage(wxT("Failed to locate LAME library"));
1052
1053 return false;
1054 }
1055
1056 wxLogMessage(wxT("LAME library successfully loaded"));
1057
1058 return true;
1059}
1060
1062{
1063 return mLibraryLoaded;
1064}
1065
1066#endif // DISABLE_DYNAMIC_LOADING_LAME
1067
1069{
1070 mMode = mode;
1071}
1072
1074{
1075 mBitrate = rate;
1076}
1077
1078void MP3Exporter::SetQuality(int q/*, int r*/)
1079{
1080 mQuality = q;
1081 //mRoutine = r;
1082}
1083
1085{
1086 mChannel = mode;
1087}
1088
1089bool MP3Exporter::InitLibrary(wxString libpath)
1090{
1092}
1093
1095{
1096 wxLogMessage(wxT("Using internal LAME"));
1097
1098// The global ::lame_something symbols only exist if LAME is built in.
1099// So we don't reference them unless they are.
1100#ifdef MP3_EXPORT_BUILT_IN
1101
1109
1123
1124 // These are optional
1125 //lame_get_lametag_frame = ::lame_get_lametag_frame;
1128
1129#if defined(__WXMSW__)
1130 //beWriteInfoTag = ::beWriteInfoTag;
1131 //beVersion = ::beVersion;
1132 beWriteInfoTag = NULL;
1133 beVersion = NULL;
1134#endif
1135
1136 mGF = lame_init();
1137 if (mGF == NULL) {
1138 return false;
1139 }
1140#endif
1141
1142 return true;
1143}
1144
1145
1147{
1148 wxLogMessage(wxT("Loading LAME from %s"), libpath);
1149
1150#ifndef DISABLE_DYNAMIC_LOADING_LAME
1151 if (!lame_lib.Load(libpath, wxDL_LAZY)) {
1152 wxLogMessage(wxT("load failed"));
1153 return false;
1154 }
1155
1156 wxLogMessage(wxT("Actual LAME path %s"),
1157 FileNames::PathFromAddr(lame_lib.GetSymbol(wxT("lame_init"))));
1158
1160 lame_lib.GetSymbol(wxT("lame_init"));
1162 lame_lib.GetSymbol(wxT("get_lame_version"));
1164 lame_lib.GetSymbol(wxT("lame_init_params"));
1166 lame_lib.GetSymbol(wxT("lame_encode_buffer_ieee_float"));
1168 lame_lib.GetSymbol(wxT("lame_encode_buffer_interleaved_ieee_float"));
1170 lame_lib.GetSymbol(wxT("lame_encode_flush"));
1172 lame_lib.GetSymbol(wxT("lame_close"));
1173
1175 lame_lib.GetSymbol(wxT("lame_set_in_samplerate"));
1177 lame_lib.GetSymbol(wxT("lame_set_out_samplerate"));
1179 lame_lib.GetSymbol(wxT("lame_set_num_channels"));
1181 lame_lib.GetSymbol(wxT("lame_set_quality"));
1183 lame_lib.GetSymbol(wxT("lame_set_brate"));
1185 lame_lib.GetSymbol(wxT("lame_set_VBR"));
1187 lame_lib.GetSymbol(wxT("lame_set_VBR_q"));
1189 lame_lib.GetSymbol(wxT("lame_set_VBR_min_bitrate_kbps"));
1191 lame_lib.GetSymbol(wxT("lame_set_mode"));
1193 lame_lib.GetSymbol(wxT("lame_set_preset"));
1195 lame_lib.GetSymbol(wxT("lame_set_error_protection"));
1197 lame_lib.GetSymbol(wxT("lame_set_disable_reservoir"));
1199 lame_lib.GetSymbol(wxT("lame_set_bWriteVbrTag"));
1200
1201 // These are optional
1203 lame_lib.GetSymbol(wxT("lame_get_lametag_frame"));
1205 lame_lib.GetSymbol(wxT("lame_mp3_tags_fid"));
1206#if defined(__WXMSW__)
1208 lame_lib.GetSymbol(wxT("beWriteInfoTag"));
1210 lame_lib.GetSymbol(wxT("beVersion"));
1211#endif
1212
1213 if (!lame_init ||
1219 !lame_close ||
1224 !lame_set_brate ||
1225 !lame_set_VBR ||
1226 !lame_set_VBR_q ||
1227 !lame_set_mode ||
1228 !lame_set_preset ||
1232 {
1233 wxLogMessage(wxT("Failed to find a required symbol in the LAME library."));
1234#if defined(__WXMSW__)
1235 if (beVersion) {
1236 be_version v;
1237 beVersion(&v);
1238
1239 mBladeVersion = XO(
1240"You are linking to lame_enc.dll v%d.%d. This version is not compatible with Audacity %d.%d.%d.\nPlease download the latest version of 'LAME for Audacity'.")
1241 .Format(
1244 AUDACITY_VERSION,
1245 AUDACITY_RELEASE,
1246 AUDACITY_REVISION);
1247 }
1248#endif
1249
1250 lame_lib.Unload();
1251 return false;
1252 }
1253#endif // DISABLE_DYNAMIC_LOADING_LAME
1254
1255 mGF = lame_init();
1256 if (mGF == NULL) {
1257 return false;
1258 }
1259
1260 return true;
1261}
1262
1264{
1265 if (mGF) {
1266 lame_close(mGF);
1267 mGF = NULL;
1268 }
1269
1270#ifndef DISABLE_DYNAMIC_LOADING_LAME
1271 lame_lib.Unload();
1272#endif // DISABLE_DYNAMIC_LOADING_LAME
1273
1274 return;
1275}
1276
1278{
1279#ifndef DISABLE_DYNAMIC_LOADING_LAME
1280 if (!mLibraryLoaded) {
1281 return wxT("");
1282 }
1283#endif // DISABLE_DYNAMIC_LOADING_LAME
1284
1285 return wxString::Format(wxT("LAME %hs"), get_lame_version());
1286}
1287
1288int MP3Exporter::InitializeStream(unsigned channels, int sampleRate)
1289{
1290#ifndef DISABLE_DYNAMIC_LOADING_LAME
1291 if (!mLibraryLoaded) {
1292 return -1;
1293 }
1294#endif // DISABLE_DYNAMIC_LOADING_LAME
1295
1296 if (channels > 2) {
1297 return -1;
1298 }
1299
1301 lame_set_num_channels(mGF, channels);
1302 lame_set_in_samplerate(mGF, sampleRate);
1303 lame_set_out_samplerate(mGF, sampleRate);
1305 // Add the VbrTag for all types. For ABR/VBR, a Xing tag will be created.
1306 // For CBR, it will be a Lame Info tag.
1308
1309 // Set the VBR quality or ABR/CBR bitrate
1310 switch (mMode) {
1311 case MODE_SET:
1312 {
1313 int preset;
1314
1315 if (mQuality == PRESET_INSANE) {
1316 preset = INSANE;
1317 }
1318 //else if (mRoutine == ROUTINE_FAST) {
1319 else if (mQuality == PRESET_EXTREME) {
1320 preset = EXTREME_FAST;
1321 }
1322 else if (mQuality == PRESET_STANDARD) {
1323 preset = STANDARD_FAST;
1324 }
1325 else {
1326 preset = 1007; // Not defined until 3.96
1327 }
1328 //}
1329 /*
1330 else {
1331 if (mQuality == PRESET_EXTREME) {
1332 preset = EXTREME;
1333 }
1334 else if (mQuality == PRESET_STANDARD) {
1335 preset = STANDARD;
1336 }
1337 else {
1338 preset = 1006; // Not defined until 3.96
1339 }
1340 }
1341 */
1343 }
1344 break;
1345
1346 case MODE_VBR:
1347 lame_set_VBR(mGF, vbr_mtrh );
1349 break;
1350
1351 case MODE_ABR:
1353 break;
1354
1355 default:
1356 lame_set_VBR(mGF, vbr_off);
1358 break;
1359 }
1360
1361 // Set the channel mode
1362 MPEG_mode mode;
1363
1364 if (channels == 1 || mChannel == CHANNEL_MONO) {
1365 mode = MONO;
1366 }
1367 else if (mChannel == CHANNEL_JOINT) {
1368 mode = JOINT_STEREO;
1369 }
1370 else {
1371 mode = STEREO;
1372 }
1373 lame_set_mode(mGF, mode);
1374
1375 int rc = lame_init_params(mGF);
1376 if (rc < 0) {
1377 return rc;
1378 }
1379
1380#if 0
1381 dump_config(mGF);
1382#endif
1383
1384 mInfoTagLen = 0;
1385 mEncoding = true;
1386
1387 return mSamplesPerChunk;
1388}
1389
1391{
1392 if (!mEncoding)
1393 return -1;
1394
1395 return mOutBufferSize;
1396}
1397
1398int MP3Exporter::EncodeBuffer(float inbuffer[], unsigned char outbuffer[])
1399{
1400 if (!mEncoding) {
1401 return -1;
1402 }
1403
1405 outbuffer, mOutBufferSize);
1406}
1407
1408int MP3Exporter::EncodeRemainder(float inbuffer[], int nSamples,
1409 unsigned char outbuffer[])
1410{
1411 if (!mEncoding) {
1412 return -1;
1413 }
1414
1415 return lame_encode_buffer_interleaved_ieee_float(mGF, inbuffer, nSamples, outbuffer,
1417}
1418
1419int MP3Exporter::EncodeBufferMono(float inbuffer[], unsigned char outbuffer[])
1420{
1421 if (!mEncoding) {
1422 return -1;
1423 }
1424
1425 return lame_encode_buffer_ieee_float(mGF, inbuffer,inbuffer, mSamplesPerChunk,
1426 outbuffer, mOutBufferSize);
1427}
1428
1429int MP3Exporter::EncodeRemainderMono(float inbuffer[], int nSamples,
1430 unsigned char outbuffer[])
1431{
1432 if (!mEncoding) {
1433 return -1;
1434 }
1435
1436 return lame_encode_buffer_ieee_float(mGF, inbuffer, inbuffer, nSamples, outbuffer,
1438}
1439
1440int MP3Exporter::FinishStream(unsigned char outbuffer[])
1441{
1442 if (!mEncoding) {
1443 return -1;
1444 }
1445
1446 mEncoding = false;
1447
1448 int result = lame_encode_flush(mGF, outbuffer, mOutBufferSize);
1449
1450#if defined(DISABLE_DYNAMIC_LOADING_LAME)
1452#else
1455 }
1456#endif
1457
1458 return result;
1459}
1460
1462{
1463 mEncoding = false;
1464}
1465
1466bool MP3Exporter::PutInfoTag(wxFFile & f, wxFileOffset off)
1467{
1468 if (mGF) {
1469 if (mInfoTagLen > 0) {
1470 // FIXME: TRAP_ERR Seek and writ ein MP3 exporter could fail.
1471 if ( !f.Seek(off, wxFromStart))
1472 return false;
1473 if (mInfoTagLen > f.Write(mInfoTagBuf, mInfoTagLen))
1474 return false;
1475 }
1476#if defined(__WXMSW__)
1477 else if (beWriteInfoTag) {
1478 if ( !f.Flush() )
1479 return false;
1480 // PRL: What is the correct error check on the return value?
1481 beWriteInfoTag(mGF, OSOUTPUT(f.GetName()));
1482 mGF = NULL;
1483 }
1484#endif
1485 else if (lame_mp3_tags_fid != NULL) {
1486 lame_mp3_tags_fid(mGF, f.fp());
1487 }
1488 }
1489
1490 if ( !f.SeekEnd() )
1491 return false;
1492
1493 return true;
1494}
1495
1496#if defined(__WXMSW__)
1497/* values for Windows */
1498
1500{
1501 wxRegKey reg(wxT("HKEY_LOCAL_MACHINE\\Software\\Lame for Audacity"));
1502 wxString path;
1503
1504 if (reg.Exists()) {
1505 wxLogMessage(wxT("LAME registry key exists."));
1506 reg.QueryValue(wxT("InstallPath"), path);
1507 }
1508 else {
1509 wxLogMessage(wxT("LAME registry key does not exist."));
1510 }
1511
1512 wxLogMessage(wxT("Library path is: ") + path);
1513
1514 return path;
1515}
1516
1518{
1519 return wxT("lame_enc.dll");
1520}
1521
1523{
1524 return {
1525 { XO("Only lame_enc.dll"), { wxT("lame_enc.dll") } },
1528 };
1529}
1530
1531#elif defined(__WXMAC__)
1532/* values for Mac OS X */
1533
1535{
1536 wxString path;
1537
1538 path = wxT("/Library/Application Support/audacity/libs");
1539 if (wxFileExists(path + wxT("/") + GetLibraryName()))
1540 {
1541 return path;
1542 }
1543
1544 path = wxT("/usr/local/lib/audacity");
1545 if (wxFileExists(path + wxT("/") + GetLibraryName()))
1546 {
1547 return path;
1548 }
1549
1550 return wxT("/Library/Application Support/audacity/libs");
1551}
1552
1554{
1555 if (sizeof(void*) == 8)
1556 return wxT("libmp3lame64bit.dylib");
1557 return wxT("libmp3lame.dylib");
1558}
1559
1561{
1562 return {
1563 (sizeof(void*) == 8)
1565 XO("Only libmp3lame64bit.dylib"), { wxT("libmp3lame64bit.dylib") }
1566 }
1568 XO("Only libmp3lame.dylib"), { wxT("libmp3lame.dylib") }
1569 }
1570 ,
1573 };
1574}
1575
1576#else
1577/* Values for Linux / Unix systems */
1578
1580{
1581 return wxT(LIBDIR);
1582}
1583
1585{
1586 return wxT("libmp3lame.so.0");
1587}
1588
1590{
1591 return {
1592 { XO("Only libmp3lame.so.0"), { wxT("libmp3lame.so.0") } },
1593 { XO("Primary shared object files"), { wxT("so") }, true },
1594 { XO("Extended libraries"), { wxT("so*") }, true },
1596 };
1597}
1598#endif
1599
1600#if 0
1601// Debug routine from BladeMP3EncDLL.c in the libmp3lame distro
1602static void dump_config( lame_global_flags* gfp )
1603{
1604 wxPrintf(wxT("\n\nLame_enc configuration options:\n"));
1605 wxPrintf(wxT("==========================================================\n"));
1606
1607 wxPrintf(wxT("version =%d\n"),lame_get_version( gfp ) );
1608 wxPrintf(wxT("Layer =3\n"));
1609 wxPrintf(wxT("mode ="));
1610 switch ( lame_get_mode( gfp ) )
1611 {
1612 case STEREO: wxPrintf(wxT( "Stereo\n" )); break;
1613 case JOINT_STEREO: wxPrintf(wxT( "Joint-Stereo\n" )); break;
1614 case DUAL_CHANNEL: wxPrintf(wxT( "Forced Stereo\n" )); break;
1615 case MONO: wxPrintf(wxT( "Mono\n" )); break;
1616 case NOT_SET: /* FALLTHROUGH */
1617 default: wxPrintf(wxT( "Error (unknown)\n" )); break;
1618 }
1619
1620 wxPrintf(wxT("Input sample rate =%.1f kHz\n"), lame_get_in_samplerate( gfp ) /1000.0 );
1621 wxPrintf(wxT("Output sample rate =%.1f kHz\n"), lame_get_out_samplerate( gfp ) /1000.0 );
1622
1623 wxPrintf(wxT("bitrate =%d kbps\n"), lame_get_brate( gfp ) );
1624 wxPrintf(wxT("Quality Setting =%d\n"), lame_get_quality( gfp ) );
1625
1626 wxPrintf(wxT("Low pass frequency =%d\n"), lame_get_lowpassfreq( gfp ) );
1627 wxPrintf(wxT("Low pass width =%d\n"), lame_get_lowpasswidth( gfp ) );
1628
1629 wxPrintf(wxT("High pass frequency =%d\n"), lame_get_highpassfreq( gfp ) );
1630 wxPrintf(wxT("High pass width =%d\n"), lame_get_highpasswidth( gfp ) );
1631
1632 wxPrintf(wxT("No short blocks =%d\n"), lame_get_no_short_blocks( gfp ) );
1633 wxPrintf(wxT("Force short blocks =%d\n"), lame_get_force_short_blocks( gfp ) );
1634
1635 wxPrintf(wxT("de-emphasis =%d\n"), lame_get_emphasis( gfp ) );
1636 wxPrintf(wxT("private flag =%d\n"), lame_get_extension( gfp ) );
1637
1638 wxPrintf(wxT("copyright flag =%d\n"), lame_get_copyright( gfp ) );
1639 wxPrintf(wxT("original flag =%d\n"), lame_get_original( gfp ) );
1640 wxPrintf(wxT("CRC =%s\n"), lame_get_error_protection( gfp ) ? wxT("on") : wxT("off") );
1641 wxPrintf(wxT("Fast mode =%s\n"), ( lame_get_quality( gfp ) )? wxT("enabled") : wxT("disabled") );
1642 wxPrintf(wxT("Force mid/side stereo =%s\n"), ( lame_get_force_ms( gfp ) )?wxT("enabled"):wxT("disabled") );
1643 wxPrintf(wxT("Padding Type =%d\n"), (int) lame_get_padding_type( gfp ) );
1644 wxPrintf(wxT("Disable Reservoir =%d\n"), lame_get_disable_reservoir( gfp ) );
1645 wxPrintf(wxT("Allow diff-short =%d\n"), lame_get_allow_diff_short( gfp ) );
1646 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
1647 wxPrintf(wxT("Strict ISO Encoding =%s\n"), ( lame_get_strict_ISO( gfp ) ) ?wxT("Yes"):wxT("No"));
1648 wxPrintf(wxT("Scale =%5.2f\n"), lame_get_scale( gfp ) );
1649
1650 wxPrintf(wxT("VBR =%s, VBR_q =%d, VBR method ="),
1651 ( lame_get_VBR( gfp ) !=vbr_off ) ? wxT("enabled"): wxT("disabled"),
1652 lame_get_VBR_q( gfp ) );
1653
1654 switch ( lame_get_VBR( gfp ) )
1655 {
1656 case vbr_off: wxPrintf(wxT( "vbr_off\n" )); break;
1657 case vbr_mt : wxPrintf(wxT( "vbr_mt \n" )); break;
1658 case vbr_rh : wxPrintf(wxT( "vbr_rh \n" )); break;
1659 case vbr_mtrh: wxPrintf(wxT( "vbr_mtrh \n" )); break;
1660 case vbr_abr:
1661 wxPrintf(wxT( "vbr_abr (average bitrate %d kbps)\n"), lame_get_VBR_mean_bitrate_kbps( gfp ) );
1662 break;
1663 default:
1664 wxPrintf(wxT("error, unknown VBR setting\n"));
1665 break;
1666 }
1667
1668 wxPrintf(wxT("Vbr Min bitrate =%d kbps\n"), lame_get_VBR_min_bitrate_kbps( gfp ) );
1669 wxPrintf(wxT("Vbr Max bitrate =%d kbps\n"), lame_get_VBR_max_bitrate_kbps( gfp ) );
1670
1671 wxPrintf(wxT("Write VBR Header =%s\n"), ( lame_get_bWriteVbrTag( gfp ) ) ?wxT("Yes"):wxT("No"));
1672 wxPrintf(wxT("VBR Hard min =%d\n"), lame_get_VBR_hard_min( gfp ) );
1673
1674 wxPrintf(wxT("ATH Only =%d\n"), lame_get_ATHonly( gfp ) );
1675 wxPrintf(wxT("ATH short =%d\n"), lame_get_ATHshort( gfp ) );
1676 wxPrintf(wxT("ATH no =%d\n"), lame_get_noATH( gfp ) );
1677 wxPrintf(wxT("ATH type =%d\n"), lame_get_ATHtype( gfp ) );
1678 wxPrintf(wxT("ATH lower =%f\n"), lame_get_ATHlower( gfp ) );
1679 wxPrintf(wxT("ATH aa =%d\n"), lame_get_athaa_type( gfp ) );
1680 wxPrintf(wxT("ATH aa loudapprox =%d\n"), lame_get_athaa_loudapprox( gfp ) );
1681 wxPrintf(wxT("ATH aa sensitivity =%f\n"), lame_get_athaa_sensitivity( gfp ) );
1682
1683 wxPrintf(wxT("Experimental nspsytune =%d\n"), lame_get_exp_nspsytune( gfp ) );
1684 wxPrintf(wxT("Experimental X =%d\n"), lame_get_experimentalX( gfp ) );
1685 wxPrintf(wxT("Experimental Y =%d\n"), lame_get_experimentalY( gfp ) );
1686 wxPrintf(wxT("Experimental Z =%d\n"), lame_get_experimentalZ( gfp ) );
1687}
1688#endif
1689
1690//----------------------------------------------------------------------------
1691// ExportMP3
1692//----------------------------------------------------------------------------
1693
1694class ExportMP3 final : public ExportPlugin
1695{
1696public:
1697
1698 ExportMP3();
1699 bool CheckFileName(wxFileName & filename, int format) override;
1700
1701 // Required
1702
1703 void OptionsCreate(ShuttleGui &S, int format) override;
1705 std::unique_ptr<ProgressDialog> &pDialog,
1706 unsigned channels,
1707 const wxFileNameWrapper &fName,
1708 bool selectedOnly,
1709 double t0,
1710 double t1,
1711 MixerSpec *mixerSpec = NULL,
1712 const Tags *metadata = NULL,
1713 int subformat = 0) override;
1714
1715private:
1716
1717 int AskResample(int bitrate, int rate, int lowrate, int highrate);
1718 unsigned long AddTags(AudacityProject *project, ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags);
1719#ifdef USE_LIBID3TAG
1720 void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
1721#endif
1722 int SetNumExportChannels() override;
1723};
1724
1726: ExportPlugin()
1727{
1728 AddFormat();
1729 SetFormat(wxT("MP3"),0);
1730 AddExtension(wxT("mp3"),0);
1731 SetMaxChannels(2,0);
1732 SetCanMetaData(true,0);
1733 SetDescription(XO("MP3 Files"),0);
1734}
1735
1736bool ExportMP3::CheckFileName(wxFileName & WXUNUSED(filename), int WXUNUSED(format))
1737{
1738#ifndef DISABLE_DYNAMIC_LOADING_LAME
1739 MP3Exporter exporter;
1740
1741 if (!exporter.LoadLibrary(wxTheApp->GetTopWindow(), MP3Exporter::Maybe)) {
1742 AudacityMessageBox( XO("Could not open MP3 encoding library!") );
1743 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1744 gPrefs->Flush();
1745
1746 return false;
1747 }
1748#endif // DISABLE_DYNAMIC_LOADING_LAME
1749
1750 return true;
1751}
1752
1754{
1755 bool mono;
1756 gPrefs->Read(wxT("/FileFormats/MP3ForceMono"), &mono, 0);
1757
1758 return (mono)? 1 : -1;
1759}
1760
1761
1763 std::unique_ptr<ProgressDialog> &pDialog,
1764 unsigned channels,
1765 const wxFileNameWrapper &fName,
1766 bool selectionOnly,
1767 double t0,
1768 double t1,
1769 MixerSpec *mixerSpec,
1770 const Tags *metadata,
1771 int WXUNUSED(subformat))
1772{
1773 int rate = lrint( ProjectRate::Get( *project ).GetRate());
1774#ifndef DISABLE_DYNAMIC_LOADING_LAME
1775 wxWindow *parent = ProjectWindow::Find( project );
1776#endif // DISABLE_DYNAMIC_LOADING_LAME
1777 const auto &tracks = TrackList::Get( *project );
1778 MP3Exporter exporter;
1779
1780#ifdef DISABLE_DYNAMIC_LOADING_LAME
1781 if (!exporter.InitLibrary(wxT(""))) {
1782 AudacityMessageBox( XO("Could not initialize MP3 encoding library!") );
1783 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1784 gPrefs->Flush();
1785
1787 }
1788#else
1789 if (!exporter.LoadLibrary(parent, MP3Exporter::Maybe)) {
1790 AudacityMessageBox( XO("Could not open MP3 encoding library!") );
1791 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1792 gPrefs->Flush();
1793
1795 }
1796
1797 if (!exporter.ValidLibraryLoaded()) {
1798 AudacityMessageBox( XO("Not a valid or supported MP3 encoding library!") );
1799 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1800 gPrefs->Flush();
1801
1803 }
1804#endif // DISABLE_DYNAMIC_LOADING_LAME
1805
1806 // Retrieve preferences
1807 int highrate = 48000;
1808 int lowrate = 8000;
1809 int bitrate = 0;
1810 int brate;
1811 //int vmode;
1812 bool forceMono;
1813
1814 gPrefs->Read(wxT("/FileFormats/MP3Bitrate"), &brate, 128);
1815 auto rmode = MP3RateModeSetting.ReadEnumWithDefault( MODE_CBR );
1816 //gPrefs->Read(wxT("/FileFormats/MP3VarMode"), &vmode, ROUTINE_FAST);
1817 auto cmode = MP3ChannelModeSetting.ReadEnumWithDefault( CHANNEL_STEREO );
1818 gPrefs->Read(wxT("/FileFormats/MP3ForceMono"), &forceMono, 0);
1819
1820 // Set the bitrate/quality and mode
1821 if (rmode == MODE_SET) {
1822 brate = ValidateValue(setRateNames.size(), brate, PRESET_STANDARD);
1823 //int r = ValidateValue( varModeNames.size(), vmode, ROUTINE_FAST );
1824 exporter.SetMode(MODE_SET);
1825 exporter.SetQuality(brate/*, r*/);
1826 }
1827 else if (rmode == MODE_VBR) {
1828 brate = ValidateValue( varRateNames.size(), brate, QUALITY_2 );
1829 //int r = ValidateValue( varModeNames.size(), vmode, ROUTINE_FAST );
1830 exporter.SetMode(MODE_VBR);
1831 exporter.SetQuality(brate/*, r*/);
1832 }
1833 else if (rmode == MODE_ABR) {
1834 brate = ValidateIndex( fixRateValues, brate, 6 /* 128 kbps */ );
1835 bitrate = fixRateValues[ brate ];
1836 exporter.SetMode(MODE_ABR);
1837 exporter.SetBitrate(bitrate);
1838 if (bitrate > 160) {
1839 lowrate = 32000;
1840 }
1841 else if (bitrate < 32 || bitrate == 144) {
1842 highrate = 24000;
1843 }
1844 }
1845 else {
1846 brate = ValidateIndex( fixRateValues, brate, 6 /* 128 kbps */ );
1847 bitrate = fixRateValues[ brate ];
1848 exporter.SetMode(MODE_CBR);
1849 exporter.SetBitrate(bitrate);
1850
1851 if (bitrate > 160) {
1852 lowrate = 32000;
1853 }
1854 else if (bitrate < 32 || bitrate == 144) {
1855 highrate = 24000;
1856 }
1857 }
1858
1859 // Verify sample rate
1860 if (!make_iterator_range( sampRates ).contains( rate ) ||
1861 (rate < lowrate) || (rate > highrate)) {
1862 // Force valid sample rate in macros.
1863 if (project->mBatchMode) {
1864 if (!make_iterator_range( sampRates ).contains( rate )) {
1865 auto const bestRateIt = std::lower_bound(sampRates.begin(),
1866 sampRates.end(), rate);
1867 rate = (bestRateIt == sampRates.end()) ? highrate : *bestRateIt;
1868 }
1869 if (rate < lowrate) {
1870 rate = lowrate;
1871 }
1872 else if (rate > highrate) {
1873 rate = highrate;
1874 }
1875 }
1876 // else validate or prompt
1877 else {
1878 if (!make_iterator_range( sampRates ).contains( rate ) ||
1879 (rate < lowrate) || (rate > highrate)) {
1880 rate = AskResample(bitrate, rate, lowrate, highrate);
1881 }
1882 if (rate == 0) {
1884
1885 }
1886 }
1887 }
1888
1889 // Set the channel mode
1890 if (forceMono) {
1891 exporter.SetChannel(CHANNEL_MONO);
1892 }
1893 else if (cmode == CHANNEL_JOINT) {
1894 exporter.SetChannel(CHANNEL_JOINT);
1895 }
1896 else {
1897 exporter.SetChannel(CHANNEL_STEREO);
1898 }
1899
1900 auto inSamples = exporter.InitializeStream(channels, rate);
1901 if (((int)inSamples) < 0) {
1902 AudacityMessageBox( XO("Unable to initialize MP3 stream") );
1904 }
1905
1906 // Put ID3 tags at beginning of file
1907 if (metadata == NULL)
1908 metadata = &Tags::Get( *project );
1909
1910 // Open file for writing
1911 wxFFile outFile(fName.GetFullPath(), wxT("w+b"));
1912 if (!outFile.IsOpened()) {
1913 AudacityMessageBox( XO("Unable to open target file for writing") );
1915 }
1916
1917 ArrayOf<char> id3buffer;
1918 bool endOfFile;
1919 unsigned long id3len = AddTags(project, id3buffer, &endOfFile, metadata);
1920 if (id3len && !endOfFile) {
1921 if (id3len > outFile.Write(id3buffer.get(), id3len)) {
1922 // TODO: more precise message
1923 ShowExportErrorDialog("MP3:1882");
1925 }
1926 }
1927
1928 wxFileOffset pos = outFile.Tell();
1929 auto updateResult = ProgressResult::Success;
1930 int bytes = 0;
1931
1932 size_t bufferSize = std::max(0, exporter.GetOutBufferSize());
1933 if (bufferSize <= 0) {
1934 // TODO: more precise message
1935 ShowExportErrorDialog("MP3:1849");
1937 }
1938
1939 ArrayOf<unsigned char> buffer{ bufferSize };
1940 wxASSERT(buffer);
1941
1942 {
1943 auto mixer = CreateMixer(tracks, selectionOnly,
1944 t0, t1,
1945 channels, inSamples, true,
1946 rate, floatSample, mixerSpec);
1947
1949 if (rmode == MODE_SET) {
1950 title = (selectionOnly ?
1951 XO("Exporting selected audio with %s preset") :
1952 XO("Exporting the audio with %s preset"))
1953 .Format( setRateNamesShort[brate] );
1954 }
1955 else if (rmode == MODE_VBR) {
1956 title = (selectionOnly ?
1957 XO("Exporting selected audio with VBR quality %s") :
1958 XO("Exporting the audio with VBR quality %s"))
1959 .Format( varRateNames[brate] );
1960 }
1961 else {
1962 title = (selectionOnly ?
1963 XO("Exporting selected audio at %d Kbps") :
1964 XO("Exporting the audio at %d Kbps"))
1965 .Format( bitrate );
1966 }
1967
1968 InitProgress( pDialog, fName, title );
1969 auto &progress = *pDialog;
1970
1971 while (updateResult == ProgressResult::Success) {
1972 auto blockLen = mixer->Process(inSamples);
1973
1974 if (blockLen == 0) {
1975 break;
1976 }
1977
1978 float *mixed = (float *)mixer->GetBuffer();
1979
1980 if ((int)blockLen < inSamples) {
1981 if (channels > 1) {
1982 bytes = exporter.EncodeRemainder(mixed, blockLen, buffer.get());
1983 }
1984 else {
1985 bytes = exporter.EncodeRemainderMono(mixed, blockLen, buffer.get());
1986 }
1987 }
1988 else {
1989 if (channels > 1) {
1990 bytes = exporter.EncodeBuffer(mixed, buffer.get());
1991 }
1992 else {
1993 bytes = exporter.EncodeBufferMono(mixed, buffer.get());
1994 }
1995 }
1996
1997 if (bytes < 0) {
1998 auto msg = XO("Error %ld returned from MP3 encoder")
1999 .Format( bytes );
2000 AudacityMessageBox( msg );
2001 updateResult = ProgressResult::Cancelled;
2002 break;
2003 }
2004
2005 if (bytes > (int)outFile.Write(buffer.get(), bytes)) {
2006 // TODO: more precise message
2008 updateResult = ProgressResult::Cancelled;
2009 break;
2010 }
2011
2012 updateResult = progress.Update(mixer->MixGetCurrentTime() - t0, t1 - t0);
2013 }
2014 }
2015
2016 if ( updateResult == ProgressResult::Success ||
2017 updateResult == ProgressResult::Stopped ) {
2018 bytes = exporter.FinishStream(buffer.get());
2019
2020 if (bytes < 0) {
2021 // TODO: more precise message
2022 ShowExportErrorDialog("MP3:1981");
2024 }
2025
2026 if (bytes > 0) {
2027 if (bytes > (int)outFile.Write(buffer.get(), bytes)) {
2028 // TODO: more precise message
2029 ShowExportErrorDialog("MP3:1988");
2031 }
2032 }
2033
2034 // Write ID3 tag if it was supposed to be at the end of the file
2035 if (id3len > 0 && endOfFile) {
2036 if (bytes > (int)outFile.Write(id3buffer.get(), id3len)) {
2037 // TODO: more precise message
2038 ShowExportErrorDialog("MP3:1997");
2040 }
2041 }
2042
2043 // Always write the info (Xing/Lame) tag. Until we stop supporting Lame
2044 // versions before 3.98, we must do this after the MP3 file has been
2045 // closed.
2046 //
2047 // Also, if beWriteInfoTag() is used, mGF will no longer be valid after
2048 // this call, so do not use it.
2049 if (!exporter.PutInfoTag(outFile, pos) ||
2050 !outFile.Flush() ||
2051 !outFile.Close()) {
2052 // TODO: more precise message
2053 ShowExportErrorDialog("MP3:2012");
2055 }
2056 }
2057
2058 return updateResult;
2059}
2060
2062{
2063 S.AddWindow( safenew ExportMP3Options{ S.GetParent(), format } );
2064}
2065
2066int ExportMP3::AskResample(int bitrate, int rate, int lowrate, int highrate)
2067{
2068 wxDialogWrapper d(nullptr, wxID_ANY, XO("Invalid sample rate"));
2069 d.SetName();
2070 wxChoice *choice;
2072
2073 int selected = -1;
2074
2075 S.StartVerticalLay();
2076 {
2077 S.SetBorder(10);
2078 S.StartStatic(XO("Resample"));
2079 {
2080 S.StartHorizontalLay(wxALIGN_CENTER, false);
2081 {
2082 S.AddTitle(
2083 ((bitrate == 0)
2084 ? XO(
2085"The project sample rate (%d) is not supported by the MP3\nfile format. ")
2086 .Format( rate )
2087 : XO(
2088"The project sample rate (%d) and bit rate (%d kbps) combination is not\nsupported by the MP3 file format. ")
2089 .Format( rate, bitrate ))
2090 + XO("You may resample to one of the rates below.")
2091 );
2092 }
2093 S.EndHorizontalLay();
2094
2095 S.StartHorizontalLay(wxALIGN_CENTER, false);
2096 {
2097 choice = S.AddChoice(XXO("Sample Rates"),
2098 [&]{
2099 TranslatableStrings choices;
2100 for (size_t ii = 0, nn = sampRates.size(); ii < nn; ++ii) {
2101 int label = sampRates[ii];
2102 if (label >= lowrate && label <= highrate) {
2103 choices.push_back( Verbatim( "%d" ).Format( label ) );
2104 if (label <= rate)
2105 selected = ii;
2106 }
2107 }
2108 return choices;
2109 }(),
2110 std::max( 0, selected )
2111 );
2112 }
2113 S.EndHorizontalLay();
2114 }
2115 S.EndStatic();
2116
2117 S.AddStandardButtons();
2118 }
2119 S.EndVerticalLay();
2120
2121 d.Layout();
2122 d.Fit();
2123 d.SetMinSize(d.GetSize());
2124 d.Center();
2125
2126 if (d.ShowModal() == wxID_CANCEL) {
2127 return 0;
2128 }
2129
2130 return wxAtoi(choice->GetStringSelection());
2131}
2132
2133#ifdef USE_LIBID3TAG
2134struct id3_tag_deleter {
2135 void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
2136};
2137using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
2138#endif
2139
2140// returns buffer len; caller frees
2141unsigned long ExportMP3::AddTags(AudacityProject *WXUNUSED(project), ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags)
2142{
2143#ifdef USE_LIBID3TAG
2144 id3_tag_holder tp { id3_tag_new() };
2145
2146 for (const auto &pair : tags->GetRange()) {
2147 const auto &n = pair.first;
2148 const auto &v = pair.second;
2149 const char *name = "TXXX";
2150
2151 if (n.CmpNoCase(TAG_TITLE) == 0) {
2152 name = ID3_FRAME_TITLE;
2153 }
2154 else if (n.CmpNoCase(TAG_ARTIST) == 0) {
2155 name = ID3_FRAME_ARTIST;
2156 }
2157 else if (n.CmpNoCase(TAG_ALBUM) == 0) {
2158 name = ID3_FRAME_ALBUM;
2159 }
2160 else if (n.CmpNoCase(TAG_YEAR) == 0) {
2161 // LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR),
2162 // so we add old one as well.
2163 AddFrame(tp.get(), n, v, "TYER");
2164 name = ID3_FRAME_YEAR;
2165 }
2166 else if (n.CmpNoCase(TAG_GENRE) == 0) {
2167 name = ID3_FRAME_GENRE;
2168 }
2169 else if (n.CmpNoCase(TAG_COMMENTS) == 0) {
2170 name = ID3_FRAME_COMMENT;
2171 }
2172 else if (n.CmpNoCase(TAG_TRACK) == 0) {
2173 name = ID3_FRAME_TRACK;
2174 }
2175
2176 AddFrame(tp.get(), n, v, name);
2177 }
2178
2179 tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
2180
2181 // If this version of libid3tag supports it, use v2.3 ID3
2182 // tags instead of the newer, but less well supported, v2.4
2183 // that libid3tag uses by default.
2184 #ifdef ID3_TAG_HAS_TAG_OPTION_ID3V2_3
2185 tp->options |= ID3_TAG_OPTION_ID3V2_3;
2186 #endif
2187
2188 *endOfFile = false;
2189
2190 unsigned long len;
2191
2192 len = id3_tag_render(tp.get(), 0);
2193 buffer.reinit(len);
2194 len = id3_tag_render(tp.get(), (id3_byte_t *)buffer.get());
2195
2196 return len;
2197#else //ifdef USE_LIBID3TAG
2198 return 0;
2199#endif
2200}
2201
2202#ifdef USE_LIBID3TAG
2203void ExportMP3::AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name)
2204{
2205 struct id3_frame *frame = id3_frame_new(name);
2206
2207 if (!n.IsAscii() || !v.IsAscii()) {
2208 id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_UTF_16);
2209 }
2210 else {
2211 id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
2212 }
2213
2215 id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
2216
2217 if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
2218 // A hack to get around iTunes not recognizing the comment. The
2219 // language defaults to XXX and, since it's not a valid language,
2220 // iTunes just ignores the tag. So, either set it to a valid language
2221 // (which one???) or just clear it. Unfortunately, there's no supported
2222 // way of clearing the field, so do it directly.
2223 struct id3_frame *frame2 = id3_frame_new(name);
2224 id3_field_setfullstring(id3_frame_field(frame2, 3), ucs4.get());
2225 id3_field *f2 = id3_frame_field(frame2, 1);
2226 memset(f2->immediate.value, 0, sizeof(f2->immediate.value));
2227 id3_tag_attachframe(tp, frame2);
2228 // Now install a second frame with the standard default language = "XXX"
2229 id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
2230 }
2231 else if (strcmp(name, "TXXX") == 0) {
2232 id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
2233
2234 ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
2235
2236 id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
2237 }
2238 else {
2239 auto addr = ucs4.get();
2240 id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
2241 }
2242
2243 id3_tag_attachframe(tp, frame);
2244}
2245#endif
2246
2248 []{ return std::make_unique< ExportMP3 >(); }
2249};
2250
2251//----------------------------------------------------------------------------
2252// Return library version
2253//----------------------------------------------------------------------------
2254
2255TranslatableString GetMP3Version(wxWindow *parent, bool prompt)
2256{
2257 MP3Exporter exporter;
2258 auto versionString = XO("MP3 export library not found");
2259
2260#ifndef DISABLE_DYNAMIC_LOADING_LAME
2261 if (prompt) {
2262 exporter.FindLibrary(parent);
2263 }
2264
2265 if (exporter.LoadLibrary(parent, prompt ? MP3Exporter::Yes : MP3Exporter::No)) {
2266#endif // DISABLE_DYNAMIC_LOADING_LAME
2267 versionString = Verbatim( exporter.GetLibraryVersion() );
2268#ifdef MP3_EXPORT_BUILT_IN
2269 versionString.Join( XO("(Built-in)"), " " );
2270#endif
2271
2272#ifndef DISABLE_DYNAMIC_LOADING_LAME
2273 }
2274#endif // DISABLE_DYNAMIC_LOADING_LAME
2275
2276 return versionString;
2277}
2278
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
END_EVENT_TABLE()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
Definition: Distortion.cpp:82
const wxChar * values
void ShowExportErrorDialog(wxString ErrorCode, TranslatableString message, const TranslatableString &caption, bool allowReporting)
Definition: Export.cpp:1520
void ShowDiskFullExportErrorDialog(const wxFileNameWrapper &fileName)
Definition: Export.cpp:1533
int lame_set_VBR_t(lame_global_flags *, vbr_mode)
Definition: ExportMP3.cpp:749
#define ID_VBR
Definition: ExportMP3.cpp:221
int lame_set_bWriteVbrTag_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:756
static const std::vector< int > sampRates
Definition: ExportMP3.cpp:208
int CDECL lame_encode_buffer_interleaved_ieee_float_t(lame_t gfp, const float pcm[], const int nsamples, unsigned char *mp3buf, const int mp3buf_size)
Definition: ExportMP3.cpp:730
static const TranslatableStrings varRateNames
Definition: ExportMP3.cpp:174
#define ID_DLOAD
Definition: ExportMP3.cpp:583
static const TranslatableStrings fixRateNames
Definition: ExportMP3.cpp:132
const char * get_lame_version_t(void)
Definition: ExportMP3.cpp:720
int lame_set_VBR_q_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:750
static const std::vector< int > fixRateValues
Definition: ExportMP3.cpp:153
@ QUALITY_2
Definition: ExportMP3.cpp:118
@ PRESET_EXTREME
Definition: ExportMP3.cpp:124
@ PRESET_INSANE
Definition: ExportMP3.cpp:123
@ PRESET_STANDARD
Definition: ExportMP3.cpp:125
@ PRESET_MEDIUM
Definition: ExportMP3.cpp:126
int lame_set_in_samplerate_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:744
int lame_close_t(lame_global_flags *)
Definition: ExportMP3.cpp:742
#define ID_ABR
Definition: ExportMP3.cpp:222
TranslatableString n_kbps(int n)
Definition: ExportMP3.cpp:130
EnumSetting< MP3RateMode > MP3RateModeSetting
Definition: ExportMP3.cpp:297
TranslatableString GetMP3Version(wxWindow *parent, bool prompt)
Definition: ExportMP3.cpp:2255
static Exporter::RegisteredExportPlugin sRegisteredPlugin
Definition: ExportMP3.cpp:2247
void lame_mp3_tags_fid_t(lame_global_flags *, FILE *)
Definition: ExportMP3.cpp:758
int lame_set_VBR_min_bitrate_kbps_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:751
int CDECL lame_encode_buffer_ieee_float_t(lame_t gfp, const float pcm_l[], const float pcm_r[], const int nsamples, unsigned char *mp3buf, const int mp3buf_size)
Definition: ExportMP3.cpp:722
int lame_set_error_protection_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:754
static EnumSetting< MP3ChannelMode > MP3ChannelModeSetting
Definition: ExportMP3.cpp:314
unsigned long beWriteInfoTag_t(lame_global_flags *, char *)
Definition: ExportMP3.cpp:766
static const TranslatableStrings setRateNames
Definition: ExportMP3.cpp:192
int lame_set_out_samplerate_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:745
int lame_set_quality_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:747
#define ID_MONO
Definition: ExportMP3.cpp:225
#define ID_SET
Definition: ExportMP3.cpp:220
MP3ChannelMode
Definition: ExportMP3.cpp:111
@ CHANNEL_MONO
Definition: ExportMP3.cpp:114
@ CHANNEL_JOINT
Definition: ExportMP3.cpp:112
@ CHANNEL_STEREO
Definition: ExportMP3.cpp:113
void beVersion_t(be_version *)
Definition: ExportMP3.cpp:798
int lame_set_preset_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:753
#define ID_BROWSE
Definition: ExportMP3.cpp:582
size_t lame_get_lametag_frame_t(const lame_global_flags *, unsigned char *buffer, size_t size)
Definition: ExportMP3.cpp:757
#define ID_QUALITY
Definition: ExportMP3.cpp:224
#define ID_CBR
Definition: ExportMP3.cpp:223
static const TranslatableStrings setRateNamesShort
Definition: ExportMP3.cpp:200
int lame_set_disable_reservoir_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:755
lame_global_flags * lame_init_t(void)
Definition: ExportMP3.cpp:718
int lame_encode_flush_t(lame_global_flags *gf, unsigned char *mp3buf, int size)
Definition: ExportMP3.cpp:737
int lame_set_num_channels_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:746
int lame_set_mode_t(lame_global_flags *, MPEG_mode)
Definition: ExportMP3.cpp:752
int lame_set_brate_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:748
int lame_init_params_t(lame_global_flags *)
Definition: ExportMP3.cpp:719
@ MODE_SET
Definition: ExportMP3.h:19
@ MODE_ABR
Definition: ExportMP3.h:21
@ MODE_VBR
Definition: ExportMP3.h:20
@ MODE_CBR
Definition: ExportMP3.h:22
int format
Definition: ExportPCM.cpp:56
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
std::unique_ptr< Character[], freer > MallocString
Definition: MemoryX.h:146
#define safenew
Definition: MemoryX.h:10
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:423
static const auto title
FileConfig * gPrefs
Definition: Prefs.cpp:71
an object holding per-project preferred sample rate
EffectReverbSettings preset
Definition: Reverb.cpp:46
@ floatSample
Definition: SampleFormat.h:34
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
Definition: SelectFile.cpp:17
#define OSOUTPUT(X)
Definition: SelectFile.h:48
@ eIsCreating
Definition: ShuttleGui.h:39
@ eIsCreatingFromPrefs
Definition: ShuttleGui.h:48
@ eIsSavingToPrefs
Definition: ShuttleGui.h:49
#define TAG_TRACK
Definition: Tags.h:61
#define TAG_COMMENTS
Definition: Tags.h:64
#define TAG_GENRE
Definition: Tags.h:63
#define TAG_ALBUM
Definition: Tags.h:60
#define TAG_YEAR
Definition: Tags.h:62
#define TAG_TITLE
Definition: Tags.h:58
#define TAG_ARTIST
Definition: Tags.h:59
static TranslatableStrings names
Definition: TagsEditor.cpp:151
#define S(N)
Definition: ToChars.cpp:64
declares abstract base class Track, TrackList, and iterators over TrackList
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
static const auto fn
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:57
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Adapts EnumSettingBase to a particular enumeration type.
Definition: Prefs.h:436
int SetNumExportChannels() override
Exporter plug-ins may override this to specify the number of channels in exported file....
Definition: ExportMP3.cpp:1753
unsigned long AddTags(AudacityProject *project, ArrayOf< char > &buffer, bool *endOfFile, const Tags *tags)
Definition: ExportMP3.cpp:2141
bool CheckFileName(wxFileName &filename, int format) override
Definition: ExportMP3.cpp:1736
int AskResample(int bitrate, int rate, int lowrate, int highrate)
Definition: ExportMP3.cpp:2066
ProgressResult Export(AudacityProject *project, std::unique_ptr< ProgressDialog > &pDialog, unsigned channels, const wxFileNameWrapper &fName, bool selectedOnly, double t0, double t1, MixerSpec *mixerSpec=NULL, const Tags *metadata=NULL, int subformat=0) override
called to export audio into a file.
Definition: ExportMP3.cpp:1762
void OptionsCreate(ShuttleGui &S, int format) override
Definition: ExportMP3.cpp:2061
ExportMP3Options(wxWindow *parent, int format)
Definition: ExportMP3.cpp:278
virtual ~ExportMP3Options()
Definition: ExportMP3.cpp:292
void OnVBR(wxCommandEvent &evt)
Definition: ExportMP3.cpp:511
wxRadioButton * mABR
Definition: ExportMP3.cpp:254
bool TransferDataToWindow() override
Definition: ExportMP3.cpp:456
wxRadioButton * mVBR
Definition: ExportMP3.cpp:253
wxRadioButton * mStereo
Definition: ExportMP3.cpp:249
bool TransferDataFromWindow() override
Definition: ExportMP3.cpp:461
wxChoice * mRate
Definition: ExportMP3.cpp:256
wxRadioButton * mSET
Definition: ExportMP3.cpp:252
void OnABR(wxCommandEvent &evt)
Definition: ExportMP3.cpp:522
void OnSET(wxCommandEvent &evt)
Definition: ExportMP3.cpp:500
void PopulateOrExchange(ShuttleGui &S)
Definition: ExportMP3.cpp:331
wxRadioButton * mCBR
Definition: ExportMP3.cpp:255
void OnCBR(wxCommandEvent &evt)
Definition: ExportMP3.cpp:533
void OnQuality(wxCommandEvent &evt)
Definition: ExportMP3.cpp:542
void LoadNames(const TranslatableStrings &choices)
Definition: ExportMP3.cpp:571
void OnMono(wxCommandEvent &evt)
Definition: ExportMP3.cpp:560
wxCheckBox * mMono
Definition: ExportMP3.cpp:251
wxRadioButton * mJoint
Definition: ExportMP3.cpp:250
void AddExtension(const FileExtension &extension, int index)
Definition: Export.cpp:127
int AddFormat()
Add a NEW entry to the list of formats this plug-in can export.
Definition: Export.cpp:101
void SetFormat(const wxString &format, int index)
Definition: Export.cpp:117
std::unique_ptr< Mixer > CreateMixer(const TrackList &tracks, bool selectionOnly, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, MixerSpec *mixerSpec)
Definition: Export.cpp:223
void SetDescription(const TranslatableString &description, int index)
Definition: Export.cpp:122
void SetCanMetaData(bool canmetadata, int index)
Definition: Export.cpp:147
static void InitProgress(std::unique_ptr< ProgressDialog > &pDialog, const TranslatableString &title, const TranslatableString &message)
Definition: Export.cpp:251
void SetMaxChannels(unsigned maxchannels, unsigned index)
Definition: Export.cpp:142
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
std::vector< FileType > FileTypes
Definition: FileNames.h:76
FILES_API const FileType AllFiles
Definition: FileNames.h:71
FILES_API const FileType DynamicLibraries
Definition: FileNames.h:73
wxTextCtrl * mPathText
Definition: ExportMP3.cpp:700
void OnBrowse(wxCommandEvent &WXUNUSED(event))
Definition: ExportMP3.cpp:657
wxFileName mLibPath
Definition: ExportMP3.cpp:693
wxString GetLibPath()
Definition: ExportMP3.cpp:683
FindDialog(wxWindow *parent, wxString path, wxString name, FileNames::FileTypes types)
Definition: ExportMP3.cpp:591
FileNames::FileTypes mTypes
Definition: ExportMP3.cpp:697
wxString mPath
Definition: ExportMP3.cpp:695
void PopulateOrExchange(ShuttleGui &S)
Definition: ExportMP3.cpp:609
void OnDownload(wxCommandEvent &WXUNUSED(event))
Definition: ExportMP3.cpp:678
wxString mName
Definition: ExportMP3.cpp:696
Abstract base class used in importing a file.
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:237
Class used to export MP3 files.
Definition: ExportMP3.cpp:802
lame_set_VBR_q_t * lame_set_VBR_q
Definition: ExportMP3.cpp:896
static const int mOutBufferSize
Definition: ExportMP3.cpp:916
lame_set_in_samplerate_t * lame_set_in_samplerate
Definition: ExportMP3.cpp:890
wxString GetLibraryVersion()
Definition: ExportMP3.cpp:1277
bool InitLibraryExternal(wxString libpath)
Definition: ExportMP3.cpp:1146
int EncodeBufferMono(float inbuffer[], unsigned char outbuffer[])
Definition: ExportMP3.cpp:1419
lame_set_disable_reservoir_t * lame_set_disable_reservoir
Definition: ExportMP3.cpp:901
int EncodeRemainderMono(float inbuffer[], int nSamples, unsigned char outbuffer[])
Definition: ExportMP3.cpp:1429
bool mLibIsExternal
Definition: ExportMP3.cpp:861
int GetOutBufferSize()
Definition: ExportMP3.cpp:1390
bool PutInfoTag(wxFFile &f, wxFileOffset off)
Definition: ExportMP3.cpp:1466
lame_mp3_tags_fid_t * lame_mp3_tags_fid
Definition: ExportMP3.cpp:904
unsigned char mInfoTagBuf[2880]
Definition: ExportMP3.cpp:920
void SetBitrate(int rate)
Definition: ExportMP3.cpp:1073
size_t mInfoTagLen
Definition: ExportMP3.cpp:921
lame_init_t * lame_init
Definition: ExportMP3.cpp:882
bool ValidLibraryLoaded()
Definition: ExportMP3.cpp:1061
lame_set_brate_t * lame_set_brate
Definition: ExportMP3.cpp:894
lame_encode_buffer_ieee_float_t * lame_encode_buffer_ieee_float
Definition: ExportMP3.cpp:884
lame_encode_buffer_interleaved_ieee_float_t * lame_encode_buffer_interleaved_ieee_float
Definition: ExportMP3.cpp:885
bool mEncoding
Definition: ExportMP3.cpp:873
lame_get_lametag_frame_t * lame_get_lametag_frame
Definition: ExportMP3.cpp:903
lame_set_num_channels_t * lame_set_num_channels
Definition: ExportMP3.cpp:892
void FreeLibrary()
Definition: ExportMP3.cpp:1263
int EncodeBuffer(float inbuffer[], unsigned char outbuffer[])
Definition: ExportMP3.cpp:1398
get_lame_version_t * get_lame_version
Definition: ExportMP3.cpp:888
static const int mSamplesPerChunk
Definition: ExportMP3.cpp:913
bool FindLibrary(wxWindow *parent)
Definition: ExportMP3.cpp:963
void CancelEncoding()
Definition: ExportMP3.cpp:1461
bool LoadLibrary(wxWindow *parent, AskUser askuser)
Definition: ExportMP3.cpp:998
wxString GetLibraryName()
Definition: ExportMP3.cpp:1517
lame_set_VBR_t * lame_set_VBR
Definition: ExportMP3.cpp:895
FileNames::FileTypes GetLibraryTypes()
Definition: ExportMP3.cpp:1522
void SetChannel(int mode)
Definition: ExportMP3.cpp:1084
wxDynamicLibrary lame_lib
Definition: ExportMP3.cpp:865
bool InitLibrary(wxString libpath)
Definition: ExportMP3.cpp:1089
lame_global_flags * mGF
Definition: ExportMP3.cpp:911
wxString GetLibraryPath()
Definition: ExportMP3.cpp:1499
lame_close_t * lame_close
Definition: ExportMP3.cpp:887
int FinishStream(unsigned char outbuffer[])
Definition: ExportMP3.cpp:1440
lame_set_quality_t * lame_set_quality
Definition: ExportMP3.cpp:893
wxString mLibPath
Definition: ExportMP3.cpp:864
beWriteInfoTag_t * beWriteInfoTag
Definition: ExportMP3.cpp:906
lame_encode_flush_t * lame_encode_flush
Definition: ExportMP3.cpp:886
void SetMode(int mode)
Definition: ExportMP3.cpp:1068
int InitializeStream(unsigned channels, int sampleRate)
Definition: ExportMP3.cpp:1288
lame_set_error_protection_t * lame_set_error_protection
Definition: ExportMP3.cpp:900
lame_set_VBR_min_bitrate_kbps_t * lame_set_VBR_min_bitrate_kbps
Definition: ExportMP3.cpp:897
void SetQuality(int q)
Definition: ExportMP3.cpp:1078
bool InitLibraryInternal()
Definition: ExportMP3.cpp:1094
int EncodeRemainder(float inbuffer[], int nSamples, unsigned char outbuffer[])
Definition: ExportMP3.cpp:1408
lame_set_out_samplerate_t * lame_set_out_samplerate
Definition: ExportMP3.cpp:891
lame_set_mode_t * lame_set_mode
Definition: ExportMP3.cpp:898
TranslatableString mBladeVersion
Definition: ExportMP3.cpp:870
lame_set_bWriteVbrTag_t * lame_set_bWriteVbrTag
Definition: ExportMP3.cpp:902
lame_init_params_t * lame_init_params
Definition: ExportMP3.cpp:883
bool mLibraryLoaded
Definition: ExportMP3.cpp:866
beVersion_t * beVersion
Definition: ExportMP3.cpp:907
lame_set_preset_t * lame_set_preset
Definition: ExportMP3.cpp:899
Class used with Mixer.
Definition: Mix.h:37
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
double GetRate() const
Definition: ProjectRate.cpp:53
static ProjectWindow * Find(AudacityProject *pProject)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
ID3 Tags (for MP3)
Definition: Tags.h:73
Iterators GetRange() const
Definition: Tags.cpp:436
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:214
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:467
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
struct with zillion of control parameters that control lame export (MP3 Conversion DLL).
void SetName(const TranslatableString &title)
#define lrint(dbl)
Definition: float_cast.h:169
ProgressResult
Definition: BasicUI.h:145
FILES_API FilePath PathFromAddr(void *addr)
BuiltinCommandsModule::Registration< CompareAudioCommand > reg
int ValidateIndex(const std::vector< int > &values, int value, int defaultIndex)
Definition: ExportMP3.cpp:489
int ValidateValue(const std::vector< int > &values, int value, int defaultValue)
Definition: ExportMP3.cpp:482
BYTE byMinorVersion
Definition: ExportMP3.cpp:780
BYTE byDLLMinorVersion
Definition: ExportMP3.cpp:775
BYTE byBetaLevel
Definition: ExportMP3.cpp:793
BYTE byMMXEnabled
Definition: ExportMP3.cpp:794
BYTE byMajorVersion
Definition: ExportMP3.cpp:779
BYTE byAlphaLevel
Definition: ExportMP3.cpp:792
BYTE byDLLMajorVersion
Definition: ExportMP3.cpp:774
BYTE byMonth
Definition: ExportMP3.cpp:785