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