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/dynlib.h>
69#include <wx/ffile.h>
70#include <wx/log.h>
71#include <wx/mimetype.h>
72
73#include <wx/textctrl.h>
74#include <wx/choice.h>
75
76#include "FileNames.h"
77#include "float_cast.h"
78#include "Mix.h"
79#include "Prefs.h"
80#include "Tags.h"
81#include "Track.h"
82#include "HelpSystem.h"
83#include "wxFileNameWrapper.h"
84#include "Project.h"
85
86#include "Export.h"
87#include "BasicUI.h"
88
89#include <lame/lame.h>
90
91#ifdef USE_LIBID3TAG
92#include <id3tag.h>
93#endif
94
95#include "ExportOptionsEditor.h"
96#include "ExportPluginHelpers.h"
98#include "SelectFile.h"
99#include "ShuttleGui.h"
100#include "ProjectWindow.h"
101
102//----------------------------------------------------------------------------
103// ExportMP3Options
104//----------------------------------------------------------------------------
105
106enum : int {
108
109 //ROUTINE_FAST = 0,
110 //ROUTINE_STANDARD = 1,
111
116};
117
118/* i18n-hint: kbps is the bitrate of the MP3 file, kilobits per second*/
119inline TranslatableString n_kbps( int n ){ return XO("%d kbps").Format( n ); }
120
122 n_kbps(320),
123 n_kbps(256),
124 n_kbps(224),
125 n_kbps(192),
126 n_kbps(160),
127 n_kbps(144),
128 n_kbps(128),
129 n_kbps(112),
130 n_kbps(96),
131 n_kbps(80),
132 n_kbps(64),
133 n_kbps(56),
134 n_kbps(48),
135 n_kbps(40),
136 n_kbps(32),
137 n_kbps(24),
138 n_kbps(16),
139 n_kbps(8),
140};
141
142static const std::vector<ExportValue> fixRateValues {
143 320,
144 256,
145 224,
146 192,
147 160,
148 144,
149 128,
150 112,
151 96,
152 80,
153 64,
154 56,
155 48,
156 40,
157 32,
158 24,
159 16,
160 8,
161};
162
164 XO("220-260 kbps (Best Quality)"),
165 XO("200-250 kbps"),
166 XO("170-210 kbps"),
167 XO("155-195 kbps"),
168 XO("145-185 kbps"),
169 XO("110-150 kbps"),
170 XO("95-135 kbps"),
171 XO("80-120 kbps"),
172 XO("65-105 kbps"),
173 XO("45-85 kbps (Smaller files)"),
174};
175/*
176static const TranslatableStrings varModeNames {
177 XO("Fast"),
178 XO("Standard"),
179};
180*/
182 /* i18n-hint: Slightly humorous - as in use an insane precision with MP3.*/
183 XO("Insane, 320 kbps"),
184 XO("Extreme, 220-260 kbps"),
185 XO("Standard, 170-210 kbps"),
186 XO("Medium, 145-185 kbps"),
187};
188
190 /* i18n-hint: Slightly humorous - as in use an insane precision with MP3.*/
191 XO("Insane"),
192 XO("Extreme"),
193 XO("Standard"),
194 XO("Medium"),
195};
196
197static const std::vector< int > sampRates {
198 8000,
199 11025,
200 12000,
201 16000,
202 22050,
203 24000,
204 32000,
205 44100,
206 48000,
207};
208
209enum MP3OptionID : int {
216
217//Option order should exactly match to the id values
218const std::initializer_list<ExportOption> MP3Options {
219 {
220 MP3OptionIDMode, XO("Bit Rate Mode"),
221 std::string("SET"),
223 {
224 // for migrating old preferences the
225 // order should be preserved
226 std::string("SET"),
227 std::string("VBR"),
228 std::string("ABR"),
229 std::string("CBR")
230 },
231 {
232 XO("Preset"),
233 XO("Variable"),
234 XO("Average"),
235 XO("Constant")
236 }
237 },
238 {
239 MP3OptionIDQualitySET, XO("Quality"),
242 { 0, 1, 2, 3 },
244 },
245 {
246 MP3OptionIDQualityVBR, XO("Quality"),
247 QUALITY_2,
249 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
251 },
252 {
253 MP3OptionIDQualityABR, XO("Quality"),
254 192,
258 },
259 {
260 MP3OptionIDQualityCBR, XO("Quality"),
261 192,
265 }
266};
267
269{
270 std::vector<ExportOption> mOptions;
271 std::unordered_map<int, ExportValue> mValues;
273public:
274
277 , mListener(listener)
278 {
279 mValues.reserve(mOptions.size());
280 for(auto& option : mOptions)
281 mValues[option.id] = option.defaultValue;
282 }
283
284 int GetOptionsCount() const override
285 {
286 return static_cast<int>(mOptions.size());
287 }
288
289 bool GetOption(int index, ExportOption& option) const override
290 {
291 if(index >= 0 && index < static_cast<int>(mOptions.size()))
292 {
293 option = mOptions[index];
294 return true;
295 }
296 return false;
297 }
298
299 bool SetValue(int id, const ExportValue& value) override
300 {
301 const auto it = mValues.find(id);
302 if(it == mValues.end())
303 return false;
304 if(value.index() != it->second.index())
305 return false;
306
307 it->second = value;
308
309 switch(id)
310 {
311 case MP3OptionIDMode:
312 {
313 const auto mode = *std::get_if<std::string>(&value);
314 OnModeChange(mode);
315 if(mListener)
316 {
323
325 }
326 } break;
331 {
332 if(mListener)
334 } break;
335 default: break;
336 }
337 return true;
338 }
339
340 bool GetValue(int id, ExportValue& value) const override
341 {
342 const auto it = mValues.find(id);
343 if(it != mValues.end())
344 {
345 value = it->second;
346 return true;
347 }
348 return false;
349 }
350
352 {
353 // Retrieve preferences
354 int highrate = 48000;
355 int lowrate = 8000;
356
357 const auto rmode = *std::get_if<std::string>(&mValues.find(MP3OptionIDMode)->second);
358
359 if (rmode == "ABR") {
360 auto bitrate = *std::get_if<int>(&mValues.find(MP3OptionIDQualityABR)->second);
361 if (bitrate > 160) {
362 lowrate = 32000;
363 }
364 else if (bitrate < 32 || bitrate == 144) {
365 highrate = 24000;
366 }
367 }
368 else if (rmode == "CBR") {
369 auto bitrate = *std::get_if<int>(&mValues.find(MP3OptionIDQualityCBR)->second);
370
371 if (bitrate > 160) {
372 lowrate = 32000;
373 }
374 else if (bitrate < 32 || bitrate == 144) {
375 highrate = 24000;
376 }
377 }
378
379 SampleRateList result;
380 result.reserve(sampRates.size());
381 for(auto rate : sampRates)
382 if(rate >= lowrate && rate <= highrate)
383 result.push_back(rate);
384
385 return result;
386 }
387
388 void Load(const audacity::BasicSettings& config) override
389 {
390 wxString mode;
391 if(config.Read(wxT("/FileFormats/MP3RateModeChoice"), &mode))
392 mValues[MP3OptionIDMode] = mode.ToStdString();
393 else
394 {
395 //attempt to recover from old-style preference
396 int index;
397 if(config.Read(wxT("/FileFormats/MP3RateMode"), &index))
399 }
400
401 config.Read(wxT("/FileFormats/MP3SetRate"), std::get_if<int>(&mValues[MP3OptionIDQualitySET]));
402 config.Read(wxT("/FileFormats/MP3AbrRate"), std::get_if<int>(&mValues[MP3OptionIDQualityABR]));
403 config.Read(wxT("/FileFormats/MP3CbrRate"), std::get_if<int>(&mValues[MP3OptionIDQualityCBR]));
404 config.Read(wxT("/FileFormats/MP3VbrRate"), std::get_if<int>(&mValues[MP3OptionIDQualityVBR]));
405
406 OnModeChange(*std::get_if<std::string>(&mValues[MP3OptionIDMode]));
407 }
408
409 void Store(audacity::BasicSettings& config) const override
410 {
411 auto it = mValues.find(MP3OptionIDMode);
412 config.Write(wxT("/FileFormats/MP3RateModeChoice"), wxString(*std::get_if<std::string>(&it->second)));
413
415 config.Write(wxT("/FileFormats/MP3SetRate"), *std::get_if<int>(&it->second));
417 config.Write(wxT("/FileFormats/MP3AbrRate"), *std::get_if<int>(&it->second));
419 config.Write(wxT("/FileFormats/MP3CbrRate"), *std::get_if<int>(&it->second));
421 config.Write(wxT("/FileFormats/MP3VbrRate"), *std::get_if<int>(&it->second));
422 }
423
424private:
425
426 void OnModeChange(const std::string& mode)
427 {
432
433 if(mode == "SET")
435 else if(mode == "ABR")
437 else if(mode == "CBR")
439 else if(mode == "VBR")
441 }
442};
443
444namespace {
445
446int ValidateValue( int nValues, int value, int defaultValue )
447{
448 return (value >= 0 && value < nValues) ? value : defaultValue;
449}
450
451int ValidateValue( const std::vector<int> &values, int value, int defaultValue )
452{
453 auto start = values.begin(), finish = values.end(),
454 iter = std::find( start, finish, value );
455 return ( iter != finish ) ? value : defaultValue;
456}
457
458int ValidateIndex( const std::vector<int> &values, int value, int defaultIndex )
459{
460 auto start = values.begin(), finish = values.end(),
461 iter = std::find( start, finish, value );
462 return ( iter != finish ) ? static_cast<int>( iter - start ) : defaultIndex;
463}
464
465}
466
467//----------------------------------------------------------------------------
468// FindDialog
469//----------------------------------------------------------------------------
470
471#define ID_BROWSE 5000
472#define ID_DLOAD 5001
473
474class FindDialog final : public wxDialogWrapper
475{
476public:
477
478#ifndef DISABLE_DYNAMIC_LOADING_LAME
479
480 FindDialog(wxWindow *parent, wxString path, wxString name,
482 : wxDialogWrapper(parent, wxID_ANY,
483 /* i18n-hint: LAME is the name of an MP3 converter and should not be translated*/
484 XO("Locate LAME"))
485 {
486 SetName();
487 ShuttleGui S(this, eIsCreating);
488
489 mPath = path;
490 mName = name;
491 mTypes = std::move( types );
492
493 mLibPath.Assign(mPath, mName);
494
496 }
497
499 {
500 S.SetBorder(10);
501 S.StartVerticalLay(true);
502 {
503 S.AddTitle(
504 XO("Audacity needs the file %s to create MP3s.")
505 .Format( mName ) );
506
507 S.SetBorder(3);
508 S.StartHorizontalLay(wxALIGN_LEFT, true);
509 {
510 S.AddTitle( XO("Location of %s:").Format( mName ) );
511 }
512 S.EndHorizontalLay();
513
514 S.StartMultiColumn(2, wxEXPAND);
515 S.SetStretchyCol(0);
516 {
517 if (mLibPath.GetFullPath().empty()) {
518 mPathText = S.AddTextBox( {},
519 /* i18n-hint: There is a button to the right of the arrow.*/
520 wxString::Format(_("To find %s, click here -->"), mName), 0);
521 }
522 else {
523 mPathText = S.AddTextBox( {}, mLibPath.GetFullPath(), 0);
524 }
525 S.Id(ID_BROWSE).AddButton(XXO("Browse..."), wxALIGN_RIGHT);
526 S.AddVariableText(
527 /* i18n-hint: There is a button to the right of the arrow.*/
528 XO("To get a free copy of LAME, click here -->"), true);
529 /* i18n-hint: (verb)*/
530 S.Id(ID_DLOAD).AddButton(XXO("Download"), wxALIGN_RIGHT);
531 }
532 S.EndMultiColumn();
533
534 S.AddStandardButtons();
535 }
536 S.EndVerticalLay();
537
538 Layout();
539 Fit();
540 SetMinSize(GetSize());
541 Center();
542
543 return;
544 }
545
546 void OnBrowse(wxCommandEvent & WXUNUSED(event))
547 {
548 /* i18n-hint: It's asking for the location of a file, for
549 * example, "Where is lame_enc.dll?" - you could translate
550 * "Where would I find the file %s" instead if you want. */
551 auto question = XO("Where is %s?").Format( mName );
552
553 wxString path = SelectFile(FileNames::Operation::_None,
554 question,
555 mLibPath.GetPath(),
556 mLibPath.GetName(),
557 wxT(""),
558 mTypes,
559 wxFD_OPEN | wxRESIZE_BORDER,
560 this);
561 if (!path.empty()) {
562 mLibPath = path;
563 mPathText->SetValue(path);
564 }
565 }
566
567 void OnDownload(wxCommandEvent & WXUNUSED(event))
568 {
569 HelpSystem::ShowHelp(this, L"FAQ:Installing_the_LAME_MP3_Encoder");
570 }
571
572 wxString GetLibPath()
573 {
574 return mLibPath.GetFullPath();
575 }
576
577#endif // DISABLE_DYNAMIC_LOADING_LAME
578
579private:
580
581#ifndef DISABLE_DYNAMIC_LOADING_LAME
582 wxFileName mLibPath;
583
584 wxString mPath;
585 wxString mName;
587#endif // DISABLE_DYNAMIC_LOADING_LAME
588
589 wxTextCtrl *mPathText;
590
591 DECLARE_EVENT_TABLE()
592};
593
594#ifndef DISABLE_DYNAMIC_LOADING_LAME
595BEGIN_EVENT_TABLE(FindDialog, wxDialogWrapper)
599#endif // DISABLE_DYNAMIC_LOADING_LAME
600
601//----------------------------------------------------------------------------
602// MP3Exporter
603//----------------------------------------------------------------------------
604
605#ifndef DISABLE_DYNAMIC_LOADING_LAME
606
609typedef const char* get_lame_version_t(void);
610
612 lame_t gfp,
613 const float pcm_l[],
614 const float pcm_r[],
615 const int nsamples,
616 unsigned char * mp3buf,
617 const int mp3buf_size);
618
620 lame_t gfp,
621 const float pcm[],
622 const int nsamples,
623 unsigned char * mp3buf,
624 const int mp3buf_size);
625
628 unsigned char* mp3buf,
629 int size );
630
632
638typedef int lame_set_VBR_t(lame_global_flags *, vbr_mode);
641typedef int lame_set_mode_t(lame_global_flags *, MPEG_mode);
646typedef size_t lame_get_lametag_frame_t(const lame_global_flags *, unsigned char* buffer, size_t size);
648
649#endif // DISABLE_DYNAMIC_LOADING_LAME
650
651#if defined(__WXMSW__)
652// An alternative solution to give Windows an additional chance of writing the tag before
653// falling bato to lame_mp3_tag_fid(). The latter can have DLL sharing issues when mixing
654// Debug/Release builds of Audacity and the lame DLL.
655typedef unsigned long beWriteInfoTag_t(lame_global_flags *, char *);
656
657// We use this to determine if the user has selected an older, Blade API only, lame_enc.dll
658// so we can be more specific about why their library isn't acceptable.
659typedef struct {
660
661 // BladeEnc DLL Version number
662
665
666 // BladeEnc Engine Version Number
667
670
671 // DLL Release date
672
673 BYTE byDay;
675 WORD wYear;
676
677 // BladeEnc Homepage URL
678
679 CHAR zHomepage[129];
680
684
685 BYTE btReserved[125];
686} be_version;
687typedef void beVersion_t(be_version *);
688#endif
689
691{
692public:
694 {
697 Yes
698 };
699
700 MP3Exporter();
701 ~MP3Exporter();
702
703#ifndef DISABLE_DYNAMIC_LOADING_LAME
704 bool FindLibrary(wxWindow *parent);
705 bool LoadLibrary(wxWindow *parent, AskUser askuser);
706 bool ValidLibraryLoaded();
707#endif // DISABLE_DYNAMIC_LOADING_LAME
708
709 /* These global settings keep state over the life of the object */
710 void SetMode(int mode);
711 void SetBitrate(int rate);
712 void SetQuality(int q/*, int r*/);
713
714 /* Virtual methods that must be supplied by library interfaces */
715
716 /* initialize the library interface */
717 bool InitLibrary(wxString libpath);
718 bool InitLibraryInternal();
719 bool InitLibraryExternal(wxString libpath);
720 void FreeLibrary();
721
722 /* get library info */
723 wxString GetLibraryVersion();
724 wxString GetLibraryName();
725 wxString GetLibraryPath();
727
728 /* returns the number of samples PER CHANNEL to send for each call to EncodeBuffer */
729 int InitializeStream(unsigned channels, int sampleRate);
730
731 /* In bytes. must be called AFTER InitializeStream */
732 int GetOutBufferSize();
733
734 /* returns the number of bytes written. input is interleaved if stereo*/
735 int EncodeBuffer(float inbuffer[], unsigned char outbuffer[]);
736 int EncodeRemainder(float inbuffer[], int nSamples,
737 unsigned char outbuffer[]);
738
739 int EncodeBufferMono(float inbuffer[], unsigned char outbuffer[]);
740 int EncodeRemainderMono(float inbuffer[], int nSamples,
741 unsigned char outbuffer[]);
742
743 int FinishStream(unsigned char outbuffer[]);
744 void CancelEncoding();
745
746 bool PutInfoTag(wxFFile & f, wxFileOffset off);
747
748private:
750
751#ifndef DISABLE_DYNAMIC_LOADING_LAME
752 wxString mLibPath;
753 wxDynamicLibrary lame_lib;
755#endif // DISABLE_DYNAMIC_LOADING_LAME
756
757#if defined(__WXMSW__)
759#endif
760
762 int mMode;
765 //int mRoutine;
766
767#ifndef DISABLE_DYNAMIC_LOADING_LAME
768 /* function pointers to the symbols we get from the library */
776
792#if defined(__WXMSW__)
795#endif
796#endif // DISABLE_DYNAMIC_LOADING_LAME
797
799
800 static const int mSamplesPerChunk = 220500;
801 // See lame.h/lame_encode_buffer() for further explanation
802 // As coded here, this should be the worst case.
803 static const int mOutBufferSize =
804 mSamplesPerChunk * (320 / 8) / 8 + 4 * 1152 * (320 / 8) / 8 + 512;
805
806 // See MAXFRAMESIZE in libmp3lame/VbrTag.c for explanation of 2880.
807 unsigned char mInfoTagBuf[2880];
809};
810
812{
813// We could use #defines rather than this variable.
814// The idea of the variable is that if we wanted, we could allow
815// a dynamic override of the library, e.g. with a newer faster version,
816// or to fix CVEs in the underlying library.
817// for now though the 'variable' is a constant.
818#ifdef MP3_EXPORT_BUILT_IN
819 mLibIsExternal = false;
820#else
821 mLibIsExternal = true;
822#endif
823
824#ifndef DISABLE_DYNAMIC_LOADING_LAME
825 mLibraryLoaded = false;
826#endif // DISABLE_DYNAMIC_LOADING_LAME
827 mEncoding = false;
828 mGF = NULL;
829
830#ifndef DISABLE_DYNAMIC_LOADING_LAME
831 if (gPrefs) {
832 mLibPath = gPrefs->Read(wxT("/MP3/MP3LibPath"), wxT(""));
833 }
834#endif // DISABLE_DYNAMIC_LOADING_LAME
835
836 mBitrate = 128;
838 mMode = MODE_CBR;
839 //mRoutine = ROUTINE_FAST;
840}
841
843{
844 FreeLibrary();
845}
846
847#ifndef DISABLE_DYNAMIC_LOADING_LAME
848
849bool MP3Exporter::FindLibrary(wxWindow *parent)
850{
851 wxString path;
852 wxString name;
853
854 if (!mLibPath.empty()) {
855 wxFileName fn = mLibPath;
856 path = fn.GetPath();
857 name = fn.GetFullName();
858 }
859 else {
860 path = GetLibraryPath();
862 }
863
864 FindDialog fd(parent,
865 path,
866 name,
868
869 if (fd.ShowModal() == wxID_CANCEL) {
870 return false;
871 }
872
873 path = fd.GetLibPath();
874
875 if (!::wxFileExists(path)) {
876 return false;
877 }
878
879 mLibPath = path;
880
881 return (gPrefs->Write(wxT("/MP3/MP3LibPath"), mLibPath) && gPrefs->Flush());
882}
883
884bool MP3Exporter::LoadLibrary(wxWindow *parent, AskUser askuser)
885{
886
887 if (ValidLibraryLoaded()) {
888 FreeLibrary();
889 mLibraryLoaded = false;
890 }
891
892#if defined(__WXMSW__)
893 mBladeVersion = {};
894#endif
895
896 if( !mLibIsExternal ){
898 return mLibraryLoaded;
899 }
900
901 // First try loading it from a previously located path
902 if (!mLibPath.empty()) {
903 wxLogMessage(wxT("Attempting to load LAME from previously defined path"));
905 }
906
907 // If not successful, try loading using system search paths
908 if (!ValidLibraryLoaded()) {
909 wxLogMessage(wxT("Attempting to load LAME from system search paths"));
912 }
913
914 // If not successful, try loading using compiled in path
915 if (!ValidLibraryLoaded()) {
916 wxLogMessage(wxT("Attempting to load LAME from builtin path"));
917 wxFileName fn(GetLibraryPath(), GetLibraryName());
918 mLibPath = fn.GetFullPath();
920 }
921
922 // If not successful, must ask the user
923 if (!ValidLibraryLoaded()) {
924 wxLogMessage(wxT("(Maybe) ask user for library"));
925 if (askuser == MP3Exporter::Maybe && FindLibrary(parent)) {
927 }
928 }
929
930 // Oh well, just give up
931 if (!ValidLibraryLoaded()) {
932#if defined(__WXMSW__)
933 if (askuser && !mBladeVersion.empty()) {
935 }
936#endif
937 wxLogMessage(wxT("Failed to locate LAME library"));
938
939 return false;
940 }
941
942 wxLogMessage(wxT("LAME library successfully loaded"));
943
944 return true;
945}
946
948{
949 return mLibraryLoaded;
950}
951
952#endif // DISABLE_DYNAMIC_LOADING_LAME
953
955{
956 mMode = mode;
957}
958
960{
961 mBitrate = rate;
962}
963
964void MP3Exporter::SetQuality(int q/*, int r*/)
965{
966 mQuality = q;
967}
968
969bool MP3Exporter::InitLibrary(wxString libpath)
970{
972}
973
975{
976 wxLogMessage(wxT("Using internal LAME"));
977
978// The global ::lame_something symbols only exist if LAME is built in.
979// So we don't reference them unless they are.
980#ifdef MP3_EXPORT_BUILT_IN
981
989
1003
1004 // These are optional
1005 //lame_get_lametag_frame = ::lame_get_lametag_frame;
1008
1009#if defined(__WXMSW__)
1010 //beWriteInfoTag = ::beWriteInfoTag;
1011 //beVersion = ::beVersion;
1012 beWriteInfoTag = NULL;
1013 beVersion = NULL;
1014#endif
1015
1016 mGF = lame_init();
1017 if (mGF == NULL) {
1018 return false;
1019 }
1020#endif
1021
1022 return true;
1023}
1024
1025
1027{
1028 wxLogMessage(wxT("Loading LAME from %s"), libpath);
1029
1030#ifndef DISABLE_DYNAMIC_LOADING_LAME
1031 if (!lame_lib.Load(libpath, wxDL_LAZY)) {
1032 wxLogMessage(wxT("load failed"));
1033 return false;
1034 }
1035
1036 wxLogMessage(wxT("Actual LAME path %s"),
1037 FileNames::PathFromAddr(lame_lib.GetSymbol(wxT("lame_init"))));
1038
1040 lame_lib.GetSymbol(wxT("lame_init"));
1042 lame_lib.GetSymbol(wxT("get_lame_version"));
1044 lame_lib.GetSymbol(wxT("lame_init_params"));
1046 lame_lib.GetSymbol(wxT("lame_encode_buffer_ieee_float"));
1048 lame_lib.GetSymbol(wxT("lame_encode_buffer_interleaved_ieee_float"));
1050 lame_lib.GetSymbol(wxT("lame_encode_flush"));
1052 lame_lib.GetSymbol(wxT("lame_close"));
1053
1055 lame_lib.GetSymbol(wxT("lame_set_in_samplerate"));
1057 lame_lib.GetSymbol(wxT("lame_set_out_samplerate"));
1059 lame_lib.GetSymbol(wxT("lame_set_num_channels"));
1061 lame_lib.GetSymbol(wxT("lame_set_quality"));
1063 lame_lib.GetSymbol(wxT("lame_set_brate"));
1065 lame_lib.GetSymbol(wxT("lame_set_VBR"));
1067 lame_lib.GetSymbol(wxT("lame_set_VBR_q"));
1069 lame_lib.GetSymbol(wxT("lame_set_VBR_min_bitrate_kbps"));
1071 lame_lib.GetSymbol(wxT("lame_set_mode"));
1073 lame_lib.GetSymbol(wxT("lame_set_preset"));
1075 lame_lib.GetSymbol(wxT("lame_set_error_protection"));
1077 lame_lib.GetSymbol(wxT("lame_set_disable_reservoir"));
1079 lame_lib.GetSymbol(wxT("lame_set_bWriteVbrTag"));
1080
1081 // These are optional
1083 lame_lib.GetSymbol(wxT("lame_get_lametag_frame"));
1085 lame_lib.GetSymbol(wxT("lame_mp3_tags_fid"));
1086#if defined(__WXMSW__)
1088 lame_lib.GetSymbol(wxT("beWriteInfoTag"));
1090 lame_lib.GetSymbol(wxT("beVersion"));
1091#endif
1092
1093 if (!lame_init ||
1099 !lame_close ||
1104 !lame_set_brate ||
1105 !lame_set_VBR ||
1106 !lame_set_VBR_q ||
1107 !lame_set_mode ||
1108 !lame_set_preset ||
1112 {
1113 wxLogMessage(wxT("Failed to find a required symbol in the LAME library."));
1114#if defined(__WXMSW__)
1115 if (beVersion) {
1116 be_version v;
1117 beVersion(&v);
1118
1119 mBladeVersion = XO(
1120"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'.")
1121 .Format(
1124 AUDACITY_VERSION,
1125 AUDACITY_RELEASE,
1126 AUDACITY_REVISION);
1127 }
1128#endif
1129
1130 lame_lib.Unload();
1131 return false;
1132 }
1133#endif // DISABLE_DYNAMIC_LOADING_LAME
1134
1135 mGF = lame_init();
1136 if (mGF == NULL) {
1137 return false;
1138 }
1139
1140 return true;
1141}
1142
1144{
1145 if (mGF) {
1146 lame_close(mGF);
1147 mGF = NULL;
1148 }
1149
1150#ifndef DISABLE_DYNAMIC_LOADING_LAME
1151 lame_lib.Unload();
1152#endif // DISABLE_DYNAMIC_LOADING_LAME
1153
1154 return;
1155}
1156
1158{
1159#ifndef DISABLE_DYNAMIC_LOADING_LAME
1160 if (!mLibraryLoaded) {
1161 return wxT("");
1162 }
1163#endif // DISABLE_DYNAMIC_LOADING_LAME
1164
1165 return wxString::Format(wxT("LAME %hs"), get_lame_version());
1166}
1167
1169{
1170#ifndef DISABLE_DYNAMIC_LOADING_LAME
1171 if (!mLibraryLoaded) {
1172 return -1;
1173 }
1174#endif // DISABLE_DYNAMIC_LOADING_LAME
1175
1176 if (channels > 2) {
1177 return -1;
1178 }
1179
1181 lame_set_num_channels(mGF, channels);
1185 // Add the VbrTag for all types. For ABR/VBR, a Xing tag will be created.
1186 // For CBR, it will be a Lame Info tag.
1188
1189 // Set the VBR quality or ABR/CBR bitrate
1190 switch (mMode) {
1191 case MODE_SET:
1192 {
1193 int preset;
1194
1195 if (mQuality == PRESET_INSANE) {
1196 preset = INSANE;
1197 }
1198 //else if (mRoutine == ROUTINE_FAST) {
1199 else if (mQuality == PRESET_EXTREME) {
1200 preset = EXTREME_FAST;
1201 }
1202 else if (mQuality == PRESET_STANDARD) {
1203 preset = STANDARD_FAST;
1204 }
1205 else {
1206 preset = 1007; // Not defined until 3.96
1207 }
1208 //}
1209 /*
1210 else {
1211 if (mQuality == PRESET_EXTREME) {
1212 preset = EXTREME;
1213 }
1214 else if (mQuality == PRESET_STANDARD) {
1215 preset = STANDARD;
1216 }
1217 else {
1218 preset = 1006; // Not defined until 3.96
1219 }
1220 }
1221 */
1223 }
1224 break;
1225
1226 case MODE_VBR:
1227 lame_set_VBR(mGF, vbr_mtrh );
1229 break;
1230
1231 case MODE_ABR:
1233 break;
1234
1235 default:
1236 lame_set_VBR(mGF, vbr_off);
1238 break;
1239 }
1240
1241 // Set the channel mode
1242 MPEG_mode mode;
1243
1244 if (channels == 1)
1245 mode = MONO;
1246 else
1247 mode = JOINT_STEREO;
1248
1249 lame_set_mode(mGF, mode);
1250
1251 int rc = lame_init_params(mGF);
1252 if (rc < 0) {
1253 return rc;
1254 }
1255
1256#if 0
1257 dump_config(mGF);
1258#endif
1259
1260 mInfoTagLen = 0;
1261 mEncoding = true;
1262
1263 return mSamplesPerChunk;
1264}
1265
1267{
1268 if (!mEncoding)
1269 return -1;
1270
1271 return mOutBufferSize;
1272}
1273
1274int MP3Exporter::EncodeBuffer(float inbuffer[], unsigned char outbuffer[])
1275{
1276 if (!mEncoding) {
1277 return -1;
1278 }
1279
1281 outbuffer, mOutBufferSize);
1282}
1283
1284int MP3Exporter::EncodeRemainder(float inbuffer[], int nSamples,
1285 unsigned char outbuffer[])
1286{
1287 if (!mEncoding) {
1288 return -1;
1289 }
1290
1291 return lame_encode_buffer_interleaved_ieee_float(mGF, inbuffer, nSamples, outbuffer,
1293}
1294
1295int MP3Exporter::EncodeBufferMono(float inbuffer[], unsigned char outbuffer[])
1296{
1297 if (!mEncoding) {
1298 return -1;
1299 }
1300
1301 return lame_encode_buffer_ieee_float(mGF, inbuffer,inbuffer, mSamplesPerChunk,
1302 outbuffer, mOutBufferSize);
1303}
1304
1305int MP3Exporter::EncodeRemainderMono(float inbuffer[], int nSamples,
1306 unsigned char outbuffer[])
1307{
1308 if (!mEncoding) {
1309 return -1;
1310 }
1311
1312 return lame_encode_buffer_ieee_float(mGF, inbuffer, inbuffer, nSamples, outbuffer,
1314}
1315
1316int MP3Exporter::FinishStream(unsigned char outbuffer[])
1317{
1318 if (!mEncoding) {
1319 return -1;
1320 }
1321
1322 mEncoding = false;
1323
1324 int result = lame_encode_flush(mGF, outbuffer, mOutBufferSize);
1325
1326#if defined(DISABLE_DYNAMIC_LOADING_LAME)
1328#else
1331 }
1332#endif
1333
1334 return result;
1335}
1336
1338{
1339 mEncoding = false;
1340}
1341
1342bool MP3Exporter::PutInfoTag(wxFFile & f, wxFileOffset off)
1343{
1344 if (mGF) {
1345 if (mInfoTagLen > 0) {
1346 // FIXME: TRAP_ERR Seek and writ ein MP3 exporter could fail.
1347 if ( !f.Seek(off, wxFromStart))
1348 return false;
1349 if (mInfoTagLen > f.Write(mInfoTagBuf, mInfoTagLen))
1350 return false;
1351 }
1352#if defined(__WXMSW__)
1353 else if (beWriteInfoTag) {
1354 if ( !f.Flush() )
1355 return false;
1356 // PRL: What is the correct error check on the return value?
1357 beWriteInfoTag(mGF, OSOUTPUT(f.GetName()));
1358 mGF = NULL;
1359 }
1360#endif
1361 else if (lame_mp3_tags_fid != NULL) {
1362 lame_mp3_tags_fid(mGF, f.fp());
1363 }
1364 }
1365
1366 if ( !f.SeekEnd() )
1367 return false;
1368
1369 return true;
1370}
1371
1372#if defined(__WXMSW__)
1373/* values for Windows */
1374
1376{
1377 wxRegKey reg(wxT("HKEY_LOCAL_MACHINE\\Software\\Lame for Audacity"));
1378 wxString path;
1379
1380 if (reg.Exists()) {
1381 wxLogMessage(wxT("LAME registry key exists."));
1382 reg.QueryValue(wxT("InstallPath"), path);
1383 }
1384 else {
1385 wxLogMessage(wxT("LAME registry key does not exist."));
1386 }
1387
1388 wxLogMessage(wxT("Library path is: ") + path);
1389
1390 return path;
1391}
1392
1394{
1395 return wxT("lame_enc.dll");
1396}
1397
1399{
1400 return {
1401 { XO("Only lame_enc.dll"), { wxT("lame_enc.dll") } },
1404 };
1405}
1406
1407#elif defined(__WXMAC__)
1408/* values for Mac OS X */
1409
1411{
1412 wxString path;
1413
1414 path = wxT("/Library/Application Support/audacity/libs");
1415 if (wxFileExists(path + wxT("/") + GetLibraryName()))
1416 {
1417 return path;
1418 }
1419
1420 path = wxT("/usr/local/lib/audacity");
1421 if (wxFileExists(path + wxT("/") + GetLibraryName()))
1422 {
1423 return path;
1424 }
1425
1426 return wxT("/Library/Application Support/audacity/libs");
1427}
1428
1430{
1431 if (sizeof(void*) == 8)
1432 return wxT("libmp3lame64bit.dylib");
1433 return wxT("libmp3lame.dylib");
1434}
1435
1437{
1438 return {
1439 (sizeof(void*) == 8)
1441 XO("Only libmp3lame64bit.dylib"), { wxT("libmp3lame64bit.dylib") }
1442 }
1444 XO("Only libmp3lame.dylib"), { wxT("libmp3lame.dylib") }
1445 }
1446 ,
1449 };
1450}
1451
1452#else
1453/* Values for Linux / Unix systems */
1454
1456{
1457 return wxT(LIBDIR);
1458}
1459
1461{
1462 return wxT("libmp3lame.so.0");
1463}
1464
1466{
1467 return {
1468 { XO("Only libmp3lame.so.0"), { wxT("libmp3lame.so.0") } },
1469 { XO("Primary shared object files"), { wxT("so") }, true },
1470 { XO("Extended libraries"), { wxT("so*") }, true },
1472 };
1473}
1474#endif
1475
1476#if 0
1477// Debug routine from BladeMP3EncDLL.c in the libmp3lame distro
1478static void dump_config( lame_global_flags* gfp )
1479{
1480 wxPrintf(wxT("\n\nLame_enc configuration options:\n"));
1481 wxPrintf(wxT("==========================================================\n"));
1482
1483 wxPrintf(wxT("version =%d\n"),lame_get_version( gfp ) );
1484 wxPrintf(wxT("Layer =3\n"));
1485 wxPrintf(wxT("mode ="));
1486 switch ( lame_get_mode( gfp ) )
1487 {
1488 case STEREO: wxPrintf(wxT( "Stereo\n" )); break;
1489 case JOINT_STEREO: wxPrintf(wxT( "Joint-Stereo\n" )); break;
1490 case DUAL_CHANNEL: wxPrintf(wxT( "Forced Stereo\n" )); break;
1491 case MONO: wxPrintf(wxT( "Mono\n" )); break;
1492 case NOT_SET: /* FALLTHROUGH */
1493 default: wxPrintf(wxT( "Error (unknown)\n" )); break;
1494 }
1495
1496 wxPrintf(wxT("Input sample rate =%.1f kHz\n"), lame_get_in_samplerate( gfp ) /1000.0 );
1497 wxPrintf(wxT("Output sample rate =%.1f kHz\n"), lame_get_out_samplerate( gfp ) /1000.0 );
1498
1499 wxPrintf(wxT("bitrate =%d kbps\n"), lame_get_brate( gfp ) );
1500 wxPrintf(wxT("Quality Setting =%d\n"), lame_get_quality( gfp ) );
1501
1502 wxPrintf(wxT("Low pass frequency =%d\n"), lame_get_lowpassfreq( gfp ) );
1503 wxPrintf(wxT("Low pass width =%d\n"), lame_get_lowpasswidth( gfp ) );
1504
1505 wxPrintf(wxT("High pass frequency =%d\n"), lame_get_highpassfreq( gfp ) );
1506 wxPrintf(wxT("High pass width =%d\n"), lame_get_highpasswidth( gfp ) );
1507
1508 wxPrintf(wxT("No short blocks =%d\n"), lame_get_no_short_blocks( gfp ) );
1509 wxPrintf(wxT("Force short blocks =%d\n"), lame_get_force_short_blocks( gfp ) );
1510
1511 wxPrintf(wxT("de-emphasis =%d\n"), lame_get_emphasis( gfp ) );
1512 wxPrintf(wxT("private flag =%d\n"), lame_get_extension( gfp ) );
1513
1514 wxPrintf(wxT("copyright flag =%d\n"), lame_get_copyright( gfp ) );
1515 wxPrintf(wxT("original flag =%d\n"), lame_get_original( gfp ) );
1516 wxPrintf(wxT("CRC =%s\n"), lame_get_error_protection( gfp ) ? wxT("on") : wxT("off") );
1517 wxPrintf(wxT("Fast mode =%s\n"), ( lame_get_quality( gfp ) )? wxT("enabled") : wxT("disabled") );
1518 wxPrintf(wxT("Force mid/side stereo =%s\n"), ( lame_get_force_ms( gfp ) )?wxT("enabled"):wxT("disabled") );
1519 wxPrintf(wxT("Padding Type =%d\n"), (int) lame_get_padding_type( gfp ) );
1520 wxPrintf(wxT("Disable Reservoir =%d\n"), lame_get_disable_reservoir( gfp ) );
1521 wxPrintf(wxT("Allow diff-short =%d\n"), lame_get_allow_diff_short( gfp ) );
1522 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
1523 wxPrintf(wxT("Strict ISO Encoding =%s\n"), ( lame_get_strict_ISO( gfp ) ) ?wxT("Yes"):wxT("No"));
1524 wxPrintf(wxT("Scale =%5.2f\n"), lame_get_scale( gfp ) );
1525
1526 wxPrintf(wxT("VBR =%s, VBR_q =%d, VBR method ="),
1527 ( lame_get_VBR( gfp ) !=vbr_off ) ? wxT("enabled"): wxT("disabled"),
1528 lame_get_VBR_q( gfp ) );
1529
1530 switch ( lame_get_VBR( gfp ) )
1531 {
1532 case vbr_off: wxPrintf(wxT( "vbr_off\n" )); break;
1533 case vbr_mt : wxPrintf(wxT( "vbr_mt \n" )); break;
1534 case vbr_rh : wxPrintf(wxT( "vbr_rh \n" )); break;
1535 case vbr_mtrh: wxPrintf(wxT( "vbr_mtrh \n" )); break;
1536 case vbr_abr:
1537 wxPrintf(wxT( "vbr_abr (average bitrate %d kbps)\n"), lame_get_VBR_mean_bitrate_kbps( gfp ) );
1538 break;
1539 default:
1540 wxPrintf(wxT("error, unknown VBR setting\n"));
1541 break;
1542 }
1543
1544 wxPrintf(wxT("Vbr Min bitrate =%d kbps\n"), lame_get_VBR_min_bitrate_kbps( gfp ) );
1545 wxPrintf(wxT("Vbr Max bitrate =%d kbps\n"), lame_get_VBR_max_bitrate_kbps( gfp ) );
1546
1547 wxPrintf(wxT("Write VBR Header =%s\n"), ( lame_get_bWriteVbrTag( gfp ) ) ?wxT("Yes"):wxT("No"));
1548 wxPrintf(wxT("VBR Hard min =%d\n"), lame_get_VBR_hard_min( gfp ) );
1549
1550 wxPrintf(wxT("ATH Only =%d\n"), lame_get_ATHonly( gfp ) );
1551 wxPrintf(wxT("ATH short =%d\n"), lame_get_ATHshort( gfp ) );
1552 wxPrintf(wxT("ATH no =%d\n"), lame_get_noATH( gfp ) );
1553 wxPrintf(wxT("ATH type =%d\n"), lame_get_ATHtype( gfp ) );
1554 wxPrintf(wxT("ATH lower =%f\n"), lame_get_ATHlower( gfp ) );
1555 wxPrintf(wxT("ATH aa =%d\n"), lame_get_athaa_type( gfp ) );
1556 wxPrintf(wxT("ATH aa loudapprox =%d\n"), lame_get_athaa_loudapprox( gfp ) );
1557 wxPrintf(wxT("ATH aa sensitivity =%f\n"), lame_get_athaa_sensitivity( gfp ) );
1558
1559 wxPrintf(wxT("Experimental nspsytune =%d\n"), lame_get_exp_nspsytune( gfp ) );
1560 wxPrintf(wxT("Experimental X =%d\n"), lame_get_experimentalX( gfp ) );
1561 wxPrintf(wxT("Experimental Y =%d\n"), lame_get_experimentalY( gfp ) );
1562 wxPrintf(wxT("Experimental Z =%d\n"), lame_get_experimentalZ( gfp ) );
1563}
1564#endif
1565
1567{
1568 struct
1569 {
1571 unsigned channels;
1572 double t0;
1573 double t1;
1575 wxFFile outFile;
1577 unsigned long id3len;
1578 wxFileOffset infoTagPos;
1581 std::unique_ptr<Mixer> mixer;
1583
1584public:
1586 const Parameters& parameters,
1587 const wxFileNameWrapper& filename,
1588 double t0, double t1, bool selectedOnly,
1589 double sampleRate, unsigned channels,
1590 MixerOptions::Downmix* mixerSpec,
1591 const Tags* tags) override;
1592
1593 ExportResult Process(ExportProcessorDelegate& delegate) override;
1594
1595private:
1596
1597 static int AskResample(int bitrate, int rate, int lowrate, int highrate);
1598 static unsigned long AddTags(ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags);
1599#ifdef USE_LIBID3TAG
1600 static void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
1601#endif
1602};
1603
1604//----------------------------------------------------------------------------
1605// ExportMP3
1606//----------------------------------------------------------------------------
1607
1608class ExportMP3 final : public ExportPlugin
1609{
1610public:
1611
1613 bool CheckFileName(wxFileName & filename, int format) const override;
1614
1615 int GetFormatCount() const override;
1616 FormatInfo GetFormatInfo(int) const override;
1617
1618 std::unique_ptr<ExportOptionsEditor>
1619 CreateOptionsEditor(int, ExportOptionsEditor::Listener* listener) const override;
1620
1621 std::unique_ptr<ExportProcessor> CreateProcessor(int format) const override;
1622};
1623
1624ExportMP3::ExportMP3() = default;
1625
1627{
1628 return 1;
1629}
1630
1632{
1633 return {
1634 wxT("MP3"), XO("MP3 Files"), { wxT("mp3") }, 2u, true
1635 };
1636}
1637
1638std::unique_ptr<ExportOptionsEditor>
1640{
1641 return std::make_unique<MP3ExportOptionsEditor>(listener);
1642}
1643
1644std::unique_ptr<ExportProcessor> ExportMP3::CreateProcessor(int format) const
1645{
1646 return std::make_unique<MP3ExportProcessor>();
1647}
1648
1649bool ExportMP3::CheckFileName(wxFileName & WXUNUSED(filename), int WXUNUSED(format)) const
1650{
1651#ifndef DISABLE_DYNAMIC_LOADING_LAME
1652 MP3Exporter exporter;
1653
1654 if (!exporter.LoadLibrary(wxTheApp->GetTopWindow(), MP3Exporter::Maybe)) {
1655 BasicUI::ShowMessageBox(XO("Could not open MP3 encoding library!"),
1657 .IconStyle(BasicUI::Icon::Error)
1658 .Caption(XO("Error")));
1659 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1660 gPrefs->Flush();
1661
1662 return false;
1663 }
1664#endif // DISABLE_DYNAMIC_LOADING_LAME
1665
1666 return true;
1667}
1668
1670 const Parameters& parameters,
1671 const wxFileNameWrapper& fName,
1672 double t0, double t1, bool selectionOnly,
1673 double sampleRate, unsigned channels,
1674 MixerOptions::Downmix* mixerSpec,
1675 const Tags* metadata)
1676{
1677 context.t0 = t0;
1678 context.t1 = t1;
1679 context.channels = channels;
1680
1681 int rate = lrint(sampleRate);
1682#ifndef DISABLE_DYNAMIC_LOADING_LAME
1683 wxWindow *parent = ProjectWindow::Find( &project );
1684#endif // DISABLE_DYNAMIC_LOADING_LAME
1685 const auto &tracks = TrackList::Get( project );
1686 auto& exporter = context.exporter;
1687
1688#ifdef DISABLE_DYNAMIC_LOADING_LAME
1689 if (!exporter.InitLibrary(wxT(""))) {
1690 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1691 gPrefs->Flush();
1692 throw ExportException(_("Could not initialize MP3 encoding library!"))
1693 }
1694#else
1695 if (!exporter.LoadLibrary(parent, MP3Exporter::Maybe)) {
1696 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1697 gPrefs->Flush();
1698 throw ExportException(_("Could not open MP3 encoding library!"));
1699 }
1700
1702 gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
1703 gPrefs->Flush();
1704 throw ExportException(_("Not a valid or supported MP3 encoding library!"));
1705 }
1706#endif // DISABLE_DYNAMIC_LOADING_LAME
1707
1708 // Retrieve preferences
1709 int highrate = 48000;
1710 int lowrate = 8000;
1711 int bitrate = 0;
1712 int quality;
1713
1715 parameters,
1717 std::string("CBR"));
1718 // Set the bitrate/quality and mode
1719 if (rmode == "SET") {
1720 quality = ExportPluginHelpers::GetParameterValue<int>(
1721 parameters,
1725 exporter.SetQuality(quality);
1726 }
1727 else if (rmode == "VBR") {
1728 quality = ExportPluginHelpers::GetParameterValue<int>(
1729 parameters,
1731 QUALITY_2);
1733 exporter.SetQuality(quality);
1734 }
1735 else if (rmode == "ABR") {
1737 parameters,
1739 128);
1741 exporter.SetBitrate(bitrate);
1742 if (bitrate > 160) {
1743 lowrate = 32000;
1744 }
1745 else if (bitrate < 32 || bitrate == 144) {
1746 highrate = 24000;
1747 }
1748 }
1749 else {
1752 exporter.SetBitrate(bitrate);
1753
1754 if (bitrate > 160) {
1755 lowrate = 32000;
1756 }
1757 else if (bitrate < 32 || bitrate == 144) {
1758 highrate = 24000;
1759 }
1760 }
1761
1762 // Verify sample rate
1763 if (!make_iterator_range( sampRates ).contains( rate ) ||
1764 (rate < lowrate) || (rate > highrate)) {
1765 // Force valid sample rate in macros.
1766 if (project.mBatchMode) {
1767 if (!make_iterator_range( sampRates ).contains( rate )) {
1768 auto const bestRateIt = std::lower_bound(sampRates.begin(),
1769 sampRates.end(), rate);
1770 rate = (bestRateIt == sampRates.end()) ? highrate : *bestRateIt;
1771 }
1772 if (rate < lowrate) {
1773 rate = lowrate;
1774 }
1775 else if (rate > highrate) {
1776 rate = highrate;
1777 }
1778 }
1779 // else validate or prompt
1780 else {
1781 if (!make_iterator_range( sampRates ).contains( rate ) ||
1782 (rate < lowrate) || (rate > highrate)) {
1783 //This call should go away once export project rate option
1784 //is available as an export dialog option
1785 rate = AskResample(bitrate, rate, lowrate, highrate);
1786 }
1787 if (rate == 0) {
1788 return false;
1789 }
1790 }
1791 }
1792
1793 context.inSamples = exporter.InitializeStream(channels, rate);
1794 if (context.inSamples < 0) {
1795 throw ExportException(_("Unable to initialize MP3 stream"));
1796 }
1797
1798 // Put ID3 tags at beginning of file
1799 if (metadata == nullptr)
1800 metadata = &Tags::Get( project );
1801
1802 // Open file for writing
1803 if (!context.outFile.Open(fName.GetFullPath(), wxT("w+b"))) {
1804 throw ExportException(_("Unable to open target file for writing"));
1805 }
1806
1807 bool endOfFile;
1808 context.id3len = AddTags(context.id3buffer, &endOfFile, metadata);
1809 if (context.id3len && !endOfFile) {
1810 if (context.id3len > context.outFile.Write(context.id3buffer.get(), context.id3len)) {
1811 // TODO: more precise message
1812 throw ExportErrorException("MP3:1882");
1813 }
1814 context.id3len = 0;
1815 context.id3buffer.reset();
1816 }
1817
1818 context.infoTagPos = context.outFile.Tell();
1819
1820 context.bufferSize = std::max(0, exporter.GetOutBufferSize());
1821 if (context.bufferSize == 0) {
1822 // TODO: more precise message
1823 throw ExportErrorException("MP3:1849");
1824 }
1825
1826 if (rmode == "SET") {
1827 context.status = (selectionOnly ?
1828 XO("Exporting selected audio with %s preset") :
1829 XO("Exporting the audio with %s preset"))
1830 .Format( setRateNamesShort[quality] );
1831 }
1832 else if (rmode == "VBR") {
1833 context.status = (selectionOnly ?
1834 XO("Exporting selected audio with VBR quality %s") :
1835 XO("Exporting the audio with VBR quality %s"))
1836 .Format( varRateNames[quality] );
1837 }
1838 else {
1839 context.status = (selectionOnly ?
1840 XO("Exporting selected audio at %d Kbps") :
1841 XO("Exporting the audio at %d Kbps"))
1842 .Format( bitrate );
1843 }
1844
1845 context.mixer = ExportPluginHelpers::CreateMixer(tracks, selectionOnly,
1846 t0, t1,
1847 channels, context.inSamples, true,
1848 rate, floatSample, mixerSpec);
1849
1850 return true;
1851}
1852
1854{
1855 delegate.SetStatusString(context.status);
1856
1857 auto& exporter = context.exporter;
1858 int bytes = 0;
1859
1860 ArrayOf<unsigned char> buffer{ context.bufferSize };
1861 wxASSERT(buffer);
1862
1863 auto exportResult = ExportResult::Success;
1864
1865 {
1866 while (exportResult == ExportResult::Success) {
1867 auto blockLen = context.mixer->Process();
1868 if (blockLen == 0)
1869 break;
1870
1871 float *mixed = (float *)context.mixer->GetBuffer();
1872
1873 if ((int)blockLen < context.inSamples) {
1874 if (context.channels > 1) {
1875 bytes = exporter.EncodeRemainder(mixed, blockLen, buffer.get());
1876 }
1877 else {
1878 bytes = exporter.EncodeRemainderMono(mixed, blockLen, buffer.get());
1879 }
1880 }
1881 else {
1882 if (context.channels > 1) {
1883 bytes = exporter.EncodeBuffer(mixed, buffer.get());
1884 }
1885 else {
1886 bytes = exporter.EncodeBufferMono(mixed, buffer.get());
1887 }
1888 }
1889
1890 if (bytes < 0) {
1891 throw ExportException(XO("Error %ld returned from MP3 encoder")
1892 .Format( bytes )
1893 .Translation());
1894 }
1895
1896 if (bytes > (int)context.outFile.Write(buffer.get(), bytes)) {
1897 // TODO: more precise message
1898 throw ExportDiskFullError(context.outFile.GetName());
1899 }
1900
1901 if(exportResult == ExportResult::Success)
1903 delegate, *context.mixer, context.t0, context.t1);
1904 }
1905 }
1906
1907 if (exportResult == ExportResult::Success) {
1908 bytes = exporter.FinishStream(buffer.get());
1909
1910 if (bytes < 0) {
1911 // TODO: more precise message
1912 throw ExportErrorException("MP3:1981");
1913 }
1914
1915 if (bytes > 0) {
1916 if (bytes > (int)context.outFile.Write(buffer.get(), bytes)) {
1917 // TODO: more precise message
1918 throw ExportErrorException("MP3:1988");
1919 }
1920 }
1921
1922 // Write ID3 tag if it was supposed to be at the end of the file
1923 if (context.id3len > 0) {
1924 if (bytes > (int)context.outFile.Write(context.id3buffer.get(), context.id3len)) {
1925 // TODO: more precise message
1926 throw ExportErrorException("MP3:1997");
1927 }
1928 }
1929
1930 // Always write the info (Xing/Lame) tag. Until we stop supporting Lame
1931 // versions before 3.98, we must do this after the MP3 file has been
1932 // closed.
1933 //
1934 // Also, if beWriteInfoTag() is used, mGF will no longer be valid after
1935 // this call, so do not use it.
1936 if (!exporter.PutInfoTag(context.outFile, context.infoTagPos) ||
1937 !context.outFile.Flush() ||
1938 !context.outFile.Close()) {
1939 // TODO: more precise message
1940 throw ExportErrorException("MP3:2012");
1941 }
1942 }
1943 return exportResult;
1944}
1945
1946int MP3ExportProcessor::AskResample(int bitrate, int rate, int lowrate, int highrate)
1947{
1948 wxDialogWrapper d(nullptr, wxID_ANY, XO("Invalid sample rate"));
1949 d.SetName();
1950 wxChoice *choice;
1952
1953 int selected = -1;
1954
1955 S.StartVerticalLay();
1956 {
1957 S.SetBorder(10);
1958 S.StartStatic(XO("Resample"));
1959 {
1960 S.StartHorizontalLay(wxALIGN_CENTER, false);
1961 {
1962 S.AddTitle(
1963 ((bitrate == 0)
1964 ? XO(
1965"The project sample rate (%d) is not supported by the MP3\nfile format. ")
1966 .Format( rate )
1967 : XO(
1968"The project sample rate (%d) and bit rate (%d kbps) combination is not\nsupported by the MP3 file format. ")
1969 .Format( rate, bitrate ))
1970 + XO("You may resample to one of the rates below.")
1971 );
1972 }
1973 S.EndHorizontalLay();
1974
1975 S.StartHorizontalLay(wxALIGN_CENTER, false);
1976 {
1977 choice = S.AddChoice(XXO("Sample Rates"),
1978 [&]{
1979 TranslatableStrings choices;
1980 for (size_t ii = 0, nn = sampRates.size(); ii < nn; ++ii) {
1981 int label = sampRates[ii];
1982 if (label >= lowrate && label <= highrate) {
1983 choices.push_back( Verbatim( "%d" ).Format( label ) );
1984 if (label <= rate)
1985 selected = ii;
1986 }
1987 }
1988 return choices;
1989 }(),
1990 std::max( 0, selected )
1991 );
1992 }
1993 S.EndHorizontalLay();
1994 }
1995 S.EndStatic();
1996
1997 S.AddStandardButtons();
1998 }
1999 S.EndVerticalLay();
2000
2001 d.Layout();
2002 d.Fit();
2003 d.SetMinSize(d.GetSize());
2004 d.Center();
2005
2006 if (d.ShowModal() == wxID_CANCEL) {
2007 return 0;
2008 }
2009
2010 return wxAtoi(choice->GetStringSelection());
2011}
2012
2013#ifdef USE_LIBID3TAG
2014struct id3_tag_deleter {
2015 void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
2016};
2017using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
2018#endif
2019
2020// returns buffer len; caller frees
2021unsigned long MP3ExportProcessor::AddTags(ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags)
2022{
2023#ifdef USE_LIBID3TAG
2024 id3_tag_holder tp { id3_tag_new() };
2025
2026 for (const auto &pair : tags->GetRange()) {
2027 const auto &n = pair.first;
2028 const auto &v = pair.second;
2029 const char *name = "TXXX";
2030
2031 if (n.CmpNoCase(TAG_TITLE) == 0) {
2032 name = ID3_FRAME_TITLE;
2033 }
2034 else if (n.CmpNoCase(TAG_ARTIST) == 0) {
2035 name = ID3_FRAME_ARTIST;
2036 }
2037 else if (n.CmpNoCase(TAG_ALBUM) == 0) {
2038 name = ID3_FRAME_ALBUM;
2039 }
2040 else if (n.CmpNoCase(TAG_YEAR) == 0) {
2041 // LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR),
2042 // so we add old one as well.
2043 AddFrame(tp.get(), n, v, "TYER");
2044 name = ID3_FRAME_YEAR;
2045 }
2046 else if (n.CmpNoCase(TAG_GENRE) == 0) {
2047 name = ID3_FRAME_GENRE;
2048 }
2049 else if (n.CmpNoCase(TAG_COMMENTS) == 0) {
2050 name = ID3_FRAME_COMMENT;
2051 }
2052 else if (n.CmpNoCase(TAG_TRACK) == 0) {
2053 name = ID3_FRAME_TRACK;
2054 }
2055
2056 AddFrame(tp.get(), n, v, name);
2057 }
2058
2059 tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
2060
2061 // If this version of libid3tag supports it, use v2.3 ID3
2062 // tags instead of the newer, but less well supported, v2.4
2063 // that libid3tag uses by default.
2064 #ifdef ID3_TAG_HAS_TAG_OPTION_ID3V2_3
2065 tp->options |= ID3_TAG_OPTION_ID3V2_3;
2066 #endif
2067
2068 *endOfFile = false;
2069
2070 unsigned long len;
2071
2072 len = id3_tag_render(tp.get(), 0);
2073 buffer.reinit(len);
2074 len = id3_tag_render(tp.get(), (id3_byte_t *)buffer.get());
2075
2076 return len;
2077#else //ifdef USE_LIBID3TAG
2078 return 0;
2079#endif
2080}
2081
2082#ifdef USE_LIBID3TAG
2083void MP3ExportProcessor::AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name)
2084{
2085 struct id3_frame *frame = id3_frame_new(name);
2086
2087 if (!n.IsAscii() || !v.IsAscii()) {
2088 id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_UTF_16);
2089 }
2090 else {
2091 id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
2092 }
2093
2095 id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
2096
2097 if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
2098 // A hack to get around iTunes not recognizing the comment. The
2099 // language defaults to XXX and, since it's not a valid language,
2100 // iTunes just ignores the tag. So, either set it to a valid language
2101 // (which one???) or just clear it. Unfortunately, there's no supported
2102 // way of clearing the field, so do it directly.
2103 struct id3_frame *frame2 = id3_frame_new(name);
2104 id3_field_setfullstring(id3_frame_field(frame2, 3), ucs4.get());
2105 id3_field *f2 = id3_frame_field(frame2, 1);
2106 memset(f2->immediate.value, 0, sizeof(f2->immediate.value));
2107 id3_tag_attachframe(tp, frame2);
2108 // Now install a second frame with the standard default language = "XXX"
2109 id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
2110 }
2111 else if (strcmp(name, "TXXX") == 0) {
2112 id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
2113
2114 ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
2115
2116 id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
2117 }
2118 else {
2119 auto addr = ucs4.get();
2120 id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
2121 }
2122
2123 id3_tag_attachframe(tp, frame);
2124}
2125#endif
2126
2128 []{ return std::make_unique< ExportMP3 >(); }
2129};
2130
2131//----------------------------------------------------------------------------
2132// Return library version
2133//----------------------------------------------------------------------------
2134
2135TranslatableString GetMP3Version(wxWindow *parent, bool prompt)
2136{
2137 MP3Exporter exporter;
2138 auto versionString = XO("MP3 export library not found");
2139
2140#ifndef DISABLE_DYNAMIC_LOADING_LAME
2141 if (prompt) {
2142 exporter.FindLibrary(parent);
2143 }
2144
2145 if (exporter.LoadLibrary(parent, prompt ? MP3Exporter::Yes : MP3Exporter::No)) {
2146#endif // DISABLE_DYNAMIC_LOADING_LAME
2147 versionString = Verbatim( exporter.GetLibraryVersion() );
2148#ifdef MP3_EXPORT_BUILT_IN
2149 versionString.Join( XO("(Built-in)"), " " );
2150#endif
2151
2152#ifndef DISABLE_DYNAMIC_LOADING_LAME
2153 }
2154#endif // DISABLE_DYNAMIC_LOADING_LAME
2155
2156 return versionString;
2157}
2158
wxT("CloseDown"))
Toolkit-neutral facade for basic user interface services.
END_EVENT_TABLE()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
Definition: Distortion.cpp:76
const wxChar * values
int lame_set_VBR_t(lame_global_flags *, vbr_mode)
Definition: ExportMP3.cpp:638
@ QUALITY_2
Definition: ExportMP3.cpp:107
@ PRESET_EXTREME
Definition: ExportMP3.cpp:113
@ PRESET_INSANE
Definition: ExportMP3.cpp:112
@ PRESET_STANDARD
Definition: ExportMP3.cpp:114
@ PRESET_MEDIUM
Definition: ExportMP3.cpp:115
static const std::vector< ExportValue > fixRateValues
Definition: ExportMP3.cpp:142
int lame_set_bWriteVbrTag_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:645
static const std::vector< int > sampRates
Definition: ExportMP3.cpp:197
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:619
static const TranslatableStrings varRateNames
Definition: ExportMP3.cpp:163
#define ID_DLOAD
Definition: ExportMP3.cpp:472
static const TranslatableStrings fixRateNames
Definition: ExportMP3.cpp:121
const char * get_lame_version_t(void)
Definition: ExportMP3.cpp:609
int lame_set_VBR_q_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:639
int lame_set_in_samplerate_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:633
int lame_close_t(lame_global_flags *)
Definition: ExportMP3.cpp:631
TranslatableString n_kbps(int n)
Definition: ExportMP3.cpp:119
TranslatableString GetMP3Version(wxWindow *parent, bool prompt)
Definition: ExportMP3.cpp:2135
MP3OptionID
Definition: ExportMP3.cpp:209
@ MP3OptionIDQualityABR
Definition: ExportMP3.cpp:213
@ MP3OptionIDQualityVBR
Definition: ExportMP3.cpp:212
@ MP3OptionIDQualityCBR
Definition: ExportMP3.cpp:214
@ MP3OptionIDQualitySET
Definition: ExportMP3.cpp:211
@ MP3OptionIDMode
Definition: ExportMP3.cpp:210
void lame_mp3_tags_fid_t(lame_global_flags *, FILE *)
Definition: ExportMP3.cpp:647
int lame_set_VBR_min_bitrate_kbps_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:640
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:611
static ExportPluginRegistry::RegisteredPlugin sRegisteredPlugin
Definition: ExportMP3.cpp:2127
int lame_set_error_protection_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:643
unsigned long beWriteInfoTag_t(lame_global_flags *, char *)
Definition: ExportMP3.cpp:655
static const TranslatableStrings setRateNames
Definition: ExportMP3.cpp:181
int lame_set_out_samplerate_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:634
int lame_set_quality_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:636
const std::initializer_list< ExportOption > MP3Options
Definition: ExportMP3.cpp:218
void beVersion_t(be_version *)
Definition: ExportMP3.cpp:687
int lame_set_preset_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:642
#define ID_BROWSE
Definition: ExportMP3.cpp:471
size_t lame_get_lametag_frame_t(const lame_global_flags *, unsigned char *buffer, size_t size)
Definition: ExportMP3.cpp:646
static const TranslatableStrings setRateNamesShort
Definition: ExportMP3.cpp:189
int lame_set_disable_reservoir_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:644
lame_global_flags * lame_init_t(void)
Definition: ExportMP3.cpp:607
int lame_encode_flush_t(lame_global_flags *gf, unsigned char *mp3buf, int size)
Definition: ExportMP3.cpp:626
int lame_set_num_channels_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:635
int lame_set_mode_t(lame_global_flags *, MPEG_mode)
Definition: ExportMP3.cpp:641
int lame_set_brate_t(lame_global_flags *, int)
Definition: ExportMP3.cpp:637
int lame_init_params_t(lame_global_flags *)
Definition: ExportMP3.cpp:608
@ MODE_SET
Definition: ExportMP3.h:19
@ MODE_ABR
Definition: ExportMP3.h:21
@ MODE_VBR
Definition: ExportMP3.h:20
@ MODE_CBR
Definition: ExportMP3.h:22
std::variant< bool, int, double, std::string > ExportValue
A type of option values (parameters) used by exporting plugins.
Definition: ExportTypes.h:38
ExportResult
Definition: ExportTypes.h:24
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
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:448
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
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
#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
const auto tracks
const auto project
#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
bool CheckFileName(wxFileName &filename, int format) const override
Definition: ExportMP3.cpp:1649
int GetFormatCount() const override
Definition: ExportMP3.cpp:1626
std::unique_ptr< ExportProcessor > CreateProcessor(int format) const override
Definition: ExportMP3.cpp:1644
std::unique_ptr< ExportOptionsEditor > CreateOptionsEditor(int, ExportOptionsEditor::Listener *listener) const override
Creates format-dependent options editor, that is used to create a valid set of parameters to be used ...
Definition: ExportMP3.cpp:1639
FormatInfo GetFormatInfo(int) const override
Returns FormatInfo structure for given index if it's valid, or a default one. FormatInfo::format isn'...
Definition: ExportMP3.cpp:1631
Listener object that is used to report on option changes.
virtual void OnExportOptionChangeEnd()=0
Called after OnExportOptionChange
virtual void OnExportOptionChangeBegin()=0
Called before OnExportOptionChange
virtual void OnExportOptionChange(const ExportOption &option)=0
Called when option change.
virtual void OnSampleRateListChange()=0
Editor objects are used to retrieve a set of export options, and configure exporting parameters accor...
std::vector< int > SampleRateList
static T GetParameterValue(const ExportProcessor::Parameters &parameters, int id, T defaultValue=T())
static ExportResult UpdateProgress(ExportProcessorDelegate &delegate, Mixer &mixer, double t0, double t1)
Sends progress update to delegate and retrieves state update from it. Typically used inside each expo...
static 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, MixerOptions::Downmix *mixerSpec)
virtual void SetStatusString(const TranslatableString &str)=0
std::vector< std::tuple< ExportOptionID, ExportValue > > Parameters
Definition: ExportPlugin.h:93
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:589
void OnBrowse(wxCommandEvent &WXUNUSED(event))
Definition: ExportMP3.cpp:546
wxFileName mLibPath
Definition: ExportMP3.cpp:582
wxString GetLibPath()
Definition: ExportMP3.cpp:572
FindDialog(wxWindow *parent, wxString path, wxString name, FileNames::FileTypes types)
Definition: ExportMP3.cpp:480
FileNames::FileTypes mTypes
Definition: ExportMP3.cpp:586
wxString mPath
Definition: ExportMP3.cpp:584
void PopulateOrExchange(ShuttleGui &S)
Definition: ExportMP3.cpp:498
void OnDownload(wxCommandEvent &WXUNUSED(event))
Definition: ExportMP3.cpp:567
wxString mName
Definition: ExportMP3.cpp:585
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
int GetOptionsCount() const override
Definition: ExportMP3.cpp:284
bool GetOption(int index, ExportOption &option) const override
Definition: ExportMP3.cpp:289
std::unordered_map< int, ExportValue > mValues
Definition: ExportMP3.cpp:271
void OnModeChange(const std::string &mode)
Definition: ExportMP3.cpp:426
bool SetValue(int id, const ExportValue &value) override
Definition: ExportMP3.cpp:299
SampleRateList GetSampleRateList() const override
Definition: ExportMP3.cpp:351
bool GetValue(int id, ExportValue &value) const override
Definition: ExportMP3.cpp:340
MP3ExportOptionsEditor(Listener *listener)
Definition: ExportMP3.cpp:275
void Load(const audacity::BasicSettings &config) override
Definition: ExportMP3.cpp:388
std::vector< ExportOption > mOptions
Definition: ExportMP3.cpp:270
void Store(audacity::BasicSettings &config) const override
Definition: ExportMP3.cpp:409
MP3Exporter exporter
Definition: ExportMP3.cpp:1574
static int AskResample(int bitrate, int rate, int lowrate, int highrate)
Definition: ExportMP3.cpp:1946
unsigned long id3len
Definition: ExportMP3.cpp:1577
bool Initialize(AudacityProject &project, const Parameters &parameters, const wxFileNameWrapper &filename, double t0, double t1, bool selectedOnly, double sampleRate, unsigned channels, MixerOptions::Downmix *mixerSpec, const Tags *tags) override
Called before start processing.
Definition: ExportMP3.cpp:1669
static unsigned long AddTags(ArrayOf< char > &buffer, bool *endOfFile, const Tags *tags)
Definition: ExportMP3.cpp:2021
ExportResult Process(ExportProcessorDelegate &delegate) override
Definition: ExportMP3.cpp:1853
wxFileOffset infoTagPos
Definition: ExportMP3.cpp:1578
ArrayOf< char > id3buffer
Definition: ExportMP3.cpp:1576
std::unique_ptr< Mixer > mixer
Definition: ExportMP3.cpp:1581
TranslatableString status
Definition: ExportMP3.cpp:1570
struct MP3ExportProcessor::@170 context
Class used to export MP3 files.
Definition: ExportMP3.cpp:691
lame_set_VBR_q_t * lame_set_VBR_q
Definition: ExportMP3.cpp:783
static const int mOutBufferSize
Definition: ExportMP3.cpp:803
lame_set_in_samplerate_t * lame_set_in_samplerate
Definition: ExportMP3.cpp:777
wxString GetLibraryVersion()
Definition: ExportMP3.cpp:1157
bool InitLibraryExternal(wxString libpath)
Definition: ExportMP3.cpp:1026
int EncodeBufferMono(float inbuffer[], unsigned char outbuffer[])
Definition: ExportMP3.cpp:1295
lame_set_disable_reservoir_t * lame_set_disable_reservoir
Definition: ExportMP3.cpp:788
int EncodeRemainderMono(float inbuffer[], int nSamples, unsigned char outbuffer[])
Definition: ExportMP3.cpp:1305
bool mLibIsExternal
Definition: ExportMP3.cpp:749
int GetOutBufferSize()
Definition: ExportMP3.cpp:1266
bool PutInfoTag(wxFFile &f, wxFileOffset off)
Definition: ExportMP3.cpp:1342
lame_mp3_tags_fid_t * lame_mp3_tags_fid
Definition: ExportMP3.cpp:791
unsigned char mInfoTagBuf[2880]
Definition: ExportMP3.cpp:807
void SetBitrate(int rate)
Definition: ExportMP3.cpp:959
size_t mInfoTagLen
Definition: ExportMP3.cpp:808
lame_init_t * lame_init
Definition: ExportMP3.cpp:769
bool ValidLibraryLoaded()
Definition: ExportMP3.cpp:947
lame_set_brate_t * lame_set_brate
Definition: ExportMP3.cpp:781
lame_encode_buffer_ieee_float_t * lame_encode_buffer_ieee_float
Definition: ExportMP3.cpp:771
lame_encode_buffer_interleaved_ieee_float_t * lame_encode_buffer_interleaved_ieee_float
Definition: ExportMP3.cpp:772
bool mEncoding
Definition: ExportMP3.cpp:761
lame_get_lametag_frame_t * lame_get_lametag_frame
Definition: ExportMP3.cpp:790
lame_set_num_channels_t * lame_set_num_channels
Definition: ExportMP3.cpp:779
void FreeLibrary()
Definition: ExportMP3.cpp:1143
int EncodeBuffer(float inbuffer[], unsigned char outbuffer[])
Definition: ExportMP3.cpp:1274
get_lame_version_t * get_lame_version
Definition: ExportMP3.cpp:775
static const int mSamplesPerChunk
Definition: ExportMP3.cpp:800
bool FindLibrary(wxWindow *parent)
Definition: ExportMP3.cpp:849
void CancelEncoding()
Definition: ExportMP3.cpp:1337
bool LoadLibrary(wxWindow *parent, AskUser askuser)
Definition: ExportMP3.cpp:884
wxString GetLibraryName()
Definition: ExportMP3.cpp:1393
lame_set_VBR_t * lame_set_VBR
Definition: ExportMP3.cpp:782
FileNames::FileTypes GetLibraryTypes()
Definition: ExportMP3.cpp:1398
wxDynamicLibrary lame_lib
Definition: ExportMP3.cpp:753
bool InitLibrary(wxString libpath)
Definition: ExportMP3.cpp:969
lame_global_flags * mGF
Definition: ExportMP3.cpp:798
wxString GetLibraryPath()
Definition: ExportMP3.cpp:1375
lame_close_t * lame_close
Definition: ExportMP3.cpp:774
int FinishStream(unsigned char outbuffer[])
Definition: ExportMP3.cpp:1316
lame_set_quality_t * lame_set_quality
Definition: ExportMP3.cpp:780
wxString mLibPath
Definition: ExportMP3.cpp:752
beWriteInfoTag_t * beWriteInfoTag
Definition: ExportMP3.cpp:793
lame_encode_flush_t * lame_encode_flush
Definition: ExportMP3.cpp:773
void SetMode(int mode)
Definition: ExportMP3.cpp:954
int InitializeStream(unsigned channels, int sampleRate)
Definition: ExportMP3.cpp:1168
lame_set_error_protection_t * lame_set_error_protection
Definition: ExportMP3.cpp:787
lame_set_VBR_min_bitrate_kbps_t * lame_set_VBR_min_bitrate_kbps
Definition: ExportMP3.cpp:784
void SetQuality(int q)
Definition: ExportMP3.cpp:964
bool InitLibraryInternal()
Definition: ExportMP3.cpp:974
int EncodeRemainder(float inbuffer[], int nSamples, unsigned char outbuffer[])
Definition: ExportMP3.cpp:1284
lame_set_out_samplerate_t * lame_set_out_samplerate
Definition: ExportMP3.cpp:778
lame_set_mode_t * lame_set_mode
Definition: ExportMP3.cpp:785
TranslatableString mBladeVersion
Definition: ExportMP3.cpp:758
lame_set_bWriteVbrTag_t * lame_set_bWriteVbrTag
Definition: ExportMP3.cpp:789
lame_init_params_t * lame_init_params
Definition: ExportMP3.cpp:770
bool mLibraryLoaded
Definition: ExportMP3.cpp:754
beVersion_t * beVersion
Definition: ExportMP3.cpp:794
lame_set_preset_t * lame_set_preset
Definition: ExportMP3.cpp:786
A matrix of booleans, one row per input channel, column per output.
Definition: MixerOptions.h:32
static ProjectWindow * Find(AudacityProject *pProject)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:630
ID3 Tags (for MP3)
Definition: Tags.h:73
Iterators GetRange() const
Definition: Tags.cpp:426
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:214
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:354
Holds a msgid for the translation catalog; may also bind format arguments.
Base class for objects that provide facility to store data persistently, and access it with string ke...
Definition: BasicSettings.h:31
virtual bool Flush() noexcept=0
virtual bool Write(const wxString &key, bool value)=0
virtual bool Read(const wxString &key, bool *value) const =0
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
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:274
FILES_API FilePath PathFromAddr(void *addr)
BuiltinCommandsModule::Registration< CompareAudioCommand > reg
int ValidateIndex(const std::vector< int > &values, int value, int defaultIndex)
Definition: ExportMP3.cpp:458
int ValidateValue(const std::vector< int > &values, int value, int defaultValue)
Definition: ExportMP3.cpp:451
A type that provides a description of an exporting option. Isn't allowed to change except non-type re...
Definition: ExportTypes.h:43
@ TypeEnum
List/enum option. values holds items, and names text to be displayed.
Definition: ExportTypes.h:48
@ Hidden
Option is not used and may be hidden from the user.
Definition: ExportTypes.h:51
BYTE byMinorVersion
Definition: ExportMP3.cpp:669
BYTE byDLLMinorVersion
Definition: ExportMP3.cpp:664
BYTE byBetaLevel
Definition: ExportMP3.cpp:682
BYTE byMMXEnabled
Definition: ExportMP3.cpp:683
BYTE byMajorVersion
Definition: ExportMP3.cpp:668
BYTE byAlphaLevel
Definition: ExportMP3.cpp:681
BYTE byDLLMajorVersion
Definition: ExportMP3.cpp:663
BYTE byMonth
Definition: ExportMP3.cpp:674