Audacity  2.3.1
Export.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  Export.cpp
6 
7  Dominic Mazzoni
8 
9 *******************************************************************//****************************************************************//****************************************************************//****************************************************************//********************************************************************/
30 
31 #include "../Audacity.h"
32 #include "Export.h"
33 
34 #include <wx/file.h>
35 #include <wx/filename.h>
36 #include <wx/progdlg.h>
37 #include <wx/sizer.h>
38 #include <wx/slider.h>
39 #include <wx/statbox.h>
40 #include <wx/stattext.h>
41 #include <wx/string.h>
42 #include <wx/textctrl.h>
43 #include <wx/timer.h>
44 #include <wx/dcmemory.h>
45 #include <wx/window.h>
46 
47 #include "ExportPCM.h"
48 #include "ExportMP3.h"
49 #include "ExportOGG.h"
50 #include "ExportFLAC.h"
51 #include "ExportCL.h"
52 #include "ExportMP2.h"
53 #include "ExportFFmpeg.h"
54 
55 #include "sndfile.h"
56 
57 #include "FileDialog.h"
58 
59 #include "../DirManager.h"
60 #include "../FileFormats.h"
61 #include "../Internat.h"
62 #include "../Menus.h"
63 #include "../Mix.h"
64 #include "../Prefs.h"
65 #include "../Project.h"
66 #include "../ShuttleGui.h"
67 #include "../WaveTrack.h"
68 #include "../widgets/ErrorDialog.h"
69 #include "../widgets/Warning.h"
70 #include "../widgets/HelpSystem.h"
71 #include "../AColor.h"
72 #include "../Dependencies.h"
73 #include "../FileNames.h"
74 #include "../widgets/HelpSystem.h"
75 
76 //----------------------------------------------------------------------------
77 // ExportPlugin
78 //----------------------------------------------------------------------------
79 
81 {
82 }
83 
85 {
86 }
87 
88 bool ExportPlugin::CheckFileName(wxFileName & WXUNUSED(filename), int WXUNUSED(format))
89 {
90  return true;
91 }
92 
101 {
102  FormatInfo nf;
103  mFormatInfos.push_back(nf);
104  return mFormatInfos.size();
105 }
106 
108 {
109  return mFormatInfos.size();
110 }
111 
116 void ExportPlugin::SetFormat(const wxString & format, int index)
117 {
118  mFormatInfos[index].mFormat = format;
119 }
120 
121 void ExportPlugin::SetDescription(const wxString & description, int index)
122 {
123  mFormatInfos[index].mDescription = description;
124 }
125 
126 void ExportPlugin::AddExtension(const wxString &extension,int index)
127 {
128  mFormatInfos[index].mExtensions.Add(extension);
129 }
130 
131 void ExportPlugin::SetExtensions(const wxArrayString & extensions, int index)
132 {
133  mFormatInfos[index].mExtensions = extensions;
134 }
135 
136 void ExportPlugin::SetMask(const wxString & mask, int index)
137 {
138  mFormatInfos[index].mMask = mask;
139 }
140 
141 void ExportPlugin::SetMaxChannels(unsigned maxchannels, unsigned index)
142 {
143  mFormatInfos[index].mMaxChannels = maxchannels;
144 }
145 
146 void ExportPlugin::SetCanMetaData(bool canmetadata, int index)
147 {
148  mFormatInfos[index].mCanMetaData = canmetadata;
149 }
150 
151 wxString ExportPlugin::GetFormat(int index)
152 {
153  return mFormatInfos[index].mFormat;
154 }
155 
156 wxString ExportPlugin::GetDescription(int index)
157 {
158  return mFormatInfos[index].mDescription;
159 }
160 
161 wxString ExportPlugin::GetExtension(int index)
162 {
163  return mFormatInfos[index].mExtensions[0];
164 }
165 
166 wxArrayString ExportPlugin::GetExtensions(int index)
167 {
168  return mFormatInfos[index].mExtensions;
169 }
170 
171 wxString ExportPlugin::GetMask(int index)
172 {
173  if (!mFormatInfos[index].mMask.IsEmpty()) {
174  return mFormatInfos[index].mMask;
175  }
176 
177  wxString mask = GetDescription(index) + wxT("|");
178 
179  // Build the mask
180  // wxString ext = GetExtension(index);
181  wxArrayString exts = GetExtensions(index);
182  for (size_t i = 0; i < exts.GetCount(); i++) {
183  mask += wxT("*.") + exts[i] + wxT(";");
184  }
185 
186  return mask;
187 }
188 
189 unsigned ExportPlugin::GetMaxChannels(int index)
190 {
191  return mFormatInfos[index].mMaxChannels;
192 }
193 
195 {
196  return mFormatInfos[index].mCanMetaData;
197 }
198 
199 bool ExportPlugin::IsExtension(const wxString & ext, int index)
200 {
201  bool isext = false;
202  for (int i = index; i < GetFormatCount(); i = GetFormatCount())
203  {
204  wxString defext = GetExtension(i);
205  wxArrayString defexts = GetExtensions(i);
206  int indofext = defexts.Index(ext, false);
207  if (defext == wxT("") || (indofext != wxNOT_FOUND))
208  isext = true;
209  }
210  return isext;
211 }
212 
213 bool ExportPlugin::DisplayOptions(wxWindow * WXUNUSED(parent), int WXUNUSED(format))
214 {
215  return false;
216 }
217 
218 wxWindow *ExportPlugin::OptionsCreate(wxWindow *parent, int WXUNUSED(format))
219 {
220  wxASSERT(parent); // To justify safenew
221  wxPanel *p = safenew wxPanelWrapper(parent, wxID_ANY);
223 
224  S.StartHorizontalLay(wxCENTER);
225  {
226  S.StartHorizontalLay(wxCENTER, 0);
227  {
228  S.Prop(1).AddTitle(_("No format specific options"));
229  }
230  S.EndHorizontalLay();
231  }
232  S.EndHorizontalLay();
233 
234  return p;
235 }
236 
237 //Create a mixer by computing the time warp factor
238 std::unique_ptr<Mixer> ExportPlugin::CreateMixer(const WaveTrackConstArray &inputTracks,
239  const TimeTrack *timeTrack,
240  double startTime, double stopTime,
241  unsigned numOutChannels, size_t outBufferSize, bool outInterleaved,
242  double outRate, sampleFormat outFormat,
243  bool highQuality, MixerSpec *mixerSpec)
244 {
245  // MB: the stop time should not be warped, this was a bug.
246  return std::make_unique<Mixer>(inputTracks,
247  // Throw, to stop exporting, if read fails:
248  true,
249  Mixer::WarpOptions(timeTrack),
250  startTime, stopTime,
251  numOutChannels, outBufferSize, outInterleaved,
252  outRate, outFormat,
253  highQuality, mixerSpec);
254 }
255 
256 void ExportPlugin::InitProgress(std::unique_ptr<ProgressDialog> &pDialog,
257  const wxString &title, const wxString &message)
258 {
259  if (!pDialog)
260  pDialog = std::make_unique<ProgressDialog>( title, message );
261  else {
262  pDialog->SetTitle( title );
263  pDialog->SetMessage( message );
264  pDialog->Reinit();
265  }
266 }
267 
268 //----------------------------------------------------------------------------
269 // Export
270 //----------------------------------------------------------------------------
271 
272 
273 wxDEFINE_EVENT(AUDACITY_FILE_SUFFIX_EVENT, wxCommandEvent);
274 
275 BEGIN_EVENT_TABLE(Exporter, wxEvtHandler)
276  EVT_FILECTRL_FILTERCHANGED(wxID_ANY, Exporter::OnFilterChanged)
277  EVT_BUTTON(wxID_HELP, Exporter::OnHelp)
278  EVT_COMMAND( wxID_ANY, AUDACITY_FILE_SUFFIX_EVENT, Exporter::OnExtensionChanged)
280 
282 {
283  mMixerSpec = NULL;
284  mBook = NULL;
285  mFormatName = "";
286 
287  SetFileDialogTitle( _("Export Audio") );
288 
289  RegisterPlugin(New_ExportPCM());
290  RegisterPlugin(New_ExportMP3());
291 
292 #ifdef USE_LIBVORBIS
293  RegisterPlugin(New_ExportOGG());
294 #endif
295 
296 #ifdef USE_LIBFLAC
297  RegisterPlugin(New_ExportFLAC());
298 #endif
299 
300 #if USE_LIBTWOLAME
301  RegisterPlugin(New_ExportMP2());
302 #endif
303 
304  // Command line export not available on Windows and Mac platforms
305  RegisterPlugin(New_ExportCL());
306 
307 #if defined(USE_FFMPEG)
308  RegisterPlugin(New_ExportFFmpeg());
309 #endif
310 }
311 
313 {
314 }
315 
316 // Beginnings of a fix for bug 1355.
317 // 'Other Uncompressed Files' Header option updates do not update
318 // the extension shown in the file dialog.
319 // Unfortunately, although we get the new extension here, we
320 // can't do anything with it as the FileDialog does not provide
321 // methods for setting its standard controls.
322 // We would need OS specific code that 'knows' about the system
323 // dialogs.
324 void Exporter::OnExtensionChanged(wxCommandEvent &evt) {
325  wxString ext = evt.GetString();
326  ext = ext.BeforeFirst(' ').Lower();
327  wxLogDebug("Extension changed to '.%s'", ext);
328 // wxString Name = mDialog->GetFilename();
329 // Name = Name.BeforeLast('.')+ext;
330 // mDialog->SetFilename(Name);
331 }
332 
333 void Exporter::OnHelp(wxCommandEvent& WXUNUSED(evt))
334 {
335  wxWindow * pWin = GetActiveProject();
336  HelpSystem::ShowHelp(pWin, wxT("File_Export_Dialog"), true);
337 }
338 
339 void Exporter::SetFileDialogTitle( const wxString & DialogTitle )
340 {
341  // The default title is "Export File"
342  mFileDialogTitle = DialogTitle;
343 }
344 
345 int Exporter::FindFormatIndex(int exportindex)
346 {
347  int c = 0;
348  for (const auto &pPlugin : mPlugins)
349  {
350  for (int j = 0; j < pPlugin->GetFormatCount(); j++)
351  {
352  if (exportindex == c) return j;
353  c++;
354  }
355  }
356  return 0;
357 }
358 
359 void Exporter::RegisterPlugin(std::unique_ptr<ExportPlugin> &&ExportPlugin)
360 {
361  mPlugins.push_back(std::move(ExportPlugin));
362 }
363 
365 {
366  return mPlugins;
367 }
368 
369 bool Exporter::Process(AudacityProject *project, bool selectedOnly, double t0, double t1)
370 {
371  // Save parms
372  mProject = project;
373  mSelectedOnly = selectedOnly;
374  mT0 = t0;
375  mT1 = t1;
376 
377  // Gather track information
378  if (!ExamineTracks()) {
379  return false;
380  }
381 
382  // Ask user for file name
383  if (!GetFilename()) {
384  return false;
385  }
386 
387  // Check for down mixing
388  if (!CheckMix()) {
389  return false;
390  }
391 
392  // Let user edit MetaData
393  if (mPlugins[mFormat]->GetCanMetaData(mSubFormat)) {
394  if (!(GetMenuCommandHandler(*project).DoEditMetadata( *project,
395  _("Edit Metadata Tags"), _("Exported Tags"),
396  mProject->GetShowId3Dialog()))) {
397  return false;
398  }
399  }
400 
401  // Ensure filename doesn't interfere with project files.
402  if (!CheckFilename()) {
403  return false;
404  }
405 
406  // Export the tracks
407  bool success = ExportTracks();
408 
409  // Get rid of mixerspec
410  mMixerSpec.reset();
411 
412  return success;
413 }
414 
415 bool Exporter::Process(AudacityProject *project, unsigned numChannels,
416  const wxChar *type, const wxString & filename,
417  bool selectedOnly, double t0, double t1)
418 {
419  // Save parms
420  mProject = project;
421  mChannels = numChannels;
422  mFilename = filename;
423  mSelectedOnly = selectedOnly;
424  mT0 = t0;
425  mT1 = t1;
427 
428  int i = -1;
429  for (const auto &pPlugin : mPlugins) {
430  ++i;
431  for (int j = 0; j < pPlugin->GetFormatCount(); j++)
432  {
433  if (pPlugin->GetFormat(j).IsSameAs(type, false))
434  {
435  mFormat = i;
436  mSubFormat = j;
437  return CheckFilename() && ExportTracks();
438  }
439  }
440  }
441 
442  return false;
443 }
444 
446 {
447  // Init
448  mNumSelected = 0;
449  mNumLeft = 0;
450  mNumRight = 0;
451  mNumMono = 0;
452 
453  // First analyze the selected audio, perform sanity checks, and provide
454  // information as appropriate.
455 
456  // Tally how many are right, left, mono, and make sure at
457  // least one track is selected (if selectedOnly==true)
458 
459  double earliestBegin = mT1;
460  double latestEnd = mT0;
461 
462  const TrackList *tracks = mProject->GetTracks();
463 
464  for (auto tr :
465  tracks->Any< const WaveTrack >()
468  ) {
469  mNumSelected++;
470 
471  if (tr->GetChannel() == Track::LeftChannel) {
472  mNumLeft++;
473  }
474  else if (tr->GetChannel() == Track::RightChannel) {
475  mNumRight++;
476  }
477  else if (tr->GetChannel() == Track::MonoChannel) {
478  // It's a mono channel, but it may be panned
479  float pan = tr->GetPan();
480 
481  if (pan == -1.0)
482  mNumLeft++;
483  else if (pan == 1.0)
484  mNumRight++;
485  else if (pan == 0)
486  mNumMono++;
487  else {
488  // Panned partially off-center. Mix as stereo.
489  mNumLeft++;
490  mNumRight++;
491  }
492  }
493 
494  if (tr->GetOffset() < earliestBegin) {
495  earliestBegin = tr->GetOffset();
496  }
497 
498  if (tr->GetEndTime() > latestEnd) {
499  latestEnd = tr->GetEndTime();
500  }
501  }
502 
503  if (mNumSelected == 0) {
504  wxString message;
505  if(mSelectedOnly)
506  message = _("All selected audio is muted.");
507  else
508  message = _("All audio is muted.");
509  AudacityMessageBox(message,
510  _("Unable to export"),
511  wxOK | wxICON_INFORMATION);
512  return false;
513  }
514 
515  if (mT0 < earliestBegin)
516  mT0 = earliestBegin;
517 
518  if (mT1 > latestEnd)
519  mT1 = latestEnd;
520 
521  return true;
522 }
523 
525 {
526  mFormat = -1;
527 
528  wxString maskString;
529  wxString defaultFormat = mFormatName;
530  if( defaultFormat.IsEmpty() )
531  defaultFormat = gPrefs->Read(wxT("/Export/Format"),
532  wxT("WAV"));
533 
534  mFilterIndex = 0;
535 
536  {
537  int i = -1;
538  for (const auto &pPlugin : mPlugins) {
539  ++i;
540  for (int j = 0; j < pPlugin->GetFormatCount(); j++)
541  {
542  maskString += pPlugin->GetMask(j) + wxT("|");
543  if (mPlugins[i]->GetFormat(j) == defaultFormat) {
544  mFormat = i;
545  mSubFormat = j;
546  }
547  if (mFormat == -1) mFilterIndex++;
548  }
549  }
550  }
551  if (mFormat == -1)
552  {
553  mFormat = 0;
554  mFilterIndex = 0;
555  mSubFormat = 0;
556  }
557  maskString.RemoveLast();
558  wxString defext = mPlugins[mFormat]->GetExtension(mSubFormat).Lower();
559 
560 //Bug 1304: Set a default path if none was given. For Export.
561  mFilename = FileNames::DefaultToDocumentsFolder(wxT("/Export/Path"));
562  mFilename.SetName(mProject->GetName());
563  if (mFilename.GetName().empty())
564  mFilename.SetName(_("untitled"));
565  while (true) {
566  // Must reset each iteration
567  mBook = NULL;
568 
569  {
570  auto useFileName = mFilename;
571  if (!useFileName.HasExt())
572  useFileName.SetExt(defext);
575  mFilename.GetPath(),
576  useFileName.GetFullName(),
577  maskString,
578  wxFD_SAVE | wxRESIZE_BORDER);
579  mDialog = &fd;
580  mDialog->PushEventHandler(this);
581 
582  fd.SetUserPaneCreator(CreateUserPaneCallback, (wxUIntPtr) this);
583  fd.SetFilterIndex(mFilterIndex);
584 
585  int result = fd.ShowModal();
586 
587  mDialog->PopEventHandler();
588 
589  if (result == wxID_CANCEL) {
590  return false;
591  }
592 
593  mFilename = fd.GetPath();
594  if (mFilename == wxT("")) {
595  return false;
596  }
597 
598  mFormat = fd.GetFilterIndex();
599  mFilterIndex = fd.GetFilterIndex();
600  }
601 
602  {
603  int c = 0;
604  int i = -1;
605  for (const auto &pPlugin : mPlugins)
606  {
607  ++i;
608  for (int j = 0; j < pPlugin->GetFormatCount(); j++)
609  {
610  if (mFilterIndex == c)
611  {
612  mFormat = i;
613  mSubFormat = j;
614  }
615  c++;
616  }
617  }
618  }
619 
620  wxString ext = mFilename.GetExt();
621  defext = mPlugins[mFormat]->GetExtension(mSubFormat).Lower();
622 
623  //
624  // Check the extension - add the default if it's not there,
625  // and warn user if it's abnormal.
626  //
627  if (ext.IsEmpty()) {
628  //
629  // Make sure the user doesn't accidentally save the file
630  // as an extension with no name, like just plain ".wav".
631  //
632  if (mFilename.GetName().Left(1) == wxT(".")) {
633  wxString prompt = wxString::Format(
634  _("Are you sure you want to export the file as \"%s\"?\n"),
635  mFilename.GetFullName() );
636 
637  int action = AudacityMessageBox(prompt,
638  _("Warning"),
639  wxYES_NO | wxICON_EXCLAMATION);
640  if (action != wxYES) {
641  continue;
642  }
643  }
644 
645  mFilename.SetExt(defext);
646  }
647  else if (!mPlugins[mFormat]->CheckFileName(mFilename, mSubFormat))
648  {
649  continue;
650  }
651  else if (!ext.IsEmpty() && !mPlugins[mFormat]->IsExtension(ext,mSubFormat) && ext.CmpNoCase(defext)) {
652  wxString prompt;
653  prompt.Printf(_("You are about to export a %s file with the name \"%s\".\n\nNormally these files end in \".%s\", and some programs will not open files with nonstandard extensions.\n\nAre you sure you want to export the file under this name?"),
654  mPlugins[mFormat]->GetFormat(mSubFormat),
655  mFilename.GetFullName(),
656  defext);
657 
658  int action = AudacityMessageBox(prompt,
659  _("Warning"),
660  wxYES_NO | wxICON_EXCLAMATION);
661  if (action != wxYES) {
662  continue;
663  }
664  }
665 
666  if (mFilename.GetFullPath().Length() >= 256) {
667  AudacityMessageBox(_("Sorry, pathnames longer than 256 characters not supported."));
668  continue;
669  }
670 
671  // Check to see if we are writing to a path that a missing aliased file existed at.
672  // This causes problems for the exporter, so we don't allow it.
673  // Overwritting non-missing aliased files is okay.
674  // Also, this can only happen for uncompressed audio.
675  bool overwritingMissingAlias;
676  overwritingMissingAlias = false;
677  for (size_t i = 0; i < gAudacityProjects.size(); i++) {
678  AliasedFileArray aliasedFiles;
679  FindDependencies(gAudacityProjects[i].get(), aliasedFiles);
680  for (const auto &aliasedFile : aliasedFiles) {
681  if (mFilename.GetFullPath() == aliasedFile.mFileName.GetFullPath() &&
682  !mFilename.FileExists()) {
683  // Warn and return to the dialog
684  AudacityMessageBox(_("You are attempting to overwrite an aliased file that is missing.\n\
685  The file cannot be written because the path is needed to restore the original audio to the project.\n\
686  Choose Help > Diagnostics > Check Dependencies to view the locations of all missing files.\n\
687  If you still wish to export, please choose a different filename or folder."));
688  overwritingMissingAlias = true;
689  }
690  }
691  }
692  if (overwritingMissingAlias)
693  continue;
694 
695  if (mFilename.FileExists()) {
696  wxString prompt;
697 
698  prompt.Printf(_("A file named \"%s\" already exists. Replace?"),
699  mFilename.GetFullPath());
700 
701  int action = AudacityMessageBox(prompt,
702  _("Warning"),
703  wxYES_NO | wxICON_EXCLAMATION);
704  if (action != wxYES) {
705  continue;
706  }
707  }
708 
709  break;
710  }
711 
712  return true;
713 }
714 
715 //
716 // For safety, if the file already exists it stores the filename
717 // the user wants in actualName, and returns a temporary file name.
718 // The calling function should rename the file when it's successfully
719 // exported.
720 //
722 {
723  //
724  // Ensure that exporting a file by this name doesn't overwrite
725  // one of the existing files in the project. (If it would
726  // overwrite an existing file, DirManager tries to rename the
727  // existing file.)
728  //
729 
730  if (!mProject->GetDirManager()->EnsureSafeFilename(mFilename))
731  return false;
732 
733  if( mFormatName.IsEmpty() )
734  gPrefs->Write(wxT("/Export/Format"), mPlugins[mFormat]->GetFormat(mSubFormat));
735  gPrefs->Write(wxT("/Export/Path"), mFilename.GetPath());
736  gPrefs->Flush();
737 
738  //
739  // To be even safer, return a temporary file name based
740  // on this one...
741  //
742 
744 
745  int suffix = 0;
746  while (mFilename.FileExists()) {
747  mFilename.SetName(mActualName.GetName() +
748  wxString::Format(wxT("%d"), suffix));
749  suffix++;
750  }
751 
752  return true;
753 }
754 
756 {
757  int c = 0;
758  int mf = -1, msf = -1;
759  int i = -1;
760  for (const auto &pPlugin : mPlugins)
761  {
762  ++i;
763  for (int j = 0; j < pPlugin->GetFormatCount(); j++)
764  {
765  if (index == c)
766  {
767  mf = i;
768  msf = j;
769  }
770  c++;
771  }
772  }
773  // This shouldn't happen...
774  if (index >= c) {
775  return;
776  }
777 
778 #if defined(__WXMSW__)
779  mPlugins[mf]->DisplayOptions(mProject, msf);
780 #else
781  mPlugins[mf]->DisplayOptions(mDialog, msf);
782 #endif
783 }
784 
786 {
787  // Clean up ... should never happen
788  mMixerSpec.reset();
789 
790  // Detemine if exported file will be stereo or mono or multichannel,
791  // and if mixing will occur.
792 
793  int downMix = gPrefs->Read(wxT("/FileFormats/ExportDownMix"), true);
794  int exportedChannels = mPlugins[mFormat]->SetNumExportChannels();
795 
796  if (downMix) {
797  if (mNumRight > 0 || mNumLeft > 0) {
798  mChannels = 2;
799  }
800  else {
801  mChannels = 1;
802  }
804  mPlugins[mFormat]->GetMaxChannels(mSubFormat));
805 
806  auto numLeft = mNumLeft + mNumMono;
807  auto numRight = mNumRight + mNumMono;
808 
809  if (numLeft > 1 || numRight > 1 || mNumLeft + mNumRight + mNumMono > mChannels) {
810  wxString exportFormat = mPlugins[mFormat]->GetFormat(mSubFormat);
811  if (exportFormat != wxT("CL") && exportFormat != wxT("FFMPEG") && exportedChannels == -1)
812  exportedChannels = mChannels;
813 
814  if (exportedChannels == 1) {
816  wxT("MixMono"),
817  _("Your tracks will be mixed down and exported as one mono file."),
818  true) == wxID_CANCEL)
819  return false;
820  }
821  else if (exportedChannels == 2) {
823  wxT("MixStereo"),
824  _("Your tracks will be mixed down and exported as one stereo file."),
825  true) == wxID_CANCEL)
826  return false;
827  }
828  else {
830  wxT("MixUnknownChannels"),
831  _("Your tracks will be mixed down to one exported file according to the encoder settings."),
832  true) == wxID_CANCEL)
833  return false;
834  }
835  }
836  }
837  else
838  {
839  if (exportedChannels < 0)
840  exportedChannels = mPlugins[mFormat]->GetMaxChannels(mSubFormat);
841 
844  exportedChannels,
845  NULL,
846  1,
847  _("Advanced Mixing Options"));
848 
849  if (md.ShowModal() != wxID_OK) {
850  return false;
851  }
852 
853  mMixerSpec = std::make_unique<MixerSpec>(*(md.GetMixerSpec()));
854  mChannels = mMixerSpec->GetNumChannels();
855  }
856 
857  return true;
858 }
859 
861 {
862  // Keep original in case of failure
863  if (mActualName != mFilename) {
864  ::wxRenameFile(mActualName.GetFullPath(), mFilename.GetFullPath());
865  }
866 
867  bool success = false;
868 
869  auto cleanup = finally( [&] {
870  if (mActualName != mFilename) {
871  // Remove backup
872  if ( success )
873  ::wxRemoveFile(mFilename.GetFullPath());
874  else {
875  // Restore original, if needed
876  ::wxRemoveFile(mActualName.GetFullPath());
877  ::wxRenameFile(mFilename.GetFullPath(), mActualName.GetFullPath());
878  }
879  }
880  else {
881  if ( ! success )
882  // Remove any new, and only partially written, file.
883  ::wxRemoveFile(mFilename.GetFullPath());
884  }
885  } );
886 
887  std::unique_ptr<ProgressDialog> pDialog;
888  auto result = mPlugins[mFormat]->Export(mProject,
889  pDialog,
890  mChannels,
891  mActualName.GetFullPath(),
893  mT0,
894  mT1,
895  mMixerSpec.get(),
896  NULL,
897  mSubFormat);
898 
899  success =
900  result == ProgressResult::Success || result == ProgressResult::Stopped;
901 
902  return success;
903 }
904 
905 void Exporter::CreateUserPaneCallback(wxWindow *parent, wxUIntPtr userdata)
906 {
907  Exporter *self = (Exporter *) userdata;
908  if (self)
909  {
910  self->CreateUserPane(parent);
911  }
912 }
913 
914 void Exporter::CreateUserPane(wxWindow *parent)
915 {
916  ShuttleGui S(parent, eIsCreating);
917 
918  S.StartVerticalLay();
919  {
920  S.StartHorizontalLay(wxEXPAND);
921  {
922  S.StartStatic(_("Format Options"), 1);
923  {
924  mBook = safenew wxSimplebook(S.GetParent());
925  S.AddWindow(mBook, wxEXPAND);
926 
927  for (const auto &pPlugin : mPlugins)
928  {
929  for (int j = 0; j < pPlugin->GetFormatCount(); j++)
930  {
931  mBook->AddPage(pPlugin->OptionsCreate(mBook, j), wxEmptyString);
932  }
933  }
934  }
935  S.EndStatic();
936  }
937  S.EndHorizontalLay();
938  }
939  S.StartHorizontalLay(wxALIGN_RIGHT, 0);
940  {
942  }
943  S.EndHorizontalLay();
944  S.EndVerticalLay();
945 
946  return;
947 }
948 
949 void Exporter::OnFilterChanged(wxFileCtrlEvent & evt)
950 {
951  int index = evt.GetFilterIndex();
952 
953  // On GTK, this event can fire before the userpane is created
954  if (mBook == NULL || index < 0 || index >= (int) mBook->GetPageCount())
955  {
956  return;
957  }
958 
959  mBook->ChangeSelection(index);
960 }
961 
963  bool selectedOnly,
964  double t0,
965  double t1,
966  wxFileName fnFile,
967  int iFormat,
968  int iSubFormat,
969  int iFilterIndex)
970 {
971  // Save parms
972  mProject = project;
973  mSelectedOnly = selectedOnly;
974  mT0 = t0;
975  mT1 = t1;
976 
977  // Auto Export Parameters
978  mFilename = fnFile;
979  mFormat = iFormat;
980  mSubFormat = iSubFormat;
981  mFilterIndex = iFilterIndex;
982 
983  // Gather track information
984  if (!ExamineTracks()) {
985  return false;
986  }
987 
988  // Check for down mixing
989  if (!CheckMix()) {
990  return false;
991  }
992 
993  // Ensure filename doesn't interfere with project files.
994  if (!CheckFilename()) {
995  return false;
996  }
997 
998  // Export the tracks
999  bool success = ExportTracks();
1000 
1001  // Get rid of mixerspec
1002  mMixerSpec.reset();
1003 
1004  return success;
1005 }
1006 
1008  return mFormat;
1009 }
1010 
1012  return mSubFormat;
1013 }
1014 
1016  return mFormat;
1017 }
1018 
1020  return mFilename;
1021 }
1022 
1024  mFormat = -1;
1025  mProject = project;
1026 
1027  if( GetFilename()==false )
1028  return false;
1029 
1030  // Let user edit MetaData
1031  if (mPlugins[mFormat]->GetCanMetaData(mSubFormat)) {
1032  if (!(GetMenuCommandHandler(*project).DoEditMetadata( *project,
1033  _("Edit Metadata Tags"),
1034  _("Exported Tags"), mProject->GetShowId3Dialog()))) {
1035  return false;
1036  }
1037  }
1038 
1039  return true;
1040 }
1041 
1042 //----------------------------------------------------------------------------
1043 // ExportMixerPanel
1044 //----------------------------------------------------------------------------
1045 
1046 BEGIN_EVENT_TABLE(ExportMixerPanel, wxPanelWrapper)
1047  EVT_PAINT(ExportMixerPanel::OnPaint)
1048  EVT_MOUSE_EVENTS(ExportMixerPanel::OnMouseEvent)
1050 
1051 ExportMixerPanel::ExportMixerPanel( wxWindow *parent, wxWindowID id,
1052  MixerSpec *mixerSpec,
1053  wxArrayString trackNames,
1054  const wxPoint& pos, const wxSize& size):
1055  wxPanelWrapper(parent, id, pos, size)
1056  , mMixerSpec{mixerSpec}
1057  , mChannelRects{ mMixerSpec->GetMaxNumChannels() }
1058  , mTrackRects{ mMixerSpec->GetNumTracks() }
1059 {
1060  mBitmap = NULL;
1061  mWidth = 0;
1062  mHeight = 0;
1063  mSelectedTrack = mSelectedChannel = -1;
1064 
1065  mTrackNames = trackNames;
1066 }
1067 
1069 {
1070 }
1071 
1072 //set the font on memDC such that text can fit in specified width and height
1073 void ExportMixerPanel::SetFont(wxMemoryDC &memDC, const wxString &text, int width,
1074  int height )
1075 {
1076  int l = 0, u = 13, m, w, h;
1077  wxFont font = memDC.GetFont();
1078  while( l < u - 1 )
1079  {
1080  m = ( l + u ) / 2;
1081  font.SetPointSize( m );
1082  memDC.SetFont( font );
1083  memDC.GetTextExtent( text, &w, &h );
1084 
1085  if( w < width && h < height )
1086  l = m;
1087  else
1088  u = m;
1089  }
1090  font.SetPointSize( l );
1091  memDC.SetFont( font );
1092 }
1093 
1094 void ExportMixerPanel::OnPaint(wxPaintEvent & WXUNUSED(event))
1095 {
1096  wxPaintDC dc( this );
1097 
1098  int width, height;
1099  GetSize( &width, &height );
1100 
1101  if( !mBitmap || mWidth != width || mHeight != height )
1102  {
1103  mWidth = width;
1104  mHeight = height;
1105  mBitmap = std::make_unique<wxBitmap>( mWidth, mHeight,24 );
1106  }
1107 
1108  wxColour bkgnd = GetBackgroundColour();
1109  wxBrush bkgndBrush( bkgnd, wxBRUSHSTYLE_SOLID );
1110 
1111  wxMemoryDC memDC;
1112  memDC.SelectObject( *mBitmap );
1113 
1114  //draw background
1115  wxRect bkgndRect;
1116  bkgndRect.x = 0;
1117  bkgndRect.y = 0;
1118  bkgndRect.width = mWidth;
1119  bkgndRect.height = mHeight;
1120 
1121  memDC.SetBrush( *wxWHITE_BRUSH );
1122  memDC.SetPen( *wxBLACK_PEN );
1123  memDC.DrawRectangle( bkgndRect );
1124 
1125  //box dimensions
1126  mBoxWidth = mWidth / 6;
1127 
1128  mTrackHeight = ( mHeight * 3 ) / ( mMixerSpec->GetNumTracks() * 4 );
1129  if( mTrackHeight > 30 )
1130  mTrackHeight = 30;
1131 
1132  mChannelHeight = ( mHeight * 3 ) / ( mMixerSpec->GetNumChannels() * 4 );
1133  if( mChannelHeight > 30 )
1134  mChannelHeight = 30;
1135 
1136  static double PI = 2 * acos( 0.0 );
1137  double angle = atan( ( 3.0 * mHeight ) / mWidth );
1138  double radius = mHeight / ( 2.0 * sin( PI - 2.0 * angle ) );
1139  double totAngle = ( asin( mHeight / ( 2.0 * radius ) ) * 2.0 );
1140 
1141  //draw tracks
1142  memDC.SetBrush( AColor::envelopeBrush );
1143  angle = totAngle / ( mMixerSpec->GetNumTracks() + 1 );
1144 
1145  int max = 0, w, h;
1146  for( unsigned int i = 1; i < mMixerSpec->GetNumTracks(); i++ )
1147  if( mTrackNames[ i ].length() > mTrackNames[ max ].length() )
1148  max = i;
1149 
1150  SetFont( memDC, mTrackNames[ max ], mBoxWidth, mTrackHeight );
1151 
1152  for( unsigned int i = 0; i < mMixerSpec->GetNumTracks(); i++ )
1153  {
1154  mTrackRects[ i ].x = (int)( mBoxWidth * 2 + radius - radius *
1155  cos( totAngle / 2.0 - angle * ( i + 1 ) ) - mBoxWidth + 0.5 );
1156  mTrackRects[ i ].y = (int)( mHeight * 0.5 - radius *
1157  sin( totAngle * 0.5 - angle * ( i + 1.0 ) ) -
1158  0.5 * mTrackHeight + 0.5 );
1159 
1160  mTrackRects[ i ].width = mBoxWidth;
1161  mTrackRects[ i ].height = mTrackHeight;
1162 
1163  memDC.SetPen( mSelectedTrack == (int)i ? *wxRED_PEN : *wxBLACK_PEN );
1164  memDC.DrawRectangle( mTrackRects[ i ] );
1165 
1166  memDC.GetTextExtent( mTrackNames[ i ], &w, &h );
1167  memDC.DrawText( mTrackNames[ i ],
1168  mTrackRects[ i ].x + ( mBoxWidth - w ) / 2,
1169  mTrackRects[ i ].y + ( mTrackHeight - h ) / 2 );
1170  }
1171 
1172  //draw channels
1173  memDC.SetBrush( AColor::playRegionBrush[ 0 ] );
1174  angle = ( asin( mHeight / ( 2.0 * radius ) ) * 2.0 ) /
1175  ( mMixerSpec->GetNumChannels() + 1 );
1176 
1177  SetFont( memDC, wxT( "Channel: XX" ), mBoxWidth, mChannelHeight );
1178  memDC.GetTextExtent( wxT( "Channel: XX" ), &w, &h );
1179 
1180  for( unsigned int i = 0; i < mMixerSpec->GetNumChannels(); i++ )
1181  {
1182  mChannelRects[ i ].x = (int)( mBoxWidth * 4 - radius + radius *
1183  cos( totAngle * 0.5 - angle * ( i + 1 ) ) + 0.5 );
1184  mChannelRects[ i ].y = (int)( mHeight * 0.5 - radius *
1185  sin( totAngle * 0.5 - angle * ( i + 1 ) ) -
1186  0.5 * mChannelHeight + 0.5 );
1187 
1188  mChannelRects[ i ].width = mBoxWidth;
1189  mChannelRects[ i ].height = mChannelHeight;
1190 
1191  memDC.SetPen( mSelectedChannel == (int)i ? *wxRED_PEN : *wxBLACK_PEN );
1192  memDC.DrawRectangle( mChannelRects[ i ] );
1193 
1194  memDC.DrawText( wxString::Format( _( "Channel: %2d" ), i + 1 ),
1195  mChannelRects[ i ].x + ( mBoxWidth - w ) / 2,
1196  mChannelRects[ i ].y + ( mChannelHeight - h ) / 2 );
1197  }
1198 
1199  //draw links
1200  memDC.SetPen( wxPen( *wxBLACK, mHeight / 200 ) );
1201  for( unsigned int i = 0; i < mMixerSpec->GetNumTracks(); i++ )
1202  for( unsigned int j = 0; j < mMixerSpec->GetNumChannels(); j++ )
1203  if( mMixerSpec->mMap[ i ][ j ] )
1204  AColor::Line(memDC, mTrackRects[ i ].x + mBoxWidth,
1205  mTrackRects[ i ].y + mTrackHeight / 2, mChannelRects[ j ].x,
1206  mChannelRects[ j ].y + mChannelHeight / 2 );
1207 
1208  dc.Blit( 0, 0, mWidth, mHeight, &memDC, 0, 0, wxCOPY, FALSE );
1209 }
1210 
1211 double ExportMixerPanel::Distance( wxPoint &a, wxPoint &b )
1212 {
1213  return sqrt( pow( a.x - b.x, 2.0 ) + pow( a.y - b.y, 2.0 ) );
1214 }
1215 
1216 //checks if p is on the line connecting la, lb with tolerence
1217 bool ExportMixerPanel::IsOnLine( wxPoint p, wxPoint la, wxPoint lb )
1218 {
1219  return Distance( p, la ) + Distance( p, lb ) - Distance( la, lb ) < 0.1;
1220 }
1221 
1222 void ExportMixerPanel::OnMouseEvent(wxMouseEvent & event)
1223 {
1224  if( event.ButtonDown() )
1225  {
1226  bool reset = true;
1227  //check tracks
1228  for( unsigned int i = 0; i < mMixerSpec->GetNumTracks(); i++ )
1229  if( mTrackRects[ i ].Contains( event.m_x, event.m_y ) )
1230  {
1231  reset = false;
1232  if( mSelectedTrack == (int)i )
1233  mSelectedTrack = -1;
1234  else
1235  {
1236  mSelectedTrack = i;
1237  if( mSelectedChannel != -1 )
1240  }
1241  goto found;
1242  }
1243 
1244  //check channels
1245  for( unsigned int i = 0; i < mMixerSpec->GetNumChannels(); i++ )
1246  if( mChannelRects[ i ].Contains( event.m_x, event.m_y ) )
1247  {
1248  reset = false;
1249  if( mSelectedChannel == (int)i )
1250  mSelectedChannel = -1;
1251  else
1252  {
1253  mSelectedChannel = i;
1254  if( mSelectedTrack != -1 )
1257  }
1258  goto found;
1259  }
1260 
1261  //check links
1262  for( unsigned int i = 0; i < mMixerSpec->GetNumTracks(); i++ )
1263  for( unsigned int j = 0; j < mMixerSpec->GetNumChannels(); j++ )
1264  if( mMixerSpec->mMap[ i ][ j ] && IsOnLine( wxPoint( event.m_x,
1265  event.m_y ), wxPoint( mTrackRects[ i ].x + mBoxWidth,
1266  mTrackRects[ i ].y + mTrackHeight / 2 ),
1267  wxPoint( mChannelRects[ j ].x, mChannelRects[ j ].y +
1268  mChannelHeight / 2 ) ) )
1269  mMixerSpec->mMap[ i ][ j ] = false;
1270 
1271 found:
1272  if( reset )
1274  Refresh( false );
1275  }
1276 }
1277 
1278 //----------------------------------------------------------------------------
1279 // ExportMixerDialog
1280 //----------------------------------------------------------------------------
1281 
1282 enum
1283 {
1284  ID_MIXERPANEL = 10001,
1286 };
1287 
1288 BEGIN_EVENT_TABLE( ExportMixerDialog, wxDialogWrapper )
1289  EVT_BUTTON( wxID_OK, ExportMixerDialog::OnOk )
1290  EVT_BUTTON( wxID_CANCEL, ExportMixerDialog::OnCancel )
1291  EVT_BUTTON( wxID_HELP, ExportMixerDialog::OnMixerPanelHelp )
1292  EVT_SIZE( ExportMixerDialog::OnSize )
1293  EVT_SLIDER( ID_SLIDER_CHANNEL, ExportMixerDialog::OnSlider )
1295 
1296 ExportMixerDialog::ExportMixerDialog( const TrackList *tracks, bool selectedOnly,
1297  unsigned maxNumChannels, wxWindow *parent, wxWindowID id, const wxString &title,
1298  const wxPoint &position, const wxSize& size, long style ) :
1299  wxDialogWrapper( parent, id, title, position, size, style | wxRESIZE_BORDER )
1300 {
1301  SetName(GetTitle());
1302 
1303  unsigned numTracks = 0;
1304 
1305  for (auto t :
1306  tracks->Any< const WaveTrack >()
1307  + ( selectedOnly ? &Track::IsSelected : &Track::Any )
1309  ) {
1310  numTracks++;
1311  const wxString sTrackName = (t->GetName()).Left(20);
1312  if( t->GetChannel() == Track::LeftChannel )
1313  /* i18n-hint: track name and L abbreviating Left channel */
1314  mTrackNames.Add( wxString::Format( _( "%s - L" ), sTrackName ) );
1315  else if( t->GetChannel() == Track::RightChannel )
1316  /* i18n-hint: track name and R abbreviating Right channel */
1317  mTrackNames.Add( wxString::Format( _( "%s - R" ), sTrackName ) );
1318  else
1319  mTrackNames.Add(sTrackName);
1320  }
1321 
1322  // JKC: This is an attempt to fix a 'watching brief' issue, where the slider is
1323  // sometimes not slidable. My suspicion is that a mixer may incorrectly
1324  // state the number of channels - so we assume there are always at least two.
1325  // The downside is that if someone is exporting to a mono device, the dialog
1326  // will allow them to output to two channels. Hmm. We may need to revisit this.
1327 
1328  if (maxNumChannels < 2 )
1329  // STF (April 2016): AMR (narrowband) and MP3 may export 1 channel.
1330  // maxNumChannels = 2;
1331  maxNumChannels = 1;
1332  if (maxNumChannels > 32)
1333  maxNumChannels = 32;
1334 
1335  mMixerSpec = std::make_unique<MixerSpec>(numTracks, maxNumChannels);
1336 
1337  wxBoxSizer *vertSizer;
1338  {
1339  auto uVertSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
1340  vertSizer = uVertSizer.get();
1341 
1342  wxWindow *mixerPanel = safenew ExportMixerPanel(this, ID_MIXERPANEL,
1343  mMixerSpec.get(), mTrackNames,
1344  wxDefaultPosition, wxSize(400, -1));
1345  mixerPanel->SetName(_("Mixer Panel"));
1346  vertSizer->Add(mixerPanel, 1, wxEXPAND | wxALL, 5);
1347 
1348  {
1349  auto horSizer = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
1350 
1351  wxString label;
1352  label.Printf(_("Output Channels: %2d"), mMixerSpec->GetNumChannels());
1353  mChannelsText = safenew wxStaticText(this, -1, label);
1354  horSizer->Add(mChannelsText, 0, wxALIGN_LEFT | wxALL, 5);
1355 
1356  wxSlider *channels = safenew wxSlider(this, ID_SLIDER_CHANNEL,
1357  mMixerSpec->GetNumChannels(), 1, mMixerSpec->GetMaxNumChannels(),
1358  wxDefaultPosition, wxSize(300, -1));
1359  channels->SetName(label);
1360  horSizer->Add(channels, 0, wxEXPAND | wxALL, 5);
1361 
1362  vertSizer->Add(horSizer.release(), 0, wxALIGN_CENTRE | wxALL, 5);
1363  }
1364 
1365  vertSizer->Add(CreateStdButtonSizer(this, eCancelButton | eOkButton | eHelpButton).release(), 0, wxEXPAND);
1366 
1367  SetAutoLayout(true);
1368  SetSizer(uVertSizer.release());
1369  }
1370 
1371  vertSizer->Fit( this );
1372  vertSizer->SetSizeHints( this );
1373 
1374  SetSizeHints( 640, 480, 20000, 20000 );
1375 
1376  SetSize( 640, 480 );
1377  Center();
1378 }
1379 
1381 {
1382 }
1383 
1384 void ExportMixerDialog::OnSize(wxSizeEvent &event)
1385 {
1386  ExportMixerPanel *pnl = ( ( ExportMixerPanel* ) FindWindow( ID_MIXERPANEL ) );
1387  pnl->Refresh( false );
1388  event.Skip();
1389 }
1390 
1391 void ExportMixerDialog::OnSlider( wxCommandEvent & WXUNUSED(event))
1392 {
1393  wxSlider *channels = ( wxSlider* )FindWindow( ID_SLIDER_CHANNEL );
1394  ExportMixerPanel *pnl = ( ( ExportMixerPanel* ) FindWindow( ID_MIXERPANEL ) );
1395  mMixerSpec->SetNumChannels( channels->GetValue() );
1396  pnl->Refresh( false );
1397  wxString label;
1398  label.Printf( _( "Output Channels: %2d" ), mMixerSpec->GetNumChannels() );
1399  mChannelsText->SetLabel( label );
1400  channels->SetName( label );
1401 }
1402 
1403 void ExportMixerDialog::OnOk(wxCommandEvent & WXUNUSED(event))
1404 {
1405  EndModal( wxID_OK );
1406 }
1407 
1408 void ExportMixerDialog::OnCancel(wxCommandEvent & WXUNUSED(event))
1409 {
1410  EndModal( wxID_CANCEL );
1411 }
1412 
1413 void ExportMixerDialog::OnMixerPanelHelp(wxCommandEvent & WXUNUSED(event))
1414 {
1415  HelpSystem::ShowHelp(this, wxT("Advanced_Mixing_Options"), true);
1416 }
1417 
virtual bool CheckFileName(wxFileName &filename, int format=0)
Definition: Export.cpp:88
#define PI
Definition: ScienFilter.cpp:62
wxDEFINE_EVENT(AUDACITY_FILE_SUFFIX_EVENT, wxCommandEvent)
std::unique_ptr< wxSizer > CreateStdButtonSizer(wxWindow *parent, long buttons, wxWindow *extra)
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
A list of TrackListNode items.
Definition: Track.h:1115
wxFileName mFilename
Definition: Export.h:217
virtual ~ExportMixerDialog()
Definition: Export.cpp:1380
static const wxChar * exts[]
Definition: ImportFLAC.cpp:53
virtual bool IsExtension(const wxString &ext, int index)
Definition: Export.cpp:199
std::unique_ptr< MixerSpec > mMixerSpec
Definition: Export.h:289
wxFileName GetAutoExportFileName()
Definition: Export.cpp:1019
virtual wxString GetDescription(int index)
Definition: Export.cpp:156
bool SetAutoExportOptions(AudacityProject *project)
Definition: Export.cpp:1023
void FindDependencies(AudacityProject *project, AliasedFileArray &outAliasedFiles)
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
Definition: LabelDialog.cpp:89
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:409
void OnFilterChanged(wxFileCtrlEvent &evt)
Definition: Export.cpp:949
std::unique_ptr< ExportPlugin > New_ExportMP2()
wxStaticText * mChannelsText
Definition: Export.h:288
std::vector< FormatInfo > mFormatInfos
Definition: Export.h:146
wxWindow * AddWindow(wxWindow *pWindow, int Flags=wxALIGN_CENTRE|wxALL)
Definition: ShuttleGui.cpp:288
static wxFileNameWrapper DefaultToDocumentsFolder(const wxString &preference)
Definition: FileNames.cpp:368
void SetFileDialogTitle(const wxString &DialogTitle)
Definition: Export.cpp:339
virtual bool DisplayOptions(wxWindow *parent, int format=0)
Definition: Export.cpp:213
double mT1
Definition: Export.h:221
AProjectArray gAudacityProjects
Definition: Project.cpp:307
int mSelectedChannel
Definition: Export.h:260
void OnSize(wxSizeEvent &event)
Definition: Export.cpp:1384
void SetDescription(const wxString &description, int index)
Definition: Export.cpp:121
ArrayOf< wxRect > mTrackRects
Definition: Export.h:259
bool mSelectedOnly
Definition: Export.h:230
void OnHelp(wxCommandEvent &evt)
Definition: Export.cpp:333
wxString label
Definition: Tags.cpp:733
bool Process(AudacityProject *project, bool selectedOnly, double t0, double t1)
Definition: Export.cpp:369
int mSelectedTrack
Definition: Export.h:260
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1195
std::vector< std::unique_ptr< ExportPlugin > > ExportPluginArray
Definition: Export.h:149
std::unique_ptr< ExportPlugin > New_ExportMP3()
Definition: ExportMP3.cpp:2161
wxString mFormatName
Definition: Export.h:209
virtual wxWindow * OptionsCreate(wxWindow *parent, int format)=0
Definition: Export.cpp:218
void OnCancel(wxCommandEvent &event)
Definition: Export.cpp:1408
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
std::unique_ptr< MixerSpec > mMixerSpec
Definition: Export.h:213
virtual wxString GetFormat(int index)
Definition: Export.cpp:151
void SetFont(wxMemoryDC &memDC, const wxString &text, int width, int height)
Definition: Export.cpp:1073
virtual bool GetCanMetaData(int index)
Definition: Export.cpp:194
unsigned mChannels
Definition: Export.h:229
bool CheckMix()
Definition: Export.cpp:785
int GetAutoExportFormat()
Definition: Export.cpp:1007
bool GetFilename()
Definition: Export.cpp:524
bool IsOnLine(wxPoint p, wxPoint la, wxPoint lb)
Definition: Export.cpp:1217
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:238
void OnMouseEvent(wxMouseEvent &event)
Definition: Export.cpp:1222
unsigned mNumRight
Definition: Export.h:227
void SetFormat(const wxString &format, int index)
Definition: Export.cpp:116
AudacityProject * mProject
Definition: Export.h:212
#define safenew
Definition: Audacity.h:230
int FindFormatIndex(int exportindex)
Definition: Export.cpp:345
void EndHorizontalLay()
void SetExtensions(const wxArrayString &extensions, int index)
Definition: Export.cpp:131
int ShowWarningDialog(wxWindow *parent, const wxString &internalDialogName, const wxString &message, bool showCancelButton, const wxString &footer)
Definition: Warning.cpp:93
const ExportPluginArray & GetPlugins()
Definition: Export.cpp:364
const std::shared_ptr< DirManager > & GetDirManager()
Definition: Project.cpp:1437
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:175
void EndVerticalLay()
A kind of Track used to 'warp time'.
Definition: TimeTrack.h:29
virtual unsigned GetMaxChannels(int index)
Definition: Export.cpp:189
wxString mFileDialogTitle
Definition: Export.h:211
int format
Definition: ExportPCM.cpp:56
virtual ~ExportPlugin()
Definition: Export.cpp:84
unsigned GetNumTracks()
Definition: Mix.h:75
std::unique_ptr< ExportPlugin > New_ExportFLAC()
static void CreateUserPaneCallback(wxWindow *parent, wxUIntPtr userdata)
Definition: Export.cpp:905
virtual void SetUserPaneCreator(UserPaneCreatorFunction creator, wxUIntPtr userdata)
Definition: FileDialog.cpp:30
bool CheckFilename()
Definition: Export.cpp:721
virtual int GetFormatCount()
Definition: Export.cpp:107
bool Any() const
Definition: Track.cpp:397
wxWindow * GetParent()
Definition: ShuttleGui.h:294
void SetMaxChannels(unsigned maxchannels, unsigned index)
Definition: Export.cpp:141
bool ProcessFromTimerRecording(AudacityProject *project, bool selectedOnly, double t0, double t1, wxFileName fnFile, int iFormat, int iSubFormat, int iFilterIndex)
Definition: Export.cpp:962
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
ExportPlugin()
Definition: Export.cpp:80
ArraysOf< bool > mMap
Definition: Mix.h:65
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:68
wxArrayString mTrackNames
Definition: Export.h:261
sampleFormat
Definition: Types.h:188
unsigned mNumLeft
Definition: Export.h:226
bool GetShowId3Dialog()
Definition: Project.h:318
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
void DisplayOptions(int index)
Definition: Export.cpp:755
int mSubFormat
Definition: Export.h:224
std::list< AliasedFile > AliasedFileArray
Definition: Dependencies.h:53
ExportPluginArray mPlugins
Definition: Export.h:215
FileDialogWrapper * mDialog
Definition: Export.h:210
static void ShowHelp(wxWindow *parent, const wxString &localFileName, const wxString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:194
int min(int a, int b)
bool ExportTracks()
Definition: Export.cpp:860
virtual ~ExportMixerPanel()
Definition: Export.cpp:1068
wxSimplebook * mBook
Definition: Export.h:232
void AddTitle(const wxString &Prompt)
Centred text string.
Definition: ShuttleGui.cpp:274
std::unique_ptr< ExportPlugin > New_ExportCL()
Definition: ExportCL.cpp:549
int GetAutoExportFilterIndex()
Definition: Export.cpp:1015
double Distance(wxPoint &a, wxPoint &b)
Definition: Export.cpp:1211
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
virtual wxString GetExtension(int index=0)
Return the (first) file name extension for the sub-format.
Definition: Export.cpp:161
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
static wxBrush envelopeBrush
Definition: AColor.h:124
std::unique_ptr< wxBitmap > mBitmap
Definition: Export.h:253
wxFileName mActualName
Definition: Export.h:218
_("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 RegisterPlugin(std::unique_ptr< ExportPlugin > &&plugin)
Definition: Export.cpp:359
unsigned mNumMono
Definition: Export.h:228
bool DoEditMetadata(AudacityProject &project, const wxString &title, const wxString &shortUndoDescription, bool force)
Definition: Menus.cpp:7869
unsigned GetNumChannels()
Definition: Mix.h:72
int AddFormat()
Add a NEW entry to the list of formats this plug-in can export.
Definition: Export.cpp:100
void OnPaint(wxPaintEvent &event)
Definition: Export.cpp:1094
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:312
void OnSlider(wxCommandEvent &event)
Definition: Export.cpp:1391
bool IsSelected() const
Definition: Track.cpp:400
void SetCanMetaData(bool canmetadata, int index)
Definition: Export.cpp:146
ArrayOf< wxRect > mChannelRects
Definition: Export.h:258
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:771
void AddExtension(const wxString &extension, int index)
Definition: Export.cpp:126
double mT0
Definition: Export.h:220
virtual wxString GetMask(int index)
Definition: Export.cpp:171
wxString GetName()
Definition: Project.cpp:1478
virtual wxArrayString GetExtensions(int index=0)
Return all the file name extensions used for the sub-format.
Definition: Export.cpp:166
int mFormat
Definition: Export.h:223
ShuttleGui & Prop(int iProp)
Definition: ShuttleGui.h:418
std::unique_ptr< ExportPlugin > New_ExportFFmpeg()
void CreateUserPane(wxWindow *parent)
Definition: Export.cpp:914
bool ExamineTracks()
Definition: Export.cpp:445
bool GetMute() const
Definition: Track.h:764
int mChannelHeight
Definition: Export.h:262
void OnExtensionChanged(wxCommandEvent &evt)
Definition: Export.cpp:324
int mFilterIndex
Definition: Export.h:222
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
Dialog for advanced mixing.
Definition: Export.h:274
std::unique_ptr< ExportPlugin > New_ExportPCM()
Definition: ExportPCM.cpp:923
END_EVENT_TABLE()
void OnOk(wxCommandEvent &event)
Definition: Export.cpp:1403
TrackList * GetTracks()
Definition: Project.h:192
void OnMixerPanelHelp(wxCommandEvent &event)
Definition: Export.cpp:1413
virtual ~Exporter()
Definition: Export.cpp:312
void SetMask(const wxString &mask, int index)
Definition: Export.cpp:136
std::unique_ptr< ExportPlugin > New_ExportOGG()
static void InitProgress(std::unique_ptr< ProgressDialog > &pDialog, const wxString &title, const wxString &message)
Definition: Export.cpp:256
int mTrackHeight
Definition: Export.h:262
int mNumSelected
Definition: Export.h:225
void SetMessage(const wxString &message)
int GetAutoExportSubFormat()
Definition: Export.cpp:1011
static wxBrush playRegionBrush[2]
Definition: AColor.h:115
Panel that displays mixing for advanced mixing option.
Definition: Export.h:240
MenuCommandHandler & GetMenuCommandHandler(AudacityProject &project)
Definition: Menus.cpp:152
Class used with Mixer.
Definition: Mix.h:58
MixerSpec * mMixerSpec
Definition: Export.h:257
void StartVerticalLay(int iProp=1)