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 IntSetting Setting{ L"/FileFormats/MP3Bitrate", defrate };
407
408 mRate = S.Id(ID_QUALITY).TieNumberAsChoice(
409 XXO("Quality"),
410 Setting,
411 *choices,
412 codes
413 );
414 /*
415 mMode = S.Disable(!enable)
416 .TieNumberAsChoice(
417 XXO("Variable Speed:"),
418 { wxT("/FileFormats/MP3VarMode"), ROUTINE_FAST },
419 varModeNames );
420 */
421 S.AddPrompt(XXO("Channel Mode:"));
422 S.StartMultiColumn(2, wxEXPAND);
423 {
424 // Bug 2692: Place button group in panel so tabbing will work and,
425 // on the Mac, VoiceOver will announce as radio buttons.
426 S.StartPanel();
427 {
428 S.StartHorizontalLay();
429 {
430 S.StartRadioButtonGroup(MP3ChannelModeSetting);
431 {
432 mJoint = S.Disable(mono)
433 .TieRadioButton();
434 mStereo = S.Disable(mono)
435 .TieRadioButton();
436 }
437 S.EndRadioButtonGroup();
438 }
439 S.EndHorizontalLay();
440 }
441 S.EndPanel();
442
443 mMono = S.Id(ID_MONO).AddCheckBox(XXO("Force export to mono"), mono);
444 }
445 S.EndMultiColumn();
446 }
447 S.EndTwoColumn();
448 }
449 S.EndMultiColumn();
450 }
451 S.EndHorizontalLay();
452 }
453 S.EndVerticalLay();
454}
455
459{
460 return true;
461}
462
464{
467
468 gPrefs->Write(wxT("/FileFormats/MP3SetRate"), mSetRate);
469 gPrefs->Write(wxT("/FileFormats/MP3VbrRate"), mVbrRate);
470 gPrefs->Write(wxT("/FileFormats/MP3AbrRate"), mAbrRate);
471 gPrefs->Write(wxT("/FileFormats/MP3CbrRate"), mCbrRate);
472 gPrefs->Flush();
473
474 return true;
475}
476
477namespace {
478
479int ValidateValue( int nValues, int value, int defaultValue )
480{
481 return (value >= 0 && value < nValues) ? value : defaultValue;
482}
483
484int ValidateValue( const std::vector<int> &values, int value, int defaultValue )
485{
486 auto start = values.begin(), finish = values.end(),
487 iter = std::find( start, finish, value );
488 return ( iter != finish ) ? value : defaultValue;
489}
490
491int ValidateIndex( const std::vector<int> &values, int value, int defaultIndex )
492{
493 auto start = values.begin(), finish = values.end(),
494 iter = std::find( start, finish, value );
495 return ( iter != finish ) ? static_cast<int>( iter - start ) : defaultIndex;
496}
497
498}
499
502void ExportMP3Options::OnSET(wxCommandEvent& WXUNUSED(event))
503{
505
506 mRate->SetSelection(ValidateValue(setRateNames.size(), mSetRate, 2));
507 mRate->Refresh();
508 //mMode->Enable(true);
509}
510
513void ExportMP3Options::OnVBR(wxCommandEvent& WXUNUSED(event))
514{
516
517 mRate->SetSelection(ValidateValue(varRateNames.size(), mVbrRate, 2));
518 mRate->Refresh();
519 //mMode->Enable(true);
520}
521
524void ExportMP3Options::OnABR(wxCommandEvent& WXUNUSED(event))
525{
527
528 mRate->SetSelection(ValidateIndex(fixRateValues, mAbrRate, 10));
529 mRate->Refresh();
530 //mMode->Enable(false);
531}
532
535void ExportMP3Options::OnCBR(wxCommandEvent& WXUNUSED(event))
536{
538
539 mRate->SetSelection(ValidateIndex(fixRateValues, mCbrRate, 10));
540 mRate->Refresh();
541 //mMode->Enable(false);
542}
543
544void ExportMP3Options::OnQuality(wxCommandEvent& WXUNUSED(event))
545{
546 int sel = mRate->GetSelection();
547
548 if (mSET->GetValue()) {
549 mSetRate = sel;
550 }
551 else if (mVBR->GetValue()) {
552 mVbrRate = sel;
553 }
554 else if (mABR->GetValue()) {
555 mAbrRate = fixRateValues[ sel ];
556 }
557 else {
558 mCbrRate = fixRateValues[ sel ];
559 }
560}
561
562void ExportMP3Options::OnMono(wxCommandEvent& /*evt*/)
563{
564 bool mono = false;
565 mono = mMono->GetValue();
566 mJoint->Enable(!mono);
567 mStereo->Enable(!mono);
568
569 gPrefs->Write(wxT("/FileFormats/MP3ForceMono"), mono);
570 gPrefs->Flush();
571}
572
574{
575 mRate->Clear();
576 for (const auto &name : names)
577 mRate->Append( name.Translation() );
578}
579
580//----------------------------------------------------------------------------
581// FindDialog
582//----------------------------------------------------------------------------
583
584#define ID_BROWSE 5000
585#define ID_DLOAD 5001
586
587class FindDialog final : public wxDialogWrapper
588{
589public:
590
591#ifndef DISABLE_DYNAMIC_LOADING_LAME
592
593 FindDialog(wxWindow *parent, wxString path, wxString name,
595 : wxDialogWrapper(parent, wxID_ANY,
596 /* i18n-hint: LAME is the name of an MP3 converter and should not be translated*/
597 XO("Locate LAME"))
598 {
599 SetName();
600 ShuttleGui S(this, eIsCreating);
601
602 mPath = path;
603 mName = name;
604 mTypes = std::move( types );
605
606 mLibPath.Assign(mPath, mName);
607
609 }
610
612 {
613 S.SetBorder(10);
614 S.StartVerticalLay(true);
615 {
616 S.AddTitle(
617 XO("Audacity needs the file %s to create MP3s.")
618 .Format( mName ) );
619
620 S.SetBorder(3);
621 S.StartHorizontalLay(wxALIGN_LEFT, true);
622 {
623 S.AddTitle( XO("Location of %s:").Format( mName ) );
624 }
625 S.EndHorizontalLay();
626
627 S.StartMultiColumn(2, wxEXPAND);
628 S.SetStretchyCol(0);
629 {
630 if (mLibPath.GetFullPath().empty()) {
631 mPathText = S.AddTextBox( {},
632 /* i18n-hint: There is a button to the right of the arrow.*/
633 wxString::Format(_("To find %s, click here -->"), mName), 0);
634 }
635 else {
636 mPathText = S.AddTextBox( {}, mLibPath.GetFullPath(), 0);
637 }
638 S.Id(ID_BROWSE).AddButton(XXO("Browse..."), wxALIGN_RIGHT);
639 S.AddVariableText(
640 /* i18n-hint: There is a button to the right of the arrow.*/
641 XO("To get a free copy of LAME, click here -->"), true);
642 /* i18n-hint: (verb)*/
643 S.Id(ID_DLOAD).AddButton(XXO("Download"), wxALIGN_RIGHT);
644 }
645 S.EndMultiColumn();
646
647 S.AddStandardButtons();
648 }
649 S.EndVerticalLay();
650
651 Layout();
652 Fit();
653 SetMinSize(GetSize());
654 Center();
655
656 return;
657 }
658
659 void OnBrowse(wxCommandEvent & WXUNUSED(event))
660 {
661 /* i18n-hint: It's asking for the location of a file, for
662 * example, "Where is lame_enc.dll?" - you could translate
663 * "Where would I find the file %s" instead if you want. */
664 auto question = XO("Where is %s?").Format( mName );
665
666 wxString path = SelectFile(FileNames::Operation::_None,
667 question,
668 mLibPath.GetPath(),
669 mLibPath.GetName(),
670 wxT(""),
671 mTypes,
672 wxFD_OPEN | wxRESIZE_BORDER,
673 this);
674 if (!path.empty()) {
675 mLibPath = path;
676 mPathText->SetValue(path);
677 }
678 }
679
680 void OnDownload(wxCommandEvent & WXUNUSED(event))
681 {
682 HelpSystem::ShowHelp(this, L"FAQ:Installing_the_LAME_MP3_Encoder");
683 }
684
685 wxString GetLibPath()
686 {
687 return mLibPath.GetFullPath();
688 }
689
690#endif // DISABLE_DYNAMIC_LOADING_LAME
691
692private:
693
694#ifndef DISABLE_DYNAMIC_LOADING_LAME
695 wxFileName mLibPath;
696
697 wxString mPath;
698 wxString mName;
700#endif // DISABLE_DYNAMIC_LOADING_LAME
701
702 wxTextCtrl *mPathText;
703
704 DECLARE_EVENT_TABLE()
705};
706
707#ifndef DISABLE_DYNAMIC_LOADING_LAME
708BEGIN_EVENT_TABLE(FindDialog, wxDialogWrapper)
712#endif // DISABLE_DYNAMIC_LOADING_LAME
713
714//----------------------------------------------------------------------------
715// MP3Exporter
716//----------------------------------------------------------------------------
717
718#ifndef DISABLE_DYNAMIC_LOADING_LAME
719
722typedef const char* get_lame_version_t(void);
723
725 lame_t gfp,
726 const float pcm_l[],
727 const float pcm_r[],
728 const int nsamples,
729 unsigned char * mp3buf,
730 const int mp3buf_size);
731
733 lame_t gfp,
734 const float pcm[],
735 const int nsamples,
736 unsigned char * mp3buf,
737 const int mp3buf_size);
738
741 unsigned char* mp3buf,
742 int size );
743
745
751typedef int lame_set_VBR_t(lame_global_flags *, vbr_mode);
754typedef int lame_set_mode_t(lame_global_flags *, MPEG_mode);
759typedef size_t lame_get_lametag_frame_t(const lame_global_flags *, unsigned char* buffer, size_t size);
761
762#endif // DISABLE_DYNAMIC_LOADING_LAME
763
764#if defined(__WXMSW__)
765// An alternative solution to give Windows an additional chance of writing the tag before
766// falling bato to lame_mp3_tag_fid(). The latter can have DLL sharing issues when mixing
767// Debug/Release builds of Audacity and the lame DLL.
768typedef unsigned long beWriteInfoTag_t(lame_global_flags *, char *);
769
770// We use this to determine if the user has selected an older, Blade API only, lame_enc.dll
771// so we can be more specific about why their library isn't acceptable.
772typedef struct {
773
774 // BladeEnc DLL Version number
775
778
779 // BladeEnc Engine Version Number
780
783
784 // DLL Release date
785
786 BYTE byDay;
788 WORD wYear;
789
790 // BladeEnc Homepage URL
791
792 CHAR zHomepage[129];
793
797
798 BYTE btReserved[125];
799} be_version;
800typedef void beVersion_t(be_version *);
801#endif
802
804{
805public:
807 {
810 Yes
811 };
812
813 MP3Exporter();
814 ~MP3Exporter();
815
816#ifndef DISABLE_DYNAMIC_LOADING_LAME
817 bool FindLibrary(wxWindow *parent);
818 bool LoadLibrary(wxWindow *parent, AskUser askuser);
819 bool ValidLibraryLoaded();
820#endif // DISABLE_DYNAMIC_LOADING_LAME
821
822 /* These global settings keep state over the life of the object */
823 void SetMode(int mode);
824 void SetBitrate(int rate);
825 void SetQuality(int q/*, int r*/);
826 void SetChannel(int mode);
827
828 /* Virtual methods that must be supplied by library interfaces */
829
830 /* initialize the library interface */
831 bool InitLibrary(wxString libpath);
832 bool InitLibraryInternal();
833 bool InitLibraryExternal(wxString libpath);
834 void FreeLibrary();
835
836 /* get library info */
837 wxString GetLibraryVersion();
838 wxString GetLibraryName();
839 wxString GetLibraryPath();
841
842 /* returns the number of samples PER CHANNEL to send for each call to EncodeBuffer */
843 int InitializeStream(unsigned channels, int sampleRate);
844
845 /* In bytes. must be called AFTER InitializeStream */
846 int GetOutBufferSize();
847
848 /* returns the number of bytes written. input is interleaved if stereo*/
849 int EncodeBuffer(float inbuffer[], unsigned char outbuffer[]);
850 int EncodeRemainder(float inbuffer[], int nSamples,
851 unsigned char outbuffer[]);
852
853 int EncodeBufferMono(float inbuffer[], unsigned char outbuffer[]);
854 int EncodeRemainderMono(float inbuffer[], int nSamples,
855 unsigned char outbuffer[]);
856
857 int FinishStream(unsigned char outbuffer[]);
858 void CancelEncoding();
859
860 bool PutInfoTag(wxFFile & f, wxFileOffset off);
861
862private:
864
865#ifndef DISABLE_DYNAMIC_LOADING_LAME
866 wxString mLibPath;
867 wxDynamicLibrary lame_lib;
869#endif // DISABLE_DYNAMIC_LOADING_LAME
870
871#if defined(__WXMSW__)
873#endif
874
876 int mMode;
879 //int mRoutine;
881
882#ifndef DISABLE_DYNAMIC_LOADING_LAME
883 /* function pointers to the symbols we get from the library */
891
907#if defined(__WXMSW__)
910#endif
911#endif // DISABLE_DYNAMIC_LOADING_LAME
912
914
915 static const int mSamplesPerChunk = 220500;
916 // See lame.h/lame_encode_buffer() for further explanation
917 // As coded here, this should be the worst case.
918 static const int mOutBufferSize =
919 mSamplesPerChunk * (320 / 8) / 8 + 4 * 1152 * (320 / 8) / 8 + 512;
920
921 // See MAXFRAMESIZE in libmp3lame/VbrTag.c for explanation of 2880.
922 unsigned char mInfoTagBuf[2880];
924};
925
927{
928// We could use #defines rather than this variable.
929// The idea of the variable is that if we wanted, we could allow
930// a dynamic override of the library, e.g. with a newer faster version,
931// or to fix CVEs in the underlying library.
932// for now though the 'variable' is a constant.
933#ifdef MP3_EXPORT_BUILT_IN
934 mLibIsExternal = false;
935#else
936 mLibIsExternal = true;
937#endif
938
939#ifndef DISABLE_DYNAMIC_LOADING_LAME
940 mLibraryLoaded = false;
941#endif // DISABLE_DYNAMIC_LOADING_LAME
942 mEncoding = false;
943 mGF = NULL;
944
945#ifndef DISABLE_DYNAMIC_LOADING_LAME
946 if (gPrefs) {
947 mLibPath = gPrefs->Read(wxT("/MP3/MP3LibPath"), wxT(""));
948 }
949#endif // DISABLE_DYNAMIC_LOADING_LAME
950
951 mBitrate = 128;
954 mMode = MODE_CBR;
955 //mRoutine = ROUTINE_FAST;
956}
957
959{
960 FreeLibrary();
961}
962
963#ifndef DISABLE_DYNAMIC_LOADING_LAME
964
965bool MP3Exporter::FindLibrary(wxWindow *parent)
966{
967 wxString path;
968 wxString name;
969
970 if (!mLibPath.empty()) {
971 wxFileName fn = mLibPath;
972 path = fn.GetPath();
973 name = fn.GetFullName();
974 }
975 else {
976 path = GetLibraryPath();
978 }
979
980 FindDialog fd(parent,
981 path,
982 name,
984
985 if (fd.ShowModal() == wxID_CANCEL) {
986 return false;
987 }
988
989 path = fd.GetLibPath();
990
991 if (!::wxFileExists(path)) {
992 return false;
993 }
994
995 mLibPath = path;
996
997 return (gPrefs->Write(wxT("/MP3/MP3LibPath"), mLibPath) && gPrefs->Flush());
998}
999
1000bool MP3Exporter::LoadLibrary(wxWindow *parent, AskUser askuser)
1001{
1002
1003 if (ValidLibraryLoaded()) {
1004 FreeLibrary();
1005 mLibraryLoaded = false;
1006 }
1007
1008#if defined(__WXMSW__)
1009 mBladeVersion = {};
1010#endif
1011
1012 if( !mLibIsExternal ){
1014 return mLibraryLoaded;
1015 }
1016
1017 // First try loading it from a previously located path
1018 if (!mLibPath.empty()) {
1019 wxLogMessage(wxT("Attempting to load LAME from previously defined path"));
1021 }
1022
1023 // If not successful, try loading using system search paths
1024 if (!ValidLibraryLoaded()) {
1025 wxLogMessage(wxT("Attempting to load LAME from system search paths"));
1028 }
1029
1030 // If not successful, try loading using compiled in path
1031 if (!ValidLibraryLoaded()) {
1032 wxLogMessage(wxT("Attempting to load LAME from builtin path"));
1033 wxFileName fn(GetLibraryPath(), GetLibraryName());
1034 mLibPath = fn.GetFullPath();
1036 }
1037
1038 // If not successful, must ask the user
1039 if (!ValidLibraryLoaded()) {
1040 wxLogMessage(wxT("(Maybe) ask user for library"));
1041 if (askuser == MP3Exporter::Maybe && FindLibrary(parent)) {
1043 }
1044 }
1045
1046 // Oh well, just give up
1047 if (!ValidLibraryLoaded()) {
1048#if defined(__WXMSW__)
1049 if (askuser && !mBladeVersion.empty()) {
1051 }
1052#endif
1053 wxLogMessage(wxT("Failed to locate LAME library"));
1054
1055 return false;
1056 }
1057
1058 wxLogMessage(wxT("LAME library successfully loaded"));
1059
1060 return true;
1061}
1062
1064{
1065 return mLibraryLoaded;
1066}
1067
1068#endif // DISABLE_DYNAMIC_LOADING_LAME
1069
1071{
1072 mMode = mode;
1073}
1074
1076{
1077 mBitrate = rate;
1078}
1079
1080void MP3Exporter::SetQuality(int q/*, int r*/)
1081{
1082 mQuality = q;
1083 //mRoutine = r;
1084}
1085
1087{
1088 mChannel = mode;
1089}
1090
1091bool MP3Exporter::InitLibrary(wxString libpath)
1092{
1094}
1095
1097{
1098 wxLogMessage(wxT("Using internal LAME"));
1099
1100// The global ::lame_something symbols only exist if LAME is built in.
1101// So we don't reference them unless they are.
1102#ifdef MP3_EXPORT_BUILT_IN
1103
1111
1125
1126 // These are optional
1127 //lame_get_lametag_frame = ::lame_get_lametag_frame;
1130
1131#if defined(__WXMSW__)
1132 //beWriteInfoTag = ::beWriteInfoTag;
1133 //beVersion = ::beVersion;
1134 beWriteInfoTag = NULL;
1135 beVersion = NULL;
1136#endif
1137
1138 mGF = lame_init();
1139 if (mGF == NULL) {
1140 return false;
1141 }
1142#endif
1143
1144 return true;
1145}
1146
1147
1149{
1150 wxLogMessage(wxT("Loading LAME from %s"), libpath);
1151
1152#ifndef DISABLE_DYNAMIC_LOADING_LAME
1153 if (!lame_lib.Load(libpath, wxDL_LAZY)) {
1154 wxLogMessage(wxT("load failed"));
1155 return false;
1156 }
1157
1158 wxLogMessage(wxT("Actual LAME path %s"),
1159 FileNames::PathFromAddr(lame_lib.GetSymbol(wxT("lame_init"))));
1160
1162 lame_lib.GetSymbol(wxT("lame_init"));
1164 lame_lib.GetSymbol(wxT("get_lame_version"));
1166 lame_lib.GetSymbol(wxT("lame_init_params"));
1168 lame_lib.GetSymbol(wxT("lame_encode_buffer_ieee_float"));
1170 lame_lib.GetSymbol(wxT("lame_encode_buffer_interleaved_ieee_float"));
1172 lame_lib.GetSymbol(wxT("lame_encode_flush"));
1174 lame_lib.GetSymbol(wxT("lame_close"));
1175
1177 lame_lib.GetSymbol(wxT("lame_set_in_samplerate"));
1179 lame_lib.GetSymbol(wxT("lame_set_out_samplerate"));
1181 lame_lib.GetSymbol(wxT("lame_set_num_channels"));
1183 lame_lib.GetSymbol(wxT("lame_set_quality"));
1185 lame_lib.GetSymbol(wxT("lame_set_brate"));
1187 lame_lib.GetSymbol(wxT("lame_set_VBR"));
1189 lame_lib.GetSymbol(wxT("lame_set_VBR_q"));
1191 lame_lib.GetSymbol(wxT("lame_set_VBR_min_bitrate_kbps"));
1193 lame_lib.GetSymbol(wxT("lame_set_mode"));
1195 lame_lib.GetSymbol(wxT("lame_set_preset"));
1197 lame_lib.GetSymbol(wxT("lame_set_error_protection"));
1199 lame_lib.GetSymbol(wxT("lame_set_disable_reservoir"));
1201 lame_lib.GetSymbol(wxT("lame_set_bWriteVbrTag"));
1202
1203 // These are optional
1205 lame_lib.GetSymbol(wxT("lame_get_lametag_frame"));
1207 lame_lib.GetSymbol(wxT("lame_mp3_tags_fid"));
1208#if defined(__WXMSW__)
1210 lame_lib.GetSymbol(wxT("beWriteInfoTag"));
1212 lame_lib.GetSymbol(wxT("beVersion"));
1213#endif
1214
1215 if (!lame_init ||
1221 !lame_close ||
1226 !lame_set_brate ||
1227 !lame_set_VBR ||
1228 !lame_set_VBR_q ||
1229 !lame_set_mode ||
1230 !lame_set_preset ||
1234 {
1235 wxLogMessage(wxT("Failed to find a required symbol in the LAME library."));
1236#if defined(__WXMSW__)
1237 if (beVersion) {
1238 be_version v;
1239 beVersion(&v);
1240
1241 mBladeVersion = XO(
1242"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'.")
1243 .Format(
1246 AUDACITY_VERSION,
1247 AUDACITY_RELEASE,
1248 AUDACITY_REVISION);
1249 }
1250#endif
1251
1252 lame_lib.Unload();
1253 return false;
1254 }
1255#endif // DISABLE_DYNAMIC_LOADING_LAME
1256
1257 mGF = lame_init();
1258 if (mGF == NULL) {
1259 return false;
1260 }
1261
1262 return true;
1263}
1264
1266{
1267 if (mGF) {
1268 lame_close(mGF);
1269 mGF = NULL;
1270 }
1271
1272#ifndef DISABLE_DYNAMIC_LOADING_LAME
1273 lame_lib.Unload();
1274#endif // DISABLE_DYNAMIC_LOADING_LAME
1275
1276 return;
1277}
1278
1280{
1281#ifndef DISABLE_DYNAMIC_LOADING_LAME
1282 if (!mLibraryLoaded) {
1283 return wxT("");
1284 }
1285#endif // DISABLE_DYNAMIC_LOADING_LAME
1286
1287 return wxString::Format(wxT("LAME %hs"), get_lame_version());
1288}
1289
1290int MP3Exporter::InitializeStream(unsigned channels, int sampleRate)
1291{
1292#ifndef DISABLE_DYNAMIC_LOADING_LAME
1293 if (!mLibraryLoaded) {
1294 return -1;
1295 }
1296#endif // DISABLE_DYNAMIC_LOADING_LAME
1297
1298 if (channels > 2) {
1299 return -1;
1300 }
1301
1303 lame_set_num_channels(mGF, channels);
1304 lame_set_in_samplerate(mGF, sampleRate);
1305 lame_set_out_samplerate(mGF, sampleRate);
1307 // Add the VbrTag for all types. For ABR/VBR, a Xing tag will be created.
1308 // For CBR, it will be a Lame Info tag.
1310
1311 // Set the VBR quality or ABR/CBR bitrate
1312 switch (mMode) {
1313 case MODE_SET:
1314 {
1315 int preset;
1316
1317 if (mQuality == PRESET_INSANE) {
1318 preset = INSANE;
1319 }
1320 //else if (mRoutine == ROUTINE_FAST) {
1321 else if (mQuality == PRESET_EXTREME) {
1322 preset = EXTREME_FAST;
1323 }
1324 else if (mQuality == PRESET_STANDARD) {
1325 preset = STANDARD_FAST;
1326 }
1327 else {
1328 preset = 1007; // Not defined until 3.96
1329 }
1330 //}
1331 /*
1332 else {
1333 if (mQuality == PRESET_EXTREME) {
1334 preset = EXTREME;
1335 }
1336 else if (mQuality == PRESET_STANDARD) {
1337 preset = STANDARD;
1338 }
1339 else {
1340 preset = 1006; // Not defined until 3.96
1341 }
1342 }
1343 */
1345 }
1346 break;
1347
1348 case MODE_VBR:
1349 lame_set_VBR(mGF, vbr_mtrh );
1351 break;
1352
1353 case MODE_ABR:
1355 break;
1356
1357 default:
1358 lame_set_VBR(mGF, vbr_off);
1360 break;
1361 }
1362
1363 // Set the channel mode
1364 MPEG_mode mode;
1365
1366 if (channels == 1 || mChannel == CHANNEL_MONO) {
1367 mode = MONO;
1368 }
1369 else if (mChannel == CHANNEL_JOINT) {
1370 mode = JOINT_STEREO;
1371 }
1372 else {
1373 mode = STEREO;
1374 }
1375 lame_set_mode(mGF, mode);
1376
1377 int rc = lame_init_params(mGF);
1378 if (rc < 0) {
1379 return rc;
1380 }
1381
1382#if 0
1383 dump_config(mGF);
1384#endif
1385
1386 mInfoTagLen = 0;
1387 mEncoding = true;
1388
1389 return mSamplesPerChunk;
1390}
1391
1393{
1394 if (!mEncoding)
1395 return -1;
1396
1397 return mOutBufferSize;
1398}
1399
1400int MP3Exporter::EncodeBuffer(float inbuffer[], unsigned char outbuffer[])
1401{
1402 if (!mEncoding) {
1403 return -1;
1404 }
1405
1407 outbuffer, mOutBufferSize);
1408}
1409
1410int MP3Exporter::EncodeRemainder(float inbuffer[], int nSamples,
1411 unsigned char outbuffer[])
1412{
1413 if (!mEncoding) {
1414 return -1;
1415 }
1416
1417 return lame_encode_buffer_interleaved_ieee_float(mGF, inbuffer, nSamples, outbuffer,
1419}
1420
1421int MP3Exporter::EncodeBufferMono(float inbuffer[], unsigned char outbuffer[])
1422{
1423 if (!mEncoding) {
1424 return -1;
1425 }
1426
1427 return lame_encode_buffer_ieee_float(mGF, inbuffer,inbuffer, mSamplesPerChunk,
1428 outbuffer, mOutBufferSize);
1429}
1430
1431int MP3Exporter::EncodeRemainderMono(float inbuffer[], int nSamples,
1432 unsigned char outbuffer[])
1433{
1434 if (!mEncoding) {
1435 return -1;
1436 }
1437
1438 return lame_encode_buffer_ieee_float(mGF, inbuffer, inbuffer, nSamples, outbuffer,
1440}
1441
1442int MP3Exporter::FinishStream(unsigned char outbuffer[])
1443{
1444 if (!mEncoding) {
1445 return -1;
1446 }
1447
1448 mEncoding = false;
1449
1450 int result = lame_encode_flush(mGF, outbuffer, mOutBufferSize);
1451
1452#if defined(DISABLE_DYNAMIC_LOADING_LAME)
1454#else
1457 }
1458#endif
1459
1460 return result;
1461}
1462
1464{
1465 mEncoding = false;
1466}
1467
1468bool MP3Exporter::PutInfoTag(wxFFile & f, wxFileOffset off)
1469{
1470 if (mGF) {
1471 if (mInfoTagLen > 0) {
1472 // FIXME: TRAP_ERR Seek and writ ein MP3 exporter could fail.
1473 if ( !f.Seek(off, wxFromStart))
1474 return false;
1475 if (mInfoTagLen > f.Write(mInfoTagBuf, mInfoTagLen))
1476 return false;
1477 }
1478#if defined(__WXMSW__)
1479 else if (beWriteInfoTag) {
1480 if ( !f.Flush() )
1481 return false;
1482 // PRL: What is the correct error check on the return value?
1483 beWriteInfoTag(mGF, OSOUTPUT(f.GetName()));
1484 mGF = NULL;
1485 }
1486#endif
1487 else if (lame_mp3_tags_fid != NULL) {
1488 lame_mp3_tags_fid(mGF, f.fp());
1489 }
1490 }
1491
1492 if ( !f.SeekEnd() )
1493 return false;
1494
1495 return true;
1496}
1497
1498#if defined(__WXMSW__)
1499/* values for Windows */
1500
1502{
1503 wxRegKey reg(wxT("HKEY_LOCAL_MACHINE\\Software\\Lame for Audacity"));
1504 wxString path;
1505
1506 if (reg.Exists()) {
1507 wxLogMessage(wxT("LAME registry key exists."));
1508 reg.QueryValue(wxT("InstallPath"), path);
1509 }
1510 else {
1511 wxLogMessage(wxT("LAME registry key does not exist."));
1512 }
1513
1514 wxLogMessage(wxT("Library path is: ") + path);
1515
1516 return path;
1517}
1518
1520{
1521 return wxT("lame_enc.dll");
1522}
1523
1525{
1526 return {
1527 { XO("Only lame_enc.dll"), { wxT("lame_enc.dll") } },
1530 };
1531}
1532
1533#elif defined(__WXMAC__)
1534/* values for Mac OS X */
1535
1537{
1538 wxString path;
1539
1540 path = wxT("/Library/Application Support/audacity/libs");
1541 if (wxFileExists(path + wxT("/") + GetLibraryName()))
1542 {
1543 return path;
1544 }
1545
1546 path = wxT("/usr/local/lib/audacity");
1547 if (wxFileExists(path + wxT("/") + GetLibraryName()))
1548 {
1549 return path;
1550 }
1551
1552 return wxT("/Library/Application Support/audacity/libs");
1553}
1554
1556{
1557 if (sizeof(void*) == 8)
1558 return wxT("libmp3lame64bit.dylib");
1559 return wxT("libmp3lame.dylib");
1560}
1561
1563{
1564 return {
1565 (sizeof(void*) == 8)
1567 XO("Only libmp3lame64bit.dylib"), { wxT("libmp3lame64bit.dylib") }
1568 }
1570 XO("Only libmp3lame.dylib"), { wxT("libmp3lame.dylib") }
1571 }
1572 ,
1575 };
1576}
1577
1578#else
1579/* Values for Linux / Unix systems */
1580
1582{
1583 return wxT(LIBDIR);
1584}
1585
1587{
1588 return wxT("libmp3lame.so.0");
1589}
1590
1592{
1593 return {
1594 { XO("Only libmp3lame.so.0"), { wxT("libmp3lame.so.0") } },
1595 { XO("Primary shared object files"), { wxT("so") }, true },
1596 { XO("Extended libraries"), { wxT("so*") }, true },
1598 };
1599}
1600#endif
1601
1602#if 0
1603// Debug routine from BladeMP3EncDLL.c in the libmp3lame distro
1604static void dump_config( lame_global_flags* gfp )
1605{
1606 wxPrintf(wxT("\n\nLame_enc configuration options:\n"));
1607 wxPrintf(wxT("==========================================================\n"));
1608
1609 wxPrintf(wxT("version =%d\n"),lame_get_version( gfp ) );
1610 wxPrintf(wxT("Layer =3\n"));
1611 wxPrintf(wxT("mode ="));
1612 switch ( lame_get_mode( gfp ) )
1613 {
1614 case STEREO: wxPrintf(wxT( "Stereo\n" )); break;
1615 case JOINT_STEREO: wxPrintf(wxT( "Joint-Stereo\n" )); break;
1616 case DUAL_CHANNEL: wxPrintf(wxT( "Forced Stereo\n" )); break;
1617 case MONO: wxPrintf(wxT( "Mono\n" )); break;
1618 case NOT_SET: /* FALLTHROUGH */
1619 default: wxPrintf(wxT( "Error (unknown)\n" )); break;
1620 }
1621
1622 wxPrintf(wxT("Input sample rate =%.1f kHz\n"), lame_get_in_samplerate( gfp ) /1000.0 );
1623 wxPrintf(wxT("Output sample rate =%.1f kHz\n"), lame_get_out_samplerate( gfp ) /1000.0 );
1624
1625 wxPrintf(wxT("bitrate =%d kbps\n"), lame_get_brate( gfp ) );
1626 wxPrintf(wxT("Quality Setting =%d\n"), lame_get_quality( gfp ) );
1627
1628 wxPrintf(wxT("Low pass frequency =%d\n"), lame_get_lowpassfreq( gfp ) );
1629 wxPrintf(wxT("Low pass width =%d\n"), lame_get_lowpasswidth( gfp ) );
1630
1631 wxPrintf(wxT("High pass frequency =%d\n"), lame_get_highpassfreq( gfp ) );
1632 wxPrintf(wxT("High pass width =%d\n"), lame_get_highpasswidth( gfp ) );
1633
1634 wxPrintf(wxT("No short blocks =%d\n"), lame_get_no_short_blocks( gfp ) );
1635 wxPrintf(wxT("Force short blocks =%d\n"), lame_get_force_short_blocks( gfp ) );
1636
1637 wxPrintf(wxT("de-emphasis =%d\n"), lame_get_emphasis( gfp ) );
1638 wxPrintf(wxT("private flag =%d\n"), lame_get_extension( gfp ) );
1639
1640 wxPrintf(wxT("copyright flag =%d\n"), lame_get_copyright( gfp ) );
1641 wxPrintf(wxT("original flag =%d\n"), lame_get_original( gfp ) );
1642 wxPrintf(wxT("CRC =%s\n"), lame_get_error_protection( gfp ) ? wxT("on") : wxT("off") );
1643 wxPrintf(wxT("Fast mode =%s\n"), ( lame_get_quality( gfp ) )? wxT("enabled") : wxT("disabled") );
1644 wxPrintf(wxT("Force mid/side stereo =%s\n"), ( lame_get_force_ms( gfp ) )?wxT("enabled"):wxT("disabled") );
1645 wxPrintf(wxT("Padding Type =%d\n"), (int) lame_get_padding_type( gfp ) );
1646 wxPrintf(wxT("Disable Reservoir =%d\n"), lame_get_disable_reservoir( gfp ) );
1647 wxPrintf(wxT("Allow diff-short =%d\n"), lame_get_allow_diff_short( gfp ) );
1648 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
1649 wxPrintf(wxT("Strict ISO Encoding =%s\n"), ( lame_get_strict_ISO( gfp ) ) ?wxT("Yes"):wxT("No"));
1650 wxPrintf(wxT("Scale =%5.2f\n"), lame_get_scale( gfp ) );
1651
1652 wxPrintf(wxT("VBR =%s, VBR_q =%d, VBR method ="),
1653 ( lame_get_VBR( gfp ) !=vbr_off ) ? wxT("enabled"): wxT("disabled"),
1654 lame_get_VBR_q( gfp ) );
1655
1656 switch ( lame_get_VBR( gfp ) )
1657 {
1658 case vbr_off: wxPrintf(wxT( "vbr_off\n" )); break;
1659 case vbr_mt : wxPrintf(wxT( "vbr_mt \n" )); break;
1660 case vbr_rh : wxPrintf(wxT( "vbr_rh \n" )); break;
1661 case vbr_mtrh: wxPrintf(wxT( "vbr_mtrh \n" )); break;
1662 case vbr_abr:
1663 wxPrintf(wxT( "vbr_abr (average bitrate %d kbps)\n"), lame_get_VBR_mean_bitrate_kbps( gfp ) );
1664 break;
1665 default:
1666 wxPrintf(wxT("error, unknown VBR setting\n"));
1667 break;
1668 }
1669
1670 wxPrintf(wxT("Vbr Min bitrate =%d kbps\n"), lame_get_VBR_min_bitrate_kbps( gfp ) );
1671 wxPrintf(wxT("Vbr Max bitrate =%d kbps\n"), lame_get_VBR_max_bitrate_kbps( gfp ) );
1672
1673 wxPrintf(wxT("Write VBR Header =%s\n"), ( lame_get_bWriteVbrTag( gfp ) ) ?wxT("Yes"):wxT("No"));
1674 wxPrintf(wxT("VBR Hard min =%d\n"), lame_get_VBR_hard_min( gfp ) );
1675
1676 wxPrintf(wxT("ATH Only =%d\n"), lame_get_ATHonly( gfp ) );
1677 wxPrintf(wxT("ATH short =%d\n"), lame_get_ATHshort( gfp ) );
1678 wxPrintf(wxT("ATH no =%d\n"), lame_get_noATH( gfp ) );
1679 wxPrintf(wxT("ATH type =%d\n"), lame_get_ATHtype( gfp ) );
1680 wxPrintf(wxT("ATH lower =%f\n"), lame_get_ATHlower( gfp ) );
1681 wxPrintf(wxT("ATH aa =%d\n"), lame_get_athaa_type( gfp ) );
1682 wxPrintf(wxT("ATH aa loudapprox =%d\n"), lame_get_athaa_loudapprox( gfp ) );
1683 wxPrintf(wxT("ATH aa sensitivity =%f\n"), lame_get_athaa_sensitivity( gfp ) );
1684
1685 wxPrintf(wxT("Experimental nspsytune =%d\n"), lame_get_exp_nspsytune( gfp ) );
1686 wxPrintf(wxT("Experimental X =%d\n"), lame_get_experimentalX( gfp ) );
1687 wxPrintf(wxT("Experimental Y =%d\n"), lame_get_experimentalY( gfp ) );
1688 wxPrintf(wxT("Experimental Z =%d\n"), lame_get_experimentalZ( gfp ) );
1689}
1690#endif
1691
1692//----------------------------------------------------------------------------
1693// ExportMP3
1694//----------------------------------------------------------------------------
1695
1696class ExportMP3 final : public ExportPlugin
1697{
1698public:
1699
1700 ExportMP3();
1701 bool CheckFileName(wxFileName & filename, int format) override;
1702
1703 // Required
1704
1705 void OptionsCreate(ShuttleGui &S, int format) override;
1707 std::unique_ptr<BasicUI::ProgressDialog> &pDialog,
1708 unsigned channels,
1709 const wxFileNameWrapper &fName,
1710 bool selectedOnly,
1711 double t0,
1712 double t1,
1713 MixerSpec *mixerSpec = NULL,
1714 const Tags *metadata = NULL,
1715 int subformat = 0) override;
1716
1717private:
1718
1719 int AskResample(int bitrate, int rate, int lowrate, int highrate);
1720 unsigned long AddTags(AudacityProject *project, ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags);
1721#ifdef USE_LIBID3TAG
1722 void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
1723#endif
1724 int SetNumExportChannels() override;
1725};
1726
1728: ExportPlugin()
1729{
1730 AddFormat();
1731 SetFormat(wxT("MP3"),0);
1732 AddExtension(wxT("mp3"),0);
1733 SetMaxChannels(2,0);
1734 SetCanMetaData(true,0);
1735 SetDescription(XO("MP3 Files"),0);
1736}
1737
1738bool ExportMP3::CheckFileName(wxFileName & WXUNUSED(filename), int WXUNUSED(format))
1739{
1740#ifndef DISABLE_DYNAMIC_LOADING_LAME
1741 MP3Exporter exporter;
1742
1743 if (!exporter.LoadLibrary(wxTheApp->GetTopWindow(), MP3Exporter::Maybe)) {
1744 AudacityMessageBox( XO("Could not open MP3 encoding library!") );
1745 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1746 gPrefs->Flush();
1747
1748 return false;
1749 }
1750#endif // DISABLE_DYNAMIC_LOADING_LAME
1751
1752 return true;
1753}
1754
1756{
1757 bool mono;
1758 gPrefs->Read(wxT("/FileFormats/MP3ForceMono"), &mono, 0);
1759
1760 return (mono)? 1 : -1;
1761}
1762
1763
1765 std::unique_ptr<BasicUI::ProgressDialog> &pDialog,
1766 unsigned channels,
1767 const wxFileNameWrapper &fName,
1768 bool selectionOnly,
1769 double t0,
1770 double t1,
1771 MixerSpec *mixerSpec,
1772 const Tags *metadata,
1773 int WXUNUSED(subformat))
1774{
1775 int rate = lrint( ProjectRate::Get( *project ).GetRate());
1776#ifndef DISABLE_DYNAMIC_LOADING_LAME
1777 wxWindow *parent = ProjectWindow::Find( project );
1778#endif // DISABLE_DYNAMIC_LOADING_LAME
1779 const auto &tracks = TrackList::Get( *project );
1780 MP3Exporter exporter;
1781
1782#ifdef DISABLE_DYNAMIC_LOADING_LAME
1783 if (!exporter.InitLibrary(wxT(""))) {
1784 AudacityMessageBox( XO("Could not initialize MP3 encoding library!") );
1785 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1786 gPrefs->Flush();
1787
1789 }
1790#else
1791 if (!exporter.LoadLibrary(parent, MP3Exporter::Maybe)) {
1792 AudacityMessageBox( XO("Could not open MP3 encoding library!") );
1793 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1794 gPrefs->Flush();
1795
1797 }
1798
1799 if (!exporter.ValidLibraryLoaded()) {
1800 AudacityMessageBox( XO("Not a valid or supported MP3 encoding library!") );
1801 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1802 gPrefs->Flush();
1803
1805 }
1806#endif // DISABLE_DYNAMIC_LOADING_LAME
1807
1808 // Retrieve preferences
1809 int highrate = 48000;
1810 int lowrate = 8000;
1811 int bitrate = 0;
1812 int brate;
1813 //int vmode;
1814 bool forceMono;
1815
1816 gPrefs->Read(wxT("/FileFormats/MP3Bitrate"), &brate, 128);
1817 auto rmode = MP3RateModeSetting.ReadEnumWithDefault( MODE_CBR );
1818 //gPrefs->Read(wxT("/FileFormats/MP3VarMode"), &vmode, ROUTINE_FAST);
1819 auto cmode = MP3ChannelModeSetting.ReadEnumWithDefault( CHANNEL_STEREO );
1820 gPrefs->Read(wxT("/FileFormats/MP3ForceMono"), &forceMono, 0);
1821
1822 // Set the bitrate/quality and mode
1823 if (rmode == MODE_SET) {
1824 brate = ValidateValue(setRateNames.size(), brate, PRESET_STANDARD);
1825 //int r = ValidateValue( varModeNames.size(), vmode, ROUTINE_FAST );
1826 exporter.SetMode(MODE_SET);
1827 exporter.SetQuality(brate/*, r*/);
1828 }
1829 else if (rmode == MODE_VBR) {
1830 brate = ValidateValue( varRateNames.size(), brate, QUALITY_2 );
1831 //int r = ValidateValue( varModeNames.size(), vmode, ROUTINE_FAST );
1832 exporter.SetMode(MODE_VBR);
1833 exporter.SetQuality(brate/*, r*/);
1834 }
1835 else if (rmode == MODE_ABR) {
1836 brate = ValidateIndex( fixRateValues, brate, 6 /* 128 kbps */ );
1837 bitrate = fixRateValues[ brate ];
1838 exporter.SetMode(MODE_ABR);
1839 exporter.SetBitrate(bitrate);
1840 if (bitrate > 160) {
1841 lowrate = 32000;
1842 }
1843 else if (bitrate < 32 || bitrate == 144) {
1844 highrate = 24000;
1845 }
1846 }
1847 else {
1848 brate = ValidateIndex( fixRateValues, brate, 6 /* 128 kbps */ );
1849 bitrate = fixRateValues[ brate ];
1850 exporter.SetMode(MODE_CBR);
1851 exporter.SetBitrate(bitrate);
1852
1853 if (bitrate > 160) {
1854 lowrate = 32000;
1855 }
1856 else if (bitrate < 32 || bitrate == 144) {
1857 highrate = 24000;
1858 }
1859 }
1860
1861 // Verify sample rate
1862 if (!make_iterator_range( sampRates ).contains( rate ) ||
1863 (rate < lowrate) || (rate > highrate)) {
1864 // Force valid sample rate in macros.
1865 if (project->mBatchMode) {
1866 if (!make_iterator_range( sampRates ).contains( rate )) {
1867 auto const bestRateIt = std::lower_bound(sampRates.begin(),
1868 sampRates.end(), rate);
1869 rate = (bestRateIt == sampRates.end()) ? highrate : *bestRateIt;
1870 }
1871 if (rate < lowrate) {
1872 rate = lowrate;
1873 }
1874 else if (rate > highrate) {
1875 rate = highrate;
1876 }
1877 }
1878 // else validate or prompt
1879 else {
1880 if (!make_iterator_range( sampRates ).contains( rate ) ||
1881 (rate < lowrate) || (rate > highrate)) {
1882 rate = AskResample(bitrate, rate, lowrate, highrate);
1883 }
1884 if (rate == 0) {
1886
1887 }
1888 }
1889 }
1890
1891 // Set the channel mode
1892 if (forceMono) {
1893 exporter.SetChannel(CHANNEL_MONO);
1894 }
1895 else if (cmode == CHANNEL_JOINT) {
1896 exporter.SetChannel(CHANNEL_JOINT);
1897 }
1898 else {
1899 exporter.SetChannel(CHANNEL_STEREO);
1900 }
1901
1902 auto inSamples = exporter.InitializeStream(channels, rate);
1903 if (((int)inSamples) < 0) {
1904 AudacityMessageBox( XO("Unable to initialize MP3 stream") );
1906 }
1907
1908 // Put ID3 tags at beginning of file
1909 if (metadata == NULL)
1910 metadata = &Tags::Get( *project );
1911
1912 // Open file for writing
1913 wxFFile outFile(fName.GetFullPath(), wxT("w+b"));
1914 if (!outFile.IsOpened()) {
1915 AudacityMessageBox( XO("Unable to open target file for writing") );
1917 }
1918
1919 ArrayOf<char> id3buffer;
1920 bool endOfFile;
1921 unsigned long id3len = AddTags(project, id3buffer, &endOfFile, metadata);
1922 if (id3len && !endOfFile) {
1923 if (id3len > outFile.Write(id3buffer.get(), id3len)) {
1924 // TODO: more precise message
1925 ShowExportErrorDialog("MP3:1882");
1927 }
1928 }
1929
1930 wxFileOffset pos = outFile.Tell();
1931 auto updateResult = ProgressResult::Success;
1932 int bytes = 0;
1933
1934 size_t bufferSize = std::max(0, exporter.GetOutBufferSize());
1935 if (bufferSize <= 0) {
1936 // TODO: more precise message
1937 ShowExportErrorDialog("MP3:1849");
1939 }
1940
1941 ArrayOf<unsigned char> buffer{ bufferSize };
1942 wxASSERT(buffer);
1943
1944 {
1945 auto mixer = CreateMixer(tracks, selectionOnly,
1946 t0, t1,
1947 channels, inSamples, true,
1948 rate, floatSample, mixerSpec);
1949
1951 if (rmode == MODE_SET) {
1952 title = (selectionOnly ?
1953 XO("Exporting selected audio with %s preset") :
1954 XO("Exporting the audio with %s preset"))
1955 .Format( setRateNamesShort[brate] );
1956 }
1957 else if (rmode == MODE_VBR) {
1958 title = (selectionOnly ?
1959 XO("Exporting selected audio with VBR quality %s") :
1960 XO("Exporting the audio with VBR quality %s"))
1961 .Format( varRateNames[brate] );
1962 }
1963 else {
1964 title = (selectionOnly ?
1965 XO("Exporting selected audio at %d Kbps") :
1966 XO("Exporting the audio at %d Kbps"))
1967 .Format( bitrate );
1968 }
1969
1970 InitProgress( pDialog, fName, title );
1971 auto &progress = *pDialog;
1972
1973 while (updateResult == ProgressResult::Success) {
1974 auto blockLen = mixer->Process();
1975 if (blockLen == 0)
1976 break;
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.Poll(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
wxT("CloseDown"))
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:1538
void ShowDiskFullExportErrorDialog(const wxFileNameWrapper &fileName)
Definition: Export.cpp:1551
int lame_set_VBR_t(lame_global_flags *, vbr_mode)
Definition: ExportMP3.cpp:751
#define ID_VBR
Definition: ExportMP3.cpp:221
int lame_set_bWriteVbrTag_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:758
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:732
static const TranslatableStrings varRateNames
Definition: ExportMP3.cpp:174
#define ID_DLOAD
Definition: ExportMP3.cpp:585
static const TranslatableStrings fixRateNames
Definition: ExportMP3.cpp:132
const char * get_lame_version_t(void)
Definition: ExportMP3.cpp:722
int lame_set_VBR_q_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:752
static const std::vector< int > fixRateValues
Definition: ExportMP3.cpp:153
int lame_set_in_samplerate_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:746
int lame_close_t(lame_global_flags *)
Definition: ExportMP3.cpp:744
#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
@ 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
static Exporter::RegisteredExportPlugin sRegisteredPlugin
Definition: ExportMP3.cpp:2247
void lame_mp3_tags_fid_t(lame_global_flags *, FILE *)
Definition: ExportMP3.cpp:760
int lame_set_VBR_min_bitrate_kbps_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:753
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:724
int lame_set_error_protection_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:756
static EnumSetting< MP3ChannelMode > MP3ChannelModeSetting
Definition: ExportMP3.cpp:314
unsigned long beWriteInfoTag_t(lame_global_flags *, char *)
Definition: ExportMP3.cpp:768
static const TranslatableStrings setRateNames
Definition: ExportMP3.cpp:192
int lame_set_out_samplerate_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:747
int lame_set_quality_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:749
#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:800
int lame_set_preset_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:755
#define ID_BROWSE
Definition: ExportMP3.cpp:584
size_t lame_get_lametag_frame_t(const lame_global_flags *, unsigned char *buffer, size_t size)
Definition: ExportMP3.cpp:759
#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:757
lame_global_flags * lame_init_t(void)
Definition: ExportMP3.cpp:720
int lame_encode_flush_t(lame_global_flags *gf, unsigned char *mp3buf, int size)
Definition: ExportMP3.cpp:739
int lame_set_num_channels_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:748
int lame_set_mode_t(lame_global_flags *, MPEG_mode)
Definition: ExportMP3.cpp:754
int lame_set_brate_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:750
int lame_init_params_t(lame_global_flags *)
Definition: ExportMP3.cpp:721
@ 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:431
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:507
int SetNumExportChannels() override
Exporter plug-ins may override this to specify the number of channels in exported file....
Definition: ExportMP3.cpp:1755
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:1738
int AskResample(int bitrate, int rate, int lowrate, int highrate)
Definition: ExportMP3.cpp:2066
ProgressResult Export(AudacityProject *project, std::unique_ptr< BasicUI::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:1764
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:513
wxRadioButton * mABR
Definition: ExportMP3.cpp:254
bool TransferDataToWindow() override
Definition: ExportMP3.cpp:458
wxRadioButton * mVBR
Definition: ExportMP3.cpp:253
wxRadioButton * mStereo
Definition: ExportMP3.cpp:249
bool TransferDataFromWindow() override
Definition: ExportMP3.cpp:463
wxChoice * mRate
Definition: ExportMP3.cpp:256
wxRadioButton * mSET
Definition: ExportMP3.cpp:252
void OnABR(wxCommandEvent &evt)
Definition: ExportMP3.cpp:524
void OnSET(wxCommandEvent &evt)
Definition: ExportMP3.cpp:502
void PopulateOrExchange(ShuttleGui &S)
Definition: ExportMP3.cpp:331
wxRadioButton * mCBR
Definition: ExportMP3.cpp:255
void OnCBR(wxCommandEvent &evt)
Definition: ExportMP3.cpp:535
void OnQuality(wxCommandEvent &evt)
Definition: ExportMP3.cpp:544
void LoadNames(const TranslatableStrings &choices)
Definition: ExportMP3.cpp:573
void OnMono(wxCommandEvent &evt)
Definition: ExportMP3.cpp:562
wxCheckBox * mMono
Definition: ExportMP3.cpp:251
wxRadioButton * mJoint
Definition: ExportMP3.cpp:250
void AddExtension(const FileExtension &extension, int index)
Definition: Export.cpp:128
int AddFormat()
Add a NEW entry to the list of formats this plug-in can export.
Definition: Export.cpp:102
static void InitProgress(std::unique_ptr< BasicUI::ProgressDialog > &pDialog, const TranslatableString &title, const TranslatableString &message)
Definition: Export.cpp:252
void SetFormat(const wxString &format, int index)
Definition: Export.cpp:118
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:224
void SetDescription(const TranslatableString &description, int index)
Definition: Export.cpp:123
void SetCanMetaData(bool canmetadata, int index)
Definition: Export.cpp:148
void SetMaxChannels(unsigned maxchannels, unsigned index)
Definition: Export.cpp:143
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:702
void OnBrowse(wxCommandEvent &WXUNUSED(event))
Definition: ExportMP3.cpp:659
wxFileName mLibPath
Definition: ExportMP3.cpp:695
wxString GetLibPath()
Definition: ExportMP3.cpp:685
FindDialog(wxWindow *parent, wxString path, wxString name, FileNames::FileTypes types)
Definition: ExportMP3.cpp:593
FileNames::FileTypes mTypes
Definition: ExportMP3.cpp:699
wxString mPath
Definition: ExportMP3.cpp:697
void PopulateOrExchange(ShuttleGui &S)
Definition: ExportMP3.cpp:611
void OnDownload(wxCommandEvent &WXUNUSED(event))
Definition: ExportMP3.cpp:680
wxString mName
Definition: ExportMP3.cpp:698
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:239
Specialization of Setting for int.
Definition: Prefs.h:349
Class used to export MP3 files.
Definition: ExportMP3.cpp:804
lame_set_VBR_q_t * lame_set_VBR_q
Definition: ExportMP3.cpp:898
static const int mOutBufferSize
Definition: ExportMP3.cpp:918
lame_set_in_samplerate_t * lame_set_in_samplerate
Definition: ExportMP3.cpp:892
wxString GetLibraryVersion()
Definition: ExportMP3.cpp:1279
bool InitLibraryExternal(wxString libpath)
Definition: ExportMP3.cpp:1148
int EncodeBufferMono(float inbuffer[], unsigned char outbuffer[])
Definition: ExportMP3.cpp:1421
lame_set_disable_reservoir_t * lame_set_disable_reservoir
Definition: ExportMP3.cpp:903
int EncodeRemainderMono(float inbuffer[], int nSamples, unsigned char outbuffer[])
Definition: ExportMP3.cpp:1431
bool mLibIsExternal
Definition: ExportMP3.cpp:863
int GetOutBufferSize()
Definition: ExportMP3.cpp:1392
bool PutInfoTag(wxFFile &f, wxFileOffset off)
Definition: ExportMP3.cpp:1468
lame_mp3_tags_fid_t * lame_mp3_tags_fid
Definition: ExportMP3.cpp:906
unsigned char mInfoTagBuf[2880]
Definition: ExportMP3.cpp:922
void SetBitrate(int rate)
Definition: ExportMP3.cpp:1075
size_t mInfoTagLen
Definition: ExportMP3.cpp:923
lame_init_t * lame_init
Definition: ExportMP3.cpp:884
bool ValidLibraryLoaded()
Definition: ExportMP3.cpp:1063
lame_set_brate_t * lame_set_brate
Definition: ExportMP3.cpp:896
lame_encode_buffer_ieee_float_t * lame_encode_buffer_ieee_float
Definition: ExportMP3.cpp:886
lame_encode_buffer_interleaved_ieee_float_t * lame_encode_buffer_interleaved_ieee_float
Definition: ExportMP3.cpp:887
bool mEncoding
Definition: ExportMP3.cpp:875
lame_get_lametag_frame_t * lame_get_lametag_frame
Definition: ExportMP3.cpp:905
lame_set_num_channels_t * lame_set_num_channels
Definition: ExportMP3.cpp:894
void FreeLibrary()
Definition: ExportMP3.cpp:1265
int EncodeBuffer(float inbuffer[], unsigned char outbuffer[])
Definition: ExportMP3.cpp:1400
get_lame_version_t * get_lame_version
Definition: ExportMP3.cpp:890
static const int mSamplesPerChunk
Definition: ExportMP3.cpp:915
bool FindLibrary(wxWindow *parent)
Definition: ExportMP3.cpp:965
void CancelEncoding()
Definition: ExportMP3.cpp:1463
bool LoadLibrary(wxWindow *parent, AskUser askuser)
Definition: ExportMP3.cpp:1000
wxString GetLibraryName()
Definition: ExportMP3.cpp:1519
lame_set_VBR_t * lame_set_VBR
Definition: ExportMP3.cpp:897
FileNames::FileTypes GetLibraryTypes()
Definition: ExportMP3.cpp:1524
void SetChannel(int mode)
Definition: ExportMP3.cpp:1086
wxDynamicLibrary lame_lib
Definition: ExportMP3.cpp:867
bool InitLibrary(wxString libpath)
Definition: ExportMP3.cpp:1091
lame_global_flags * mGF
Definition: ExportMP3.cpp:913
wxString GetLibraryPath()
Definition: ExportMP3.cpp:1501
lame_close_t * lame_close
Definition: ExportMP3.cpp:889
int FinishStream(unsigned char outbuffer[])
Definition: ExportMP3.cpp:1442
lame_set_quality_t * lame_set_quality
Definition: ExportMP3.cpp:895
wxString mLibPath
Definition: ExportMP3.cpp:866
beWriteInfoTag_t * beWriteInfoTag
Definition: ExportMP3.cpp:908
lame_encode_flush_t * lame_encode_flush
Definition: ExportMP3.cpp:888
void SetMode(int mode)
Definition: ExportMP3.cpp:1070
int InitializeStream(unsigned channels, int sampleRate)
Definition: ExportMP3.cpp:1290
lame_set_error_protection_t * lame_set_error_protection
Definition: ExportMP3.cpp:902
lame_set_VBR_min_bitrate_kbps_t * lame_set_VBR_min_bitrate_kbps
Definition: ExportMP3.cpp:899
void SetQuality(int q)
Definition: ExportMP3.cpp:1080
bool InitLibraryInternal()
Definition: ExportMP3.cpp:1096
int EncodeRemainder(float inbuffer[], int nSamples, unsigned char outbuffer[])
Definition: ExportMP3.cpp:1410
lame_set_out_samplerate_t * lame_set_out_samplerate
Definition: ExportMP3.cpp:893
lame_set_mode_t * lame_set_mode
Definition: ExportMP3.cpp:900
TranslatableString mBladeVersion
Definition: ExportMP3.cpp:872
lame_set_bWriteVbrTag_t * lame_set_bWriteVbrTag
Definition: ExportMP3.cpp:904
lame_init_params_t * lame_init_params
Definition: ExportMP3.cpp:885
bool mLibraryLoaded
Definition: ExportMP3.cpp:868
beVersion_t * beVersion
Definition: ExportMP3.cpp:909
lame_set_preset_t * lame_set_preset
Definition: ExportMP3.cpp:901
A matrix of booleans, one row per input channel, column per output.
Definition: MixerOptions.h:32
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
double GetRate() const
Definition: ProjectRate.cpp:53
static ProjectWindow * Find(AudacityProject *pProject)
Definition: Prefs.h:173
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:628
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:486
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:491
int ValidateValue(const std::vector< int > &values, int value, int defaultValue)
Definition: ExportMP3.cpp:484
BYTE byMinorVersion
Definition: ExportMP3.cpp:782
BYTE byDLLMinorVersion
Definition: ExportMP3.cpp:777
BYTE byBetaLevel
Definition: ExportMP3.cpp:795
BYTE byMMXEnabled
Definition: ExportMP3.cpp:796
BYTE byMajorVersion
Definition: ExportMP3.cpp:781
BYTE byAlphaLevel
Definition: ExportMP3.cpp:794
BYTE byDLLMajorVersion
Definition: ExportMP3.cpp:776
BYTE byMonth
Definition: ExportMP3.cpp:787