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