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