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