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