Audacity  2.2.2
Effect.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  Effect.cpp
6 
7  Dominic Mazzoni
8  Vaughan Johnson
9  Martyn Shaw
10 
11 *******************************************************************//****************************************************************//*******************************************************************/
23 
24 #include "../Audacity.h"
25 #include "Effect.h"
26 
27 #include <algorithm>
28 
29 #include <wx/defs.h>
30 #include <wx/hashmap.h>
31 #include <wx/sizer.h>
32 #include <wx/stockitem.h>
33 #include <wx/string.h>
34 #include <wx/tglbtn.h>
35 #include <wx/timer.h>
36 #include <wx/utils.h>
37 #include <wx/log.h>
38 
39 #include "audacity/ConfigInterface.h"
40 
41 #include "../AudacityException.h"
42 #include "../AudioIO.h"
43 #include "../LabelTrack.h"
44 #include "../Mix.h"
45 #include "../Prefs.h"
46 #include "../Project.h"
47 #include "../ShuttleGui.h"
48 #include "../WaveTrack.h"
49 #include "../toolbars/ControlToolBar.h"
50 #include "../widgets/AButton.h"
51 #include "../widgets/ProgressDialog.h"
52 #include "../ondemand/ODManager.h"
53 #include "TimeWarper.h"
54 #include "nyquist/Nyquist.h"
55 #include "../widgets/HelpSystem.h"
56 #include "../widgets/LinkingHtmlWindow.h"
57 #include "../widgets/ErrorDialog.h"
58 #include "../FileNames.h"
59 
60 #if defined(__WXMAC__)
61 #include <Cocoa/Cocoa.h>
62 #endif
63 
64 #include "../Experimental.h"
65 #include "../commands/ScreenshotCommand.h"
66 
67 #ifndef __AUDACITY_OLD_STD__
68 #include <unordered_map>
69 #endif
70 
71 static const int kDummyID = 20000;
72 static const int kSaveAsID = 20001;
73 static const int kImportID = 20002;
74 static const int kExportID = 20003;
75 static const int kDefaultsID = 20004;
76 static const int kOptionsID = 20005;
77 static const int kUserPresetsDummyID = 20006;
78 static const int kDeletePresetDummyID = 20007;
79 static const int kMenuID = 20100;
80 static const int kEnableID = 20101;
81 static const int kPlayID = 20102;
82 static const int kRewindID = 20103;
83 static const int kFFwdID = 20104;
84 static const int kPlaybackID = 20105;
85 static const int kCaptureID = 20106;
86 static const int kUserPresetsID = 21000;
87 static const int kDeletePresetID = 22000;
88 static const int kFactoryPresetsID = 23000;
89 
90 const wxString Effect::kUserPresetIdent = wxT("User Preset:");
91 const wxString Effect::kFactoryPresetIdent = wxT("Factory Preset:");
92 const wxString Effect::kCurrentSettingsIdent = wxT("<Current Settings>");
93 const wxString Effect::kFactoryDefaultsIdent = wxT("<Factory Defaults>");
94 
95 using t2bHash = std::unordered_map< void*, bool >;
96 
98 {
99  mClient = NULL;
100 
101  mTracks = NULL;
103  mT0 = 0.0;
104  mT1 = 0.0;
105  mDuration = 0.0;
106  mIsPreview = false;
107  mIsLinearEffect = false;
108  mPreviewWithNotSelected = false;
109  mPreviewFullSelection = false;
110  mNumTracks = 0;
111  mNumGroups = 0;
112  mProgress = NULL;
113 
114  mRealtimeSuspendLock.Enter();
115  mRealtimeSuspendCount = 1; // Effects are initially suspended
116  mRealtimeSuspendLock.Leave();
117 
118  mUIParent = NULL;
119  mUIDialog = NULL;
120 
121  mNumAudioIn = 0;
122  mNumAudioOut = 0;
123 
124  mBufferSize = 0;
125  mBlockSize = 0;
126  mNumChannels = 0;
127 
128  mUIDebug = false;
129 
131  mProjectRate = p ? p->GetRate() : 44100;
132 
133  mIsBatch = false;
134 }
135 
137 {
138  if (mUIDialog)
139  {
140  mUIDialog->Close();
141  }
142 }
143 
144 // EffectIdentInterface implementation
145 
146 EffectType Effect::GetType()
147 {
148  if (mClient)
149  {
150  return mClient->GetType();
151  }
152 
153  return EffectTypeNone;
154 }
155 
156 wxString Effect::GetPath()
157 {
158  if (mClient)
159  {
160  return mClient->GetPath();
161  }
162 
163  return BUILTIN_EFFECT_PREFIX + GetSymbol();
164 }
165 
167 {
168  if (mClient)
169  {
170  return mClient->GetSymbol();
171  }
172 
173  return wxEmptyString;
174 }
175 
176 wxString Effect::GetName()
177 {
178  if (mClient)
179  {
180  return mClient->GetName();
181  }
182 
183  return GetSymbol();
184 }
185 
187 {
188  if (mClient)
189  {
190  return mClient->GetVendor();
191  }
192 
193  return XO("Audacity");
194 }
195 
197 {
198  if (mClient)
199  {
200  return mClient->GetVersion();
201  }
202 
204 }
205 
207 {
208  if (mClient)
209  {
210  return mClient->GetDescription();
211  }
212 
213  return wxEmptyString;
214 }
215 
217 {
218  if (mClient)
219  {
220  return mClient->GetFamily();
221  }
222 
223  // PRL: In 2.2.2 we wanted to change the user-visible name to
224  // "Built-in" but we did not do it the obvious way by just changing this
225  // string, because of problems with compatibility of pluginsettings.cfg
226  // See PluginDescriptor::GetTranslatedEffectFamily and
227  // EffectUIHost::OnMenu
228  // See PluginManager::RegisterPlugin and PluginManager::GetID, where the
229  // return value is also (mis?)used for internal identification purposes,
230  // NOT as a user-visible string!
231  // Thereby affecting configuration file contents!
232  return XO("Audacity");
233 }
234 
236 {
237  if (mClient)
238  {
239  return mClient->IsInteractive();
240  }
241 
242  return true;
243 }
244 
246 {
247  if (mClient)
248  {
249  return mClient->IsDefault();
250  }
251 
252  return true;
253 }
254 
256 {
257  if (mClient)
258  {
259  return false;
260  }
261 
262  return true;
263 }
264 
266 {
267  if (mClient)
268  {
269  return mClient->SupportsRealtime();
270  }
271 
272  return false;
273 }
274 
276 {
277  if (mClient)
278  {
279  return mClient->SupportsAutomation();
280  }
281 
282  return true;
283 }
284 
285 // EffectClientInterface implementation
286 
287 bool Effect::SetHost(EffectHostInterface *host)
288 {
289  if (mClient)
290  {
291  return mClient->SetHost(host);
292  }
293 
294  return true;
295 }
296 
298 {
299  if (mClient)
300  {
301  return mClient->GetAudioInCount();
302  }
303 
304  return 0;
305 }
306 
308 {
309  if (mClient)
310  {
311  return mClient->GetAudioOutCount();
312  }
313 
314  return 0;
315 }
316 
318 {
319  if (mClient)
320  {
321  return mClient->GetMidiInCount();
322  }
323 
324  return 0;
325 }
326 
328 {
329  if (mClient)
330  {
331  return mClient->GetMidiOutCount();
332  }
333 
334  return 0;
335 }
336 
337 void Effect::SetSampleRate(double rate)
338 {
339  if (mClient)
340  {
341  mClient->SetSampleRate(rate);
342  }
343 
344  mSampleRate = rate;
345 }
346 
347 size_t Effect::SetBlockSize(size_t maxBlockSize)
348 {
349  if (mClient)
350  {
351  return mClient->SetBlockSize(maxBlockSize);
352  }
353 
354  mBlockSize = maxBlockSize;
355 
356  return mBlockSize;
357 }
358 
359 sampleCount Effect::GetLatency()
360 {
361  if (mClient)
362  {
363  return mClient->GetLatency();
364  }
365 
366  return 0;
367 }
368 
370 {
371  if (mClient)
372  {
373  return mClient->GetTailSize();
374  }
375 
376  return 0;
377 }
378 
380 {
381  if (mClient)
382  {
383  return mClient->IsReady();
384  }
385 
386  return true;
387 }
388 
389 bool Effect::ProcessInitialize(sampleCount totalLen, ChannelNames chanMap)
390 {
391  if (mClient)
392  {
393  return mClient->ProcessInitialize(totalLen, chanMap);
394  }
395 
396  return true;
397 }
398 
400 {
401  if (mClient)
402  {
403  return mClient->ProcessFinalize();
404  }
405 
406  return true;
407 }
408 
409 size_t Effect::ProcessBlock(float **inBlock, float **outBlock, size_t blockLen)
410 {
411  if (mClient)
412  {
413  return mClient->ProcessBlock(inBlock, outBlock, blockLen);
414  }
415 
416  return 0;
417 }
418 
420 {
421  if (mClient)
422  {
423  mBlockSize = mClient->SetBlockSize(512);
424  return mClient->RealtimeInitialize();
425  }
426 
427  mBlockSize = 512;
428 
429  return false;
430 }
431 
432 bool Effect::RealtimeAddProcessor(unsigned numChannels, float sampleRate)
433 {
434  if (mClient)
435  {
436  return mClient->RealtimeAddProcessor(numChannels, sampleRate);
437  }
438 
439  return true;
440 }
441 
443 {
444  if (mClient)
445  {
446  return mClient->RealtimeFinalize();
447  }
448 
449  return false;
450 }
451 
453 {
454  if (mClient)
455  {
456  if (mClient->RealtimeSuspend())
457  {
458  mRealtimeSuspendLock.Enter();
460  mRealtimeSuspendLock.Leave();
461  return true;
462  }
463 
464  return false;
465  }
466 
467  mRealtimeSuspendLock.Enter();
469  mRealtimeSuspendLock.Leave();
470 
471  return true;
472 }
473 
475 {
476  if (mClient)
477  {
478  if (mClient->RealtimeResume())
479  {
480  mRealtimeSuspendLock.Enter();
482  mRealtimeSuspendLock.Leave();
483  return true;
484  }
485 
486  return false;
487  }
488 
489  mRealtimeSuspendLock.Enter();
491  mRealtimeSuspendLock.Leave();
492 
493  return true;
494 }
495 
497 {
498  if (mClient)
499  {
500  return mClient->RealtimeProcessStart();
501  }
502 
503  return true;
504 }
505 
506 size_t Effect::RealtimeProcess(int group,
507  float **inbuf,
508  float **outbuf,
509  size_t numSamples)
510 {
511  if (mClient)
512  {
513  return mClient->RealtimeProcess(group, inbuf, outbuf, numSamples);
514  }
515 
516  return 0;
517 }
518 
520 {
521  if (mClient)
522  {
523  return mClient->RealtimeProcessEnd();
524  }
525 
526  return true;
527 }
528 
529 bool Effect::ShowInterface(wxWindow *parent, bool forceModal)
530 {
531  if (!IsInteractive())
532  {
533  return true;
534  }
535 
536  if (mUIDialog)
537  {
538  if ( mUIDialog->Close(true) )
539  mUIDialog = nullptr;
540  return false;
541  }
542 
543  if (mClient)
544  {
545  return mClient->ShowInterface(parent, forceModal);
546  }
547 
548  // mUIDialog is null
549  auto cleanup = valueRestorer( mUIDialog );
550 
551  mUIDialog = CreateUI(parent, this);
552  if (!mUIDialog)
553  {
554  return false;
555  }
556 
557 
558  mUIDialog->Layout();
559  mUIDialog->Fit();
560  mUIDialog->SetMinSize(mUIDialog->GetSize());
561 
563  return false;
564 
565  if( SupportsRealtime() && !forceModal )
566  {
567  mUIDialog->Show();
568  cleanup.release();
569 
570  // Return false to bypass effect processing
571  return false;
572  }
573 
574  bool res = mUIDialog->ShowModal() != 0;
575 
576  return res;
577 }
578 
579 bool Effect::GetAutomationParameters(EffectAutomationParameters & parms)
580 {
581  if (mClient)
582  {
583  return mClient->GetAutomationParameters(parms);
584  }
585 
586  return true;
587 }
588 
589 bool Effect::SetAutomationParameters(EffectAutomationParameters & parms)
590 {
591  if (mClient)
592  {
593  return mClient->SetAutomationParameters(parms);
594  }
595 
596  return true;
597 }
598 
599 bool Effect::LoadUserPreset(const wxString & name)
600 {
601  if (mClient)
602  {
603  return mClient->LoadUserPreset(name);
604  }
605 
606  wxString parms;
607  if (!GetPrivateConfig(name, wxT("Parameters"), parms))
608  {
609  return false;
610  }
611 
612  return SetAutomationParameters(parms);
613 }
614 
615 bool Effect::SaveUserPreset(const wxString & name)
616 {
617  if (mClient)
618  {
619  return mClient->SaveUserPreset(name);
620  }
621 
622  wxString parms;
623  if (!GetAutomationParameters(parms))
624  {
625  return false;
626  }
627 
628  return SetPrivateConfig(name, wxT("Parameters"), parms);
629 }
630 
632 {
633  if (mClient)
634  {
635  return mClient->GetFactoryPresets();
636  }
637 
638  return wxArrayString();
639 }
640 
642 {
643  if (mClient)
644  {
645  return mClient->LoadFactoryPreset(id);
646  }
647 
648  return true;
649 }
650 
652 {
653  if (mClient)
654  {
655  return mClient->LoadFactoryDefaults();
656  }
657 
659 }
660 
661 // EffectUIClientInterface implementation
662 
663 void Effect::SetHostUI(EffectUIHostInterface *WXUNUSED(host))
664 {
665 }
666 
667 bool Effect::PopulateUI(wxWindow *parent)
668 {
669  mUIParent = parent;
670  mUIParent->PushEventHandler(this);
671 
672 // LoadUserPreset(GetCurrentSettingsGroup());
673 
676 
677  mUIParent->SetMinSize(mUIParent->GetSizer()->GetMinSize());
678 
679  return true;
680 }
681 
683 {
684  return false;
685 }
686 
688 {
689  return mUIParent->Validate();
690 }
691 
693 {
694  return true;
695 }
696 
698 {
699  if (mUIParent)
700  mUIParent->RemoveEventHandler(this);
701 
702  mUIParent = NULL;
703  mUIDialog = NULL;
704 
705  return true;
706 }
707 
709 {
710  return false;
711 }
712 
714 {
715 }
716 
718 {
719 }
720 
722 {
723  return false;
724 }
725 
727 {
728 }
729 
730 // EffectHostInterface implementation
731 
733 {
734  return 30.0;
735 }
736 
738 {
739  if (mDuration < 0.0)
740  {
741  mDuration = 0.0;
742  }
743 
744  return mDuration;
745 }
746 
748 {
749  return mDurationFormat;
750 }
751 
753 {
755 }
756 
757 void Effect::SetDuration(double seconds)
758 {
759  if (seconds < 0.0)
760  {
761  seconds = 0.0;
762  }
763 
764  if (GetType() == EffectTypeGenerate)
765  {
766  SetPrivateConfig(GetCurrentSettingsGroup(), wxT("LastUsedDuration"), seconds);
767  }
768 
769  mDuration = seconds;
770 
771  mIsSelection = false;
772 
773  return;
774 }
775 
777 {
778  // This is absolute hackage...but easy and I can't think of another way just now.
779  //
780  // It should callback to the EffectManager to kick off the processing
782 }
783 
785 {
786  Preview(false);
787 }
788 
789 wxDialog *Effect::CreateUI(wxWindow *parent, EffectUIClientInterface *client)
790 {
792  { safenew EffectUIHost{ parent, this, client} };
793 
794  if (dlg->Initialize())
795  {
796  // release() is safe because parent will own it
797  return dlg.release();
798  }
799 
800  return NULL;
801 }
802 
803 wxString Effect::GetUserPresetsGroup(const wxString & name)
804 {
805  wxString group = wxT("UserPresets");
806  if (!name.IsEmpty())
807  {
808  group += wxCONFIG_PATH_SEPARATOR + name;
809  }
810 
811  return group;
812 }
813 
815 {
816  return wxT("CurrentSettings");
817 }
818 
820 {
821  return wxT("FactoryDefaults");
822 }
823 
825 {
826  return wxT("SavedState");
827 }
828 
829 // ConfigClientInterface implementation
830 bool Effect::HasSharedConfigGroup(const wxString & group)
831 {
832  return PluginManager::Get().HasSharedConfigGroup(GetID(), group);
833 }
834 
835 bool Effect::GetSharedConfigSubgroups(const wxString & group, wxArrayString & subgroups)
836 {
837  return PluginManager::Get().GetSharedConfigSubgroups(GetID(), group, subgroups);
838 }
839 
840 bool Effect::GetSharedConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval)
841 {
842  return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval);
843 }
844 
845 bool Effect::GetSharedConfig(const wxString & group, const wxString & key, int & value, int defval)
846 {
847  return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval);
848 }
849 
850 bool Effect::GetSharedConfig(const wxString & group, const wxString & key, bool & value, bool defval)
851 {
852  return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval);
853 }
854 
855 bool Effect::GetSharedConfig(const wxString & group, const wxString & key, float & value, float defval)
856 {
857  return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval);
858 }
859 
860 bool Effect::GetSharedConfig(const wxString & group, const wxString & key, double & value, double defval)
861 {
862  return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval);
863 }
864 
865 bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const wxString & value)
866 {
867  return PluginManager::Get().SetSharedConfig(GetID(), group, key, value);
868 }
869 
870 bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const int & value)
871 {
872  return PluginManager::Get().SetSharedConfig(GetID(), group, key, value);
873 }
874 
875 bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const bool & value)
876 {
877  return PluginManager::Get().SetSharedConfig(GetID(), group, key, value);
878 }
879 
880 bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const float & value)
881 {
882  return PluginManager::Get().SetSharedConfig(GetID(), group, key, value);
883 }
884 
885 bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const double & value)
886 {
887  return PluginManager::Get().SetSharedConfig(GetID(), group, key, value);
888 }
889 
890 bool Effect::RemoveSharedConfigSubgroup(const wxString & group)
891 {
893 }
894 
895 bool Effect::RemoveSharedConfig(const wxString & group, const wxString & key)
896 {
897  return PluginManager::Get().RemoveSharedConfig(GetID(), group, key);
898 }
899 
900 bool Effect::HasPrivateConfigGroup(const wxString & group)
901 {
903 }
904 
905 bool Effect::GetPrivateConfigSubgroups(const wxString & group, wxArrayString & subgroups)
906 {
907  return PluginManager::Get().GetPrivateConfigSubgroups(GetID(), group, subgroups);
908 }
909 
910 bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval)
911 {
912  return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval);
913 }
914 
915 bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, int & value, int defval)
916 {
917  return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval);
918 }
919 
920 bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, bool & value, bool defval)
921 {
922  return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval);
923 }
924 
925 bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, float & value, float defval)
926 {
927  return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval);
928 }
929 
930 bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, double & value, double defval)
931 {
932  return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval);
933 }
934 
935 bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, const wxString & value)
936 {
937  return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value);
938 }
939 
940 bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, const int & value)
941 {
942  return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value);
943 }
944 
945 bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, const bool & value)
946 {
947  return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value);
948 }
949 
950 bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, const float & value)
951 {
952  return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value);
953 }
954 
955 bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, const double & value)
956 {
957  return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value);
958 }
959 
960 bool Effect::RemovePrivateConfigSubgroup(const wxString & group)
961 {
963 }
964 
965 bool Effect::RemovePrivateConfig(const wxString & group, const wxString & key)
966 {
967  return PluginManager::Get().RemovePrivateConfig(GetID(), group, key);
968 }
969 
970 // Effect implementation
971 
972 PluginID Effect::GetID()
973 {
974  if (mClient)
975  {
977  }
978 
979  return PluginManager::GetID(this);
980 }
981 
982 bool Effect::Startup(EffectClientInterface *client)
983 {
984  // Let destructor know we need to be shutdown
985  mClient = client;
986 
987  // Set host so client startup can use our services
988  if (!SetHost(this))
989  {
990  // Bail if the client startup fails
991  mClient = NULL;
992  return false;
993  }
994 
997 
998  bool haveDefaults;
999  GetPrivateConfig(GetFactoryDefaultsGroup(), wxT("Initialized"), haveDefaults, false);
1000  if (!haveDefaults)
1001  {
1003  SetPrivateConfig(GetFactoryDefaultsGroup(), wxT("Initialized"), true);
1004  }
1006 
1007  return Startup();
1008 }
1009 
1011 {
1012  return true;
1013 }
1014 
1015 bool Effect::GetAutomationParameters(wxString & parms)
1016 {
1017  EffectAutomationParameters eap;
1018 
1020  {
1021  return false;
1022  }
1023 
1024  if (!GetAutomationParameters(eap))
1025  {
1026  return false;
1027  }
1028 
1029  return eap.GetParameters(parms);
1030 }
1031 
1032 bool Effect::SetAutomationParameters(const wxString & parms)
1033 {
1034  wxString preset = parms;
1035  bool success = false;
1036  if (preset.StartsWith(kUserPresetIdent))
1037  {
1038  preset.Replace(kUserPresetIdent, wxEmptyString, false);
1039  success = LoadUserPreset(GetUserPresetsGroup(preset));
1040  }
1041  else if (preset.StartsWith(kFactoryPresetIdent))
1042  {
1043  preset.Replace(kFactoryPresetIdent, wxEmptyString, false);
1044  wxArrayString presets = GetFactoryPresets();
1045  success = LoadFactoryPreset(presets.Index(preset));
1046  }
1047  else if (preset.StartsWith(kCurrentSettingsIdent))
1048  {
1049  preset.Replace(kCurrentSettingsIdent, wxEmptyString, false);
1051  }
1052  else if (preset.StartsWith(kFactoryDefaultsIdent))
1053  {
1054  preset.Replace(kFactoryDefaultsIdent, wxEmptyString, false);
1056  }
1057  else
1058  {
1059  EffectAutomationParameters eap(parms);
1060  success = SetAutomationParameters(eap);
1061  }
1062 
1063  if (!success)
1064  {
1066  wxString::Format(
1067  _("%s: Could not load settings below. Default settings will be used.\n\n%s"),
1068  GetTranslatedName(),
1069  preset
1070  )
1071  );
1072 
1073  return false;
1074  }
1075 
1076  if (!mUIDialog)
1077  {
1078  return true;
1079  }
1080 
1081  return TransferDataToWindow();
1082 }
1083 
1084 wxArrayString Effect::GetUserPresets()
1085 {
1086  wxArrayString presets;
1087 
1088  GetPrivateConfigSubgroups(GetUserPresetsGroup(wxEmptyString), presets);
1089 
1090  presets.Sort();
1091 
1092  return presets;
1093 }
1094 
1096 {
1098 }
1099 
1101 {
1103 }
1104 
1105 wxString Effect::GetPreset(wxWindow * parent, const wxString & parms)
1106 {
1107  EffectPresetsDialog dlg(parent, this);
1108  dlg.Layout();
1109  dlg.Fit();
1110  dlg.SetSize(dlg.GetMinSize());
1111  dlg.CenterOnParent();
1112  dlg.SetSelected(parms);
1113 
1114  if (dlg.ShowModal())
1115  {
1116  return dlg.GetSelected();
1117  }
1118 
1119  return wxEmptyString;
1120 }
1121 
1123 {
1124  return wxEmptyString;
1125 }
1126 
1128 {
1129  return wxEmptyString;
1130 }
1131 
1133 {
1134  return mIsBatch;
1135 }
1136 
1138 {
1139  mIsBatch = start;
1140 
1141  if (start)
1142  {
1144  }
1145  else
1146  {
1148  }
1149 }
1150 
1151 bool Effect::DoEffect(wxWindow *parent,
1152  double projectRate,
1153  TrackList *list,
1154  TrackFactory *factory,
1155  SelectedRegion *selectedRegion,
1156  bool shouldPrompt /* = true */)
1157 {
1158  wxASSERT(selectedRegion->duration() >= 0.0);
1159 
1160  mOutputTracks.reset();
1161 
1162  mFactory = factory;
1163  mProjectRate = projectRate;
1164  mTracks = list;
1165 
1166  bool isSelection = false;
1167 
1168  mDuration = 0.0;
1169 
1170  if (GetType() == EffectTypeGenerate)
1171  {
1172  GetPrivateConfig(GetCurrentSettingsGroup(), wxT("LastUsedDuration"), mDuration, GetDefaultDuration());
1173  }
1174 
1175  mT0 = selectedRegion->t0();
1176  mT1 = selectedRegion->t1();
1177  if (mT1 > mT0)
1178  {
1179  // there is a selection: let's fit in there...
1180  // MJS: note that this is just for the TTC and is independent of the track rate
1181  // but we do need to make sure we have the right number of samples at the project rate
1182  double quantMT0 = QUANTIZED_TIME(mT0, mProjectRate);
1183  double quantMT1 = QUANTIZED_TIME(mT1, mProjectRate);
1184  mDuration = quantMT1 - quantMT0;
1185  mT1 = mT0 + mDuration;
1186 
1187  isSelection = true;
1188  }
1189 
1190  mDurationFormat = isSelection ? _("hh:mm:ss + samples") : _("hh:mm:ss + milliseconds");
1191 
1192 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
1193  mF0 = selectedRegion->f0();
1194  mF1 = selectedRegion->f1();
1195  wxArrayString Names;
1197  Names.Add(wxT("control-f0"));
1199  Names.Add(wxT("control-f1"));
1200  SetPresetParameters( &Names, NULL );
1201 
1202 #endif
1203  CountWaveTracks();
1204 
1205  // Note: Init may read parameters from preferences
1206  if (!Init())
1207  {
1208  return false;
1209  }
1210 
1211  // Prompting will be bypassed when applying an effect that has already
1212  // been configured, e.g. repeating the last effect on a different selection.
1213  // Prompting may call Effect::Preview
1214  if (shouldPrompt && IsInteractive() && !PromptUser(parent))
1215  {
1216  return false;
1217  }
1218 
1219  auto cleanup = finally( [&] {
1220  End();
1221 
1222  // In case of failed effect, be sure to free memory.
1223  ReplaceProcessedTracks( false );
1224  } );
1225 
1226  bool returnVal = true;
1227  bool skipFlag = CheckWhetherSkipEffect();
1228  if (skipFlag == false)
1229  {
1230  auto name = GetTranslatedName();
1231  ProgressDialog progress{
1232  name,
1233  wxString::Format(_("Applying %s..."), name),
1235  };
1236  auto vr = valueRestorer( mProgress, &progress );
1237 
1238  returnVal = Process();
1239  }
1240 
1241  if (returnVal)
1242  {
1243  selectedRegion->setTimes(mT0, mT1);
1244  }
1245 
1246  return returnVal;
1247 }
1248 
1249 bool Effect::Delegate( Effect &delegate,
1250  wxWindow *parent, SelectedRegion *selectedRegion, bool shouldPrompt)
1251 {
1252  return delegate.DoEffect( parent, mProjectRate, mTracks, mFactory,
1253  selectedRegion, shouldPrompt );
1254 }
1255 
1256 // All legacy effects should have this overridden
1258 {
1259  return true;
1260 }
1261 
1262 // Remove this method once NoiseReduction gets migrated
1263 bool Effect::PromptUser(wxWindow *parent)
1264 {
1265  return ShowInterface(parent, IsBatchProcessing());
1266 }
1267 
1269 {
1270  return mPass;
1271 }
1272 
1274 {
1275  return true;
1276 }
1277 
1279 {
1280  return false;
1281 }
1282 
1284 {
1286  bool bGoodResult = true;
1287 
1288  // It's possible that the number of channels the effect expects changed based on
1289  // the parameters (the Audacity Reverb effect does when the stereo width is 0).
1292 
1293  mPass = 1;
1294  if (InitPass1())
1295  {
1296  bGoodResult = ProcessPass();
1297  mPass = 2;
1298  if (bGoodResult && InitPass2())
1299  {
1300  bGoodResult = ProcessPass();
1301  }
1302  }
1303 
1304  ReplaceProcessedTracks(bGoodResult);
1305 
1306  return bGoodResult;
1307 }
1308 
1310 {
1311  bool bGoodResult = true;
1312  bool isGenerator = GetType() == EffectTypeGenerate;
1313 
1314  FloatBuffers inBuffer, outBuffer;
1315  ArrayOf<float *> inBufPos, outBufPos;
1316 
1317  ChannelName map[3];
1318 
1319  mBufferSize = 0;
1320  mBlockSize = 0;
1321 
1322  TrackListIterator iter(mOutputTracks.get());
1323  int count = 0;
1324  bool clear = false;
1325  Track* t = iter.First();
1326 
1327  for (t = iter.First(); t; t = iter.Next())
1328  {
1329  if (t->GetKind() != Track::Wave || !t->GetSelected())
1330  {
1331  if (t->IsSyncLockSelected())
1332  {
1334  }
1335  continue;
1336  }
1337 
1338  WaveTrack *left = (WaveTrack *)t;
1339  WaveTrack *right;
1340  sampleCount len;
1341  sampleCount leftStart;
1342  sampleCount rightStart;
1343 
1344  if (!isGenerator)
1345  {
1346  GetSamples(left, &leftStart, &len);
1347  mSampleCnt = len;
1348  }
1349  else
1350  {
1351  len = 0;
1352  leftStart = 0;
1354  }
1355 
1356  mNumChannels = 1;
1357 
1358  if (left->GetChannel() == Track::LeftChannel)
1359  {
1360  map[0] = ChannelNameFrontLeft;
1361  }
1362  else if (left->GetChannel() == Track::RightChannel)
1363  {
1364  map[0] = ChannelNameFrontRight;
1365  }
1366  else
1367  {
1368  map[0] = ChannelNameMono;
1369  }
1370  map[1] = ChannelNameEOL;
1371 
1372  right = NULL;
1373  rightStart = 0;
1374  if (left->GetLinked() && mNumAudioIn > 1)
1375  {
1376  // Assume linked track is wave
1377  right = static_cast<WaveTrack *>(iter.Next());
1378  if (!isGenerator)
1379  {
1380  GetSamples(right, &rightStart, &len);
1381  }
1382  clear = false;
1383  mNumChannels = 2;
1384 
1385  if (right->GetChannel() == Track::LeftChannel)
1386  {
1387  map[1] = ChannelNameFrontLeft;
1388  }
1389  else if (right->GetChannel() == Track::RightChannel)
1390  {
1391  map[1] = ChannelNameFrontRight;
1392  }
1393  else
1394  {
1395  map[1] = ChannelNameMono;
1396  }
1397  map[2] = ChannelNameEOL;
1398  }
1399 
1400  // Let the client know the sample rate
1401  SetSampleRate(left->GetRate());
1402 
1403  // Get the block size the client wants to use
1404  auto max = left->GetMaxBlockSize() * 2;
1405  mBlockSize = SetBlockSize(max);
1406 
1407  // Calculate the buffer size to be at least the max rounded up to the clients
1408  // selected block size.
1409  const auto prevBufferSize = mBufferSize;
1410  mBufferSize = ((max + (mBlockSize - 1)) / mBlockSize) * mBlockSize;
1411 
1412  // If the buffer size has changed, then (re)allocate the buffers
1413  if (prevBufferSize != mBufferSize)
1414  {
1415  // Always create the number of input buffers the client expects even if we don't have
1416  // the same number of channels.
1417  inBufPos.reinit( mNumAudioIn );
1418  inBuffer.reinit( mNumAudioIn, mBufferSize );
1419 
1420  // We won't be using more than the first 2 buffers, so clear the rest (if any)
1421  for (size_t i = 2; i < mNumAudioIn; i++)
1422  {
1423  for (size_t j = 0; j < mBufferSize; j++)
1424  {
1425  inBuffer[i][j] = 0.0;
1426  }
1427  }
1428 
1429  // Always create the number of output buffers the client expects even if we don't have
1430  // the same number of channels.
1431  // Output buffers get an extra mBlockSize worth to give extra room if
1432  // the plugin adds latency
1433  outBufPos.reinit( mNumAudioOut );
1434  outBuffer.reinit( mNumAudioOut, mBufferSize + mBlockSize );
1435  }
1436 
1437  // (Re)Set the input buffer positions
1438  for (size_t i = 0; i < mNumAudioIn; i++)
1439  {
1440  inBufPos[i] = inBuffer[i].get();
1441  }
1442 
1443  // (Re)Set the output buffer positions
1444  for (size_t i = 0; i < mNumAudioOut; i++)
1445  {
1446  outBufPos[i] = outBuffer[i].get();
1447  }
1448 
1449  // Clear unused input buffers
1450  if (!right && !clear && mNumAudioIn > 1)
1451  {
1452  for (size_t j = 0; j < mBufferSize; j++)
1453  {
1454  inBuffer[1][j] = 0.0;
1455  }
1456  clear = true;
1457  }
1458 
1459  // Go process the track(s)
1460  bGoodResult = ProcessTrack(
1461  count, map, left, right, leftStart, rightStart, len,
1462  inBuffer, outBuffer, inBufPos, outBufPos);
1463  if (!bGoodResult)
1464  {
1465  break;
1466  }
1467 
1468  count++;
1469  }
1470 
1471  if (bGoodResult && GetType() == EffectTypeGenerate)
1472  {
1473  mT1 = mT0 + mDuration;
1474  }
1475 
1476  return bGoodResult;
1477 }
1478 
1479 bool Effect::ProcessTrack(int count,
1480  ChannelNames map,
1481  WaveTrack *left,
1482  WaveTrack *right,
1483  sampleCount leftStart,
1484  sampleCount rightStart,
1485  sampleCount len,
1486  FloatBuffers &inBuffer,
1487  FloatBuffers &outBuffer,
1488  ArrayOf< float * > &inBufPos,
1489  ArrayOf< float *> &outBufPos)
1490 {
1491  bool rc = true;
1492 
1493  // Give the plugin a chance to initialize
1494  if (!ProcessInitialize(len, map))
1495  {
1496  return false;
1497  }
1498 
1499  { // Start scope for cleanup
1500  auto cleanup = finally( [&] {
1501  // Allow the plugin to cleanup
1502  if (!ProcessFinalize())
1503  {
1504  // In case of non-exceptional flow of control, set rc
1505  rc = false;
1506  }
1507  } );
1508 
1509  // For each input block of samples, we pass it to the effect along with a
1510  // variable output location. This output location is simply a pointer into a
1511  // much larger buffer. This reduces the number of calls required to add the
1512  // samples to the output track.
1513  //
1514  // Upon return from the effect, the output samples are "moved to the left" by
1515  // the number of samples in the current latency setting, effectively removing any
1516  // delay introduced by the effect.
1517  //
1518  // At the same time the total number of delayed samples are gathered and when
1519  // there is no further input data to process, the loop continues to call the
1520  // effect with an empty input buffer until the effect has had a chance to
1521  // return all of the remaining delayed samples.
1522  auto inLeftPos = leftStart;
1523  auto inRightPos = rightStart;
1524  auto outLeftPos = leftStart;
1525  auto outRightPos = rightStart;
1526 
1527  auto inputRemaining = len;
1528  decltype(GetLatency()) curDelay = 0, delayRemaining = 0;
1529  decltype(mBlockSize) curBlockSize = 0;
1530 
1531  decltype(mBufferSize) inputBufferCnt = 0;
1532  decltype(mBufferSize) outputBufferCnt = 0;
1533  bool cleared = false;
1534 
1535  auto chans = std::min<unsigned>(mNumAudioOut, mNumChannels);
1536 
1537  std::unique_ptr<WaveTrack> genLeft, genRight;
1538 
1539  decltype(len) genLength = 0;
1540  bool isGenerator = GetType() == EffectTypeGenerate;
1541  bool isProcessor = GetType() == EffectTypeProcess;
1542  double genDur = 0;
1543  if (isGenerator)
1544  {
1545  if (mIsPreview) {
1546  gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &genDur, 6.0);
1547  genDur = wxMin(mDuration, CalcPreviewInputLength(genDur));
1548  }
1549  else {
1550  genDur = mDuration;
1551  }
1552 
1553  genLength = sampleCount((left->GetRate() * genDur) + 0.5); // round to nearest sample
1554  delayRemaining = genLength;
1555  cleared = true;
1556 
1557  // Create temporary tracks
1558  genLeft = mFactory->NewWaveTrack(left->GetSampleFormat(), left->GetRate());
1559  genLeft->SetWaveColorIndex( left->GetWaveColorIndex() );
1560 
1561  if (right)
1562  {
1563  genRight = mFactory->NewWaveTrack(right->GetSampleFormat(), right->GetRate());
1564  genRight->SetWaveColorIndex( right->GetWaveColorIndex() );
1565  }
1566  }
1567 
1568  // Call the effect until we run out of input or delayed samples
1569  while (inputRemaining != 0 || delayRemaining != 0)
1570  {
1571  // Still working on the input samples
1572  if (inputRemaining != 0)
1573  {
1574  // Need to refill the input buffers
1575  if (inputBufferCnt == 0)
1576  {
1577  // Calculate the number of samples to get
1578  inputBufferCnt =
1579  limitSampleBufferSize( mBufferSize, inputRemaining );
1580 
1581  // Fill the input buffers
1582  left->Get((samplePtr) inBuffer[0].get(), floatSample, inLeftPos, inputBufferCnt);
1583  if (right)
1584  {
1585  right->Get((samplePtr) inBuffer[1].get(), floatSample, inRightPos, inputBufferCnt);
1586  }
1587 
1588  // Reset the input buffer positions
1589  for (size_t i = 0; i < mNumChannels; i++)
1590  {
1591  inBufPos[i] = inBuffer[i].get();
1592  }
1593  }
1594 
1595  // Calculate the number of samples to process
1596  curBlockSize = mBlockSize;
1597  if (curBlockSize > inputRemaining)
1598  {
1599  // We've reached the last block...set current block size to what's left
1600  // inputRemaining is positive and bounded by a size_t
1601  curBlockSize = inputRemaining.as_size_t();
1602  inputRemaining = 0;
1603 
1604  // Clear the remainder of the buffers so that a full block can be passed
1605  // to the effect
1606  auto cnt = mBlockSize - curBlockSize;
1607  for (size_t i = 0; i < mNumChannels; i++)
1608  {
1609  for (decltype(cnt) j = 0 ; j < cnt; j++)
1610  {
1611  inBufPos[i][j + curBlockSize] = 0.0;
1612  }
1613  }
1614 
1615  // Might be able to use up some of the delayed samples
1616  if (delayRemaining != 0)
1617  {
1618  // Don't use more than needed
1619  cnt = limitSampleBufferSize(cnt, delayRemaining);
1620  delayRemaining -= cnt;
1621  curBlockSize += cnt;
1622  }
1623  }
1624  }
1625  // We've exhausted the input samples and are now working on the delay
1626  else if (delayRemaining != 0)
1627  {
1628  // Calculate the number of samples to process
1629  curBlockSize = limitSampleBufferSize( mBlockSize, delayRemaining );
1630  delayRemaining -= curBlockSize;
1631 
1632  // From this point on, we only want to feed zeros to the plugin
1633  if (!cleared)
1634  {
1635  // Reset the input buffer positions
1636  for (size_t i = 0; i < mNumChannels; i++)
1637  {
1638  inBufPos[i] = inBuffer[i].get();
1639 
1640  // And clear
1641  for (size_t j = 0; j < mBlockSize; j++)
1642  {
1643  inBuffer[i][j] = 0.0;
1644  }
1645  }
1646  cleared = true;
1647  }
1648  }
1649 
1650  // Finally call the plugin to process the block
1651  decltype(curBlockSize) processed;
1652  try
1653  {
1654  processed = ProcessBlock(inBufPos.get(), outBufPos.get(), curBlockSize);
1655  }
1656  catch( const AudacityException & WXUNUSED(e) )
1657  {
1658  // PRL: Bug 437:
1659  // Pass this along to our application-level handler
1660  throw;
1661  }
1662  catch(...)
1663  {
1664  // PRL:
1665  // Exceptions for other reasons, maybe in third-party code...
1666  // Continue treating them as we used to, but I wonder if these
1667  // should now be treated the same way.
1668  return false;
1669  }
1670  wxASSERT(processed == curBlockSize);
1671  wxUnusedVar(processed);
1672 
1673  // Bump to next input buffer position
1674  if (inputRemaining != 0)
1675  {
1676  for (size_t i = 0; i < mNumChannels; i++)
1677  {
1678  inBufPos[i] += curBlockSize;
1679  }
1680  inputRemaining -= curBlockSize;
1681  inputBufferCnt -= curBlockSize;
1682  }
1683 
1684  // "ls" and "rs" serve as the input sample index for the left and
1685  // right channels when processing the input samples. If we flip
1686  // over to processing delayed samples, they simply become counters
1687  // for the progress display.
1688  inLeftPos += curBlockSize;
1689  inRightPos += curBlockSize;
1690 
1691  // Get the current number of delayed samples and accumulate
1692  if (isProcessor)
1693  {
1694  auto delay = GetLatency();
1695  curDelay += delay;
1696  delayRemaining += delay;
1697 
1698  // If the plugin has delayed the output by more samples than our current
1699  // block size, then we leave the output pointers alone. This effectively
1700  // removes those delayed samples from the output buffer.
1701  if (curDelay >= curBlockSize)
1702  {
1703  curDelay -= curBlockSize;
1704  curBlockSize = 0;
1705  }
1706  // We have some delayed samples, at the beginning of the output samples,
1707  // so overlay them by shifting the remaining output samples.
1708  else if (curDelay > 0)
1709  {
1710  // curDelay is bounded by curBlockSize:
1711  auto delay = curDelay.as_size_t();
1712  curBlockSize -= delay;
1713  for (size_t i = 0; i < chans; i++)
1714  {
1715  memmove(outBufPos[i], outBufPos[i] + delay, sizeof(float) * curBlockSize);
1716  }
1717  curDelay = 0;
1718  }
1719  }
1720 
1721  // Adjust the number of samples in the output buffers
1722  outputBufferCnt += curBlockSize;
1723 
1724  // Still have room in the output buffers
1725  if (outputBufferCnt < mBufferSize)
1726  {
1727  // Bump to next output buffer position
1728  for (size_t i = 0; i < chans; i++)
1729  {
1730  outBufPos[i] += curBlockSize;
1731  }
1732  }
1733  // Output buffers have filled
1734  else
1735  {
1736  if (isProcessor)
1737  {
1738  // Write them out
1739  left->Set((samplePtr) outBuffer[0].get(), floatSample, outLeftPos, outputBufferCnt);
1740  if (right)
1741  {
1742  if (chans >= 2)
1743  {
1744  right->Set((samplePtr) outBuffer[1].get(), floatSample, outRightPos, outputBufferCnt);
1745  }
1746  else
1747  {
1748  right->Set((samplePtr) outBuffer[0].get(), floatSample, outRightPos, outputBufferCnt);
1749  }
1750  }
1751  }
1752  else if (isGenerator)
1753  {
1754  genLeft->Append((samplePtr) outBuffer[0].get(), floatSample, outputBufferCnt);
1755  if (genRight)
1756  {
1757  genRight->Append((samplePtr) outBuffer[1].get(), floatSample, outputBufferCnt);
1758  }
1759  }
1760 
1761  // Reset the output buffer positions
1762  for (size_t i = 0; i < chans; i++)
1763  {
1764  outBufPos[i] = outBuffer[i].get();
1765  }
1766 
1767  // Bump to the next track position
1768  outLeftPos += outputBufferCnt;
1769  outRightPos += outputBufferCnt;
1770  outputBufferCnt = 0;
1771  }
1772 
1773  if (mNumChannels > 1)
1774  {
1775  if (TrackGroupProgress(count,
1776  (inLeftPos - leftStart).as_double() /
1777  (isGenerator ? genLength : len).as_double()))
1778  {
1779  rc = false;
1780  break;
1781  }
1782  }
1783  else
1784  {
1785  if (TrackProgress(count,
1786  (inLeftPos - leftStart).as_double() /
1787  (isGenerator ? genLength : len).as_double()))
1788  {
1789  rc = false;
1790  break;
1791  }
1792  }
1793  }
1794 
1795  // Put any remaining output
1796  if (rc && outputBufferCnt)
1797  {
1798  if (isProcessor)
1799  {
1800  left->Set((samplePtr) outBuffer[0].get(), floatSample, outLeftPos, outputBufferCnt);
1801  if (right)
1802  {
1803  if (chans >= 2)
1804  {
1805  right->Set((samplePtr) outBuffer[1].get(), floatSample, outRightPos, outputBufferCnt);
1806  }
1807  else
1808  {
1809  right->Set((samplePtr) outBuffer[0].get(), floatSample, outRightPos, outputBufferCnt);
1810  }
1811  }
1812  }
1813  else if (isGenerator)
1814  {
1815  genLeft->Append((samplePtr) outBuffer[0].get(), floatSample, outputBufferCnt);
1816  if (genRight)
1817  {
1818  genRight->Append((samplePtr) outBuffer[1].get(), floatSample, outputBufferCnt);
1819  }
1820  }
1821  }
1822 
1823  if (rc && isGenerator)
1824  {
1826 
1827  // PRL: this code was here and could not have been the right
1828  // intent, mixing time and sampleCount values:
1829  // StepTimeWarper warper(mT0 + genLength, genLength - (mT1 - mT0));
1830 
1831  // This looks like what it should have been:
1832  // StepTimeWarper warper(mT0 + genDur, genDur - (mT1 - mT0));
1833  // But rather than fix it, I will just disable the use of it for now.
1834  // The purpose was to remap split lines inside the selected region when
1835  // a generator replaces it with sound of different duration. But
1836  // the "correct" version might have the effect of mapping some splits too
1837  // far left, to before the selection.
1838  // In practice the wrong version probably did nothing most of the time,
1839  // because the cutoff time for the step time warper was 44100 times too
1840  // far from mT0.
1841 
1842  // Transfer the data from the temporary tracks to the actual ones
1843  genLeft->Flush();
1844  // mT1 gives us the NEW selection. We want to replace up to GetSel1().
1845  left->ClearAndPaste(mT0, p->GetSel1(), genLeft.get(), true, true,
1846  nullptr /* &warper */);
1847 
1848  if (genRight)
1849  {
1850  genRight->Flush();
1851  right->ClearAndPaste(mT0, mT1, genRight.get(), true, true,
1852  nullptr /* &warper */);
1853  }
1854  }
1855 
1856  } // End scope for cleanup
1857  return rc;
1858 }
1859 
1861 {
1862 }
1863 
1865 {
1866  return;
1867 }
1868 
1870 {
1871  return true;
1872 }
1873 
1875 {
1876  return true;
1877 }
1878 
1879 bool Effect::EnableApply(bool enable)
1880 {
1881  // May be called during initialization, so try to find the dialog
1882  wxWindow *dlg = mUIDialog;
1883  if (!dlg && mUIParent)
1884  {
1885  dlg = wxGetTopLevelParent(mUIParent);
1886  }
1887 
1888  if (dlg)
1889  {
1890  wxWindow *apply = dlg->FindWindow(wxID_APPLY);
1891 
1892  // Don't allow focus to get trapped
1893  if (!enable)
1894  {
1895  wxWindow *focus = dlg->FindFocus();
1896  if (focus == apply)
1897  {
1898  dlg->FindWindow(wxID_CLOSE)->SetFocus();
1899  }
1900  }
1901 
1902  apply->Enable(enable);
1903  }
1904 
1905  EnablePreview(enable);
1906 
1907  return enable;
1908 }
1909 
1910 bool Effect::EnablePreview(bool enable)
1911 {
1912  // May be called during initialization, so try to find the dialog
1913  wxWindow *dlg = mUIDialog;
1914  if (!dlg && mUIParent)
1915  {
1916  dlg = wxGetTopLevelParent(mUIParent);
1917  }
1918 
1919  if (dlg)
1920  {
1921  wxWindow *play = dlg->FindWindow(kPlayID);
1922  if (play)
1923  {
1924  wxWindow *rewind = dlg->FindWindow(kRewindID);
1925  wxWindow *ffwd = dlg->FindWindow(kFFwdID);
1926 
1927  // Don't allow focus to get trapped
1928  if (!enable)
1929  {
1930  wxWindow *focus = dlg->FindFocus();
1931  if (focus && (focus == play || focus == rewind || focus == ffwd))
1932  {
1933  dlg->FindWindow(wxID_CLOSE)->SetFocus();
1934  }
1935  }
1936 
1937  play->Enable(enable);
1938  if (SupportsRealtime())
1939  {
1940  rewind->Enable(enable);
1941  ffwd->Enable(enable);
1942  }
1943  }
1944  }
1945 
1946  return enable;
1947 }
1948 
1949 void Effect::EnableDebug(bool enable)
1950 {
1951  mUIDebug = enable;
1952 }
1953 
1954 void Effect::SetLinearEffectFlag(bool linearEffectFlag)
1955 {
1956  mIsLinearEffect = linearEffectFlag;
1957 }
1958 
1959 void Effect::SetPreviewFullSelectionFlag(bool previewDurationFlag)
1960 {
1961  mPreviewFullSelection = previewDurationFlag;
1962 }
1963 
1964 
1965 void Effect::IncludeNotSelectedPreviewTracks(bool includeNotSelected)
1966 {
1967  mPreviewWithNotSelected = includeNotSelected;
1968 }
1969 
1970 bool Effect::TotalProgress(double frac)
1971 {
1972  auto updateResult = (mProgress ?
1973  mProgress->Update(frac) :
1975  return (updateResult != ProgressResult::Success);
1976 }
1977 
1978 bool Effect::TrackProgress(int whichTrack, double frac, const wxString &msg)
1979 {
1980  auto updateResult = (mProgress ?
1981  mProgress->Update(whichTrack + frac, (double) mNumTracks, msg) :
1983  return (updateResult != ProgressResult::Success);
1984 }
1985 
1986 bool Effect::TrackGroupProgress(int whichGroup, double frac, const wxString &msg)
1987 {
1988  auto updateResult = (mProgress ?
1989  mProgress->Update(whichGroup + frac, (double) mNumGroups, msg) :
1991  return (updateResult != ProgressResult::Success);
1992 }
1993 
1995  const WaveTrack *track, sampleCount *start, sampleCount *len)
1996 {
1997  double trackStart = track->GetStartTime();
1998  double trackEnd = track->GetEndTime();
1999  double t0 = mT0 < trackStart ? trackStart : mT0;
2000  double t1 = mT1 > trackEnd ? trackEnd : mT1;
2001 
2002 #if 0
2003  if (GetType() & INSERT_EFFECT) {
2004  t1 = t0 + mDuration;
2005  if (mT0 == mT1) {
2006  // Not really part of the calculation, but convenient to put here
2007  track->InsertSilence(t0, t1);
2008  }
2009  }
2010 #endif
2011 
2012  if (t1 > t0) {
2013  *start = track->TimeToLongSamples(t0);
2014  auto end = track->TimeToLongSamples(t1);
2015  *len = end - *start;
2016  }
2017  else {
2018  *start = 0;
2019  *len = 0;
2020  }
2021 }
2022 
2023 //
2024 // private methods
2025 //
2026 // Use these two methods to copy the input tracks to mOutputTracks, if
2027 // doing the processing on them, and replacing the originals only on success (and not cancel).
2028 // Copy the group tracks that have tracks selected
2030 {
2032 }
2033 
2034 void Effect::CopyInputTracks(int trackType)
2035 {
2036  // Reset map
2037  mIMap.clear();
2038  mOMap.clear();
2039 
2041  mOutputTracksType = trackType;
2042 
2043  //iterate over tracks of type trackType (All types if Track::All)
2044  TrackListOfKindIterator aIt(trackType, mTracks);
2045  t2bHash added;
2046 
2047  for (Track *aTrack = aIt.First(); aTrack; aTrack = aIt.Next())
2048  {
2049  // Include selected tracks, plus sync-lock selected tracks for Track::All.
2050  if (aTrack->GetSelected() ||
2051  (trackType == Track::All && aTrack->IsSyncLockSelected()))
2052  {
2053  Track *o = mOutputTracks->Add(aTrack->Duplicate());
2054  mIMap.push_back(aTrack);
2055  mOMap.push_back(o);
2056  }
2057  }
2058 }
2059 
2060 Track *Effect::AddToOutputTracks(std::unique_ptr<Track> &&t)
2061 {
2062  mIMap.push_back(NULL);
2063  mOMap.push_back(t.get());
2064  return mOutputTracks->Add(std::move(t));
2065 }
2066 
2068  : mpEffect(pEffect)
2069 {
2070  LabelTrack::Holder pTrack{ pEffect->mFactory->NewLabelTrack() };
2071  mpTrack = pTrack.get();
2072  if (!name.empty())
2073  pTrack->SetName(name);
2074  pEffect->mTracks->Add(std::move(pTrack));
2075 }
2076 
2078 {
2079  mpEffect = that.mpEffect;
2080  mpTrack = that.mpTrack;
2081  that.Commit();
2082 }
2083 
2085 {
2086  mpEffect = nullptr;
2087 }
2088 
2090 {
2091  if (mpEffect) {
2092  // not committed -- DELETE the label track
2093  mpEffect->mTracks->Remove(mpTrack);
2094  }
2095 }
2096 
2097 auto Effect::AddAnalysisTrack(const wxString &name) -> std::shared_ptr<AddedAnalysisTrack>
2098 {
2099  return std::shared_ptr<AddedAnalysisTrack>
2100  { safenew AddedAnalysisTrack{ this, name } };
2101 }
2102 
2104  (Effect *pEffect, const LabelTrack *pOrigTrack, const wxString &name)
2105  : mpEffect(pEffect)
2106 {
2107  // copy LabelTrack here, so it can be undone on cancel
2108  auto newTrack = pOrigTrack->Copy(pOrigTrack->GetStartTime(), pOrigTrack->GetEndTime());
2109 
2110  mpTrack = static_cast<LabelTrack*>(newTrack.get());
2111 
2112  // Why doesn't LabelTrack::Copy complete the job? :
2113  mpTrack->SetOffset(pOrigTrack->GetStartTime());
2114  if (!name.empty())
2115  mpTrack->SetName(name);
2116 
2117  // mpOrigTrack came from mTracks which we own but expose as const to subclasses
2118  // So it's okay that we cast it back to const
2119  mpOrigTrack =
2120  pEffect->mTracks->Replace(const_cast<LabelTrack*>(pOrigTrack),
2121 #ifdef __AUDACITY_OLD_STD__
2122  std::shared_ptr<Track>(newTrack.release())
2123 #else
2124  std::move(newTrack)
2125 #endif
2126  );
2127 }
2128 
2130 {
2131  mpEffect = that.mpEffect;
2132  mpTrack = that.mpTrack;
2133  mpOrigTrack = std::move(that.mpOrigTrack);
2134  that.Commit();
2135 }
2136 
2138 {
2139  mpEffect = nullptr;
2140 }
2141 
2143 {
2144  if (mpEffect) {
2145  // not committed -- DELETE the label track
2146  // mpOrigTrack came from mTracks which we own but expose as const to subclasses
2147  // So it's okay that we cast it back to const
2148  mpEffect->mTracks->Replace(mpTrack, std::move(mpOrigTrack));
2149  }
2150 }
2151 
2153  (const LabelTrack *pOrigTrack, const wxString &name) -> ModifiedAnalysisTrack
2154 {
2155  return{ this, pOrigTrack, name };
2156 }
2157 
2158 // If bGoodResult, replace mTracks tracks with successfully processed mOutputTracks copies.
2159 // Else clear and DELETE mOutputTracks copies.
2160 void Effect::ReplaceProcessedTracks(const bool bGoodResult)
2161 {
2162  if (!bGoodResult) {
2163  // Free resources, unless already freed.
2164 
2165  // Processing failed or was cancelled so throw away the processed tracks.
2166  if ( mOutputTracks )
2167  mOutputTracks->Clear();
2168 
2169  // Reset map
2170  mIMap.clear();
2171  mOMap.clear();
2172 
2174 
2175  //TODO:undo the non-gui ODTask transfer
2176  return;
2177  }
2178 
2179  // Assume resources need to be freed.
2180  wxASSERT(mOutputTracks); // Make sure we at least did the CopyInputTracks().
2181 
2182  auto iterOut = mOutputTracks->ListOfTracks::begin(),
2183  iterEnd = mOutputTracks->ListOfTracks::end();
2184 
2185  size_t cnt = mOMap.size();
2186  size_t i = 0;
2187 
2188  for (; iterOut != iterEnd; ++i) {
2189  ListOfTracks::value_type o = std::move(*iterOut);
2190  // If tracks were removed from mOutputTracks, then there will be
2191  // tracks in the map that must be removed from mTracks.
2192  while (i < cnt && mOMap[i] != o.get()) {
2193  const auto t = mIMap[i];
2194  if (t) {
2195  mTracks->Remove(t);
2196  }
2197  i++;
2198  }
2199 
2200  // This should never happen
2201  wxASSERT(i < cnt);
2202 
2203  // Remove the track from the output list...don't DELETE it
2204  iterOut = mOutputTracks->erase(iterOut);
2205 
2206  const auto t = mIMap[i];
2207  if (t == NULL)
2208  {
2209  // This track is a NEW addition to output tracks; add it to mTracks
2210  mTracks->Add(std::move(o));
2211  }
2212  else
2213  {
2214  // Replace mTracks entry with the NEW track
2215  WaveTrack *newTrack = static_cast<WaveTrack*>(o.get());
2216  mTracks->Replace(t, std::move(o));
2217 
2218  // Swap the wavecache track the ondemand task uses, since now the NEW
2219  // one will be kept in the project
2222  newTrack);
2223  }
2224  }
2225  }
2226 
2227  // If tracks were removed from mOutputTracks, then there may be tracks
2228  // left at the end of the map that must be removed from mTracks.
2229  while (i < cnt) {
2230  const auto t = mIMap[i];
2231  if (t) {
2232  mTracks->Remove(t);
2233  }
2234  i++;
2235  }
2236 
2237  // Reset map
2238  mIMap.clear();
2239  mOMap.clear();
2240 
2241  // Make sure we processed everything
2242  wxASSERT(mOutputTracks->empty());
2243 
2244  // The output list is no longer needed
2245  mOutputTracks.reset();
2247 }
2248 
2250 {
2251  mNumTracks = 0;
2252  mNumGroups = 0;
2253 
2255  Track *t = iter.First();
2256 
2257  while(t) {
2258  if (!t->GetSelected()) {
2259  t = iter.Next();
2260  continue;
2261  }
2262 
2263  if (t->GetKind() == Track::Wave) {
2264  mNumTracks++;
2265  if (!t->GetLinked())
2266  mNumGroups++;
2267  }
2268  t = iter.Next();
2269  }
2270 }
2271 
2272 double Effect::CalcPreviewInputLength(double previewLength)
2273 {
2274  return previewLength;
2275 }
2276 
2277 // RealtimeAddProcessor and RealtimeProcess use the same method of
2278 // determining the current processor index, so updates to one should
2279 // be reflected in the other.
2280 bool Effect::RealtimeAddProcessor(int group, unsigned chans, float rate)
2281 {
2282  auto ichans = chans;
2283  auto ochans = chans;
2284  auto gchans = chans;
2285 
2286  // Reset processor index
2287  if (group == 0)
2288  {
2289  mCurrentProcessor = 0;
2290  mGroupProcessor.Clear();
2291  }
2292 
2293  // Remember the processor starting index
2295 
2296  // Call the client until we run out of input or output channels
2297  while (ichans > 0 && ochans > 0)
2298  {
2299  // If we don't have enough input channels to accomodate the client's
2300  // requirements, then we replicate the input channels until the
2301  // client's needs are met.
2302  if (ichans < mNumAudioIn)
2303  {
2304  // All input channels have been consumed
2305  ichans = 0;
2306  }
2307  // Otherwise fullfil the client's needs with as many input channels as possible.
2308  // After calling the client with this set, we will loop back up to process more
2309  // of the input/output channels.
2310  else if (ichans >= mNumAudioIn)
2311  {
2312  gchans = mNumAudioIn;
2313  ichans -= gchans;
2314  }
2315 
2316  // If we don't have enough output channels to accomodate the client's
2317  // requirements, then we provide all of the output channels and fulfill
2318  // the client's needs with dummy buffers. These will just get tossed.
2319  if (ochans < mNumAudioOut)
2320  {
2321  // All output channels have been consumed
2322  ochans = 0;
2323  }
2324  // Otherwise fullfil the client's needs with as many output channels as possible.
2325  // After calling the client with this set, we will loop back up to process more
2326  // of the input/output channels.
2327  else if (ochans >= mNumAudioOut)
2328  {
2329  ochans -= mNumAudioOut;
2330  }
2331 
2332  // Add a NEW processor
2333  RealtimeAddProcessor(gchans, rate);
2334 
2335  // Bump to next processor
2337  }
2338 
2339  return true;
2340 }
2341 
2342 // RealtimeAddProcessor and RealtimeProcess use the same method of
2343 // determining the current processor group, so updates to one should
2344 // be reflected in the other.
2345 size_t Effect::RealtimeProcess(int group,
2346  unsigned chans,
2347  float **inbuf,
2348  float **outbuf,
2349  size_t numSamples)
2350 {
2351  //
2352  // The caller passes the number of channels to process and specifies
2353  // the number of input and output buffers. There will always be the
2354  // same number of output buffers as there are input buffers.
2355  //
2356  // Effects always require a certain number of input and output buffers,
2357  // so if the number of channels we're curently processing are different
2358  // than what the effect expects, then we use a few methods of satisfying
2359  // the effects requirements.
2360  float **clientIn = (float **) alloca(mNumAudioIn * sizeof(float *));
2361  float **clientOut = (float **) alloca(mNumAudioOut * sizeof(float *));
2362  float *dummybuf = (float *) alloca(numSamples * sizeof(float));
2363  decltype(numSamples) len = 0;
2364  auto ichans = chans;
2365  auto ochans = chans;
2366  auto gchans = chans;
2367  unsigned indx = 0;
2368  unsigned ondx = 0;
2369 
2370  int processor = mGroupProcessor[group];
2371 
2372  // Call the client until we run out of input or output channels
2373  while (ichans > 0 && ochans > 0)
2374  {
2375  // If we don't have enough input channels to accomodate the client's
2376  // requirements, then we replicate the input channels until the
2377  // client's needs are met.
2378  if (ichans < mNumAudioIn)
2379  {
2380  for (size_t i = 0; i < mNumAudioIn; i++)
2381  {
2382  if (indx == ichans)
2383  {
2384  indx = 0;
2385  }
2386  clientIn[i] = inbuf[indx++];
2387  }
2388 
2389  // All input channels have been consumed
2390  ichans = 0;
2391  }
2392  // Otherwise fullfil the client's needs with as many input channels as possible.
2393  // After calling the client with this set, we will loop back up to process more
2394  // of the input/output channels.
2395  else if (ichans >= mNumAudioIn)
2396  {
2397  gchans = 0;
2398  for (size_t i = 0; i < mNumAudioIn; i++, ichans--, gchans++)
2399  {
2400  clientIn[i] = inbuf[indx++];
2401  }
2402  }
2403 
2404  // If we don't have enough output channels to accomodate the client's
2405  // requirements, then we provide all of the output channels and fulfill
2406  // the client's needs with dummy buffers. These will just get tossed.
2407  if (ochans < mNumAudioOut)
2408  {
2409  for (size_t i = 0; i < mNumAudioOut; i++)
2410  {
2411  if (i < ochans)
2412  {
2413  clientOut[i] = outbuf[i];
2414  }
2415  else
2416  {
2417  clientOut[i] = dummybuf;
2418  }
2419  }
2420 
2421  // All output channels have been consumed
2422  ochans = 0;
2423  }
2424  // Otherwise fullfil the client's needs with as many output channels as possible.
2425  // After calling the client with this set, we will loop back up to process more
2426  // of the input/output channels.
2427  else if (ochans >= mNumAudioOut)
2428  {
2429  for (size_t i = 0; i < mNumAudioOut; i++, ochans--)
2430  {
2431  clientOut[i] = outbuf[ondx++];
2432  }
2433  }
2434 
2435  // Finally call the plugin to process the block
2436  len = 0;
2437  for (decltype(numSamples) block = 0; block < numSamples; block += mBlockSize)
2438  {
2439  auto cnt = std::min(numSamples - block, mBlockSize);
2440  len += RealtimeProcess(processor, clientIn, clientOut, cnt);
2441 
2442  for (size_t i = 0 ; i < mNumAudioIn; i++)
2443  {
2444  clientIn[i] += cnt;
2445  }
2446 
2447  for (size_t i = 0 ; i < mNumAudioOut; i++)
2448  {
2449  clientOut[i] += cnt;
2450  }
2451  }
2452 
2453  // Bump to next processor
2454  processor++;
2455  }
2456 
2457  return len;
2458 }
2459 
2461 {
2462  return mRealtimeSuspendCount == 0;
2463 }
2464 
2466 {
2467  return false;
2468 }
2469 
2470 void Effect::Preview(bool dryOnly)
2471 {
2472  if (mNumTracks == 0) { // nothing to preview
2473  return;
2474  }
2475 
2476  if (gAudioIO->IsBusy()) {
2477  return;
2478  }
2479 
2480  wxWindow *FocusDialog = wxWindow::FindFocus();
2481 
2482  double previewDuration;
2483  bool isNyquist = (GetFamily().IsSameAs(NYQUISTEFFECTS_FAMILY))? true : false;
2484  bool isGenerator = GetType() == EffectTypeGenerate;
2485 
2486  // Mix a few seconds of audio from all of the tracks
2487  double previewLen;
2488  gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLen, 6.0);
2489 
2490  const double rate = mProjectRate;
2491 
2492  if (isNyquist && isGenerator) {
2493  previewDuration = CalcPreviewInputLength(previewLen);
2494  }
2495  else {
2496  previewDuration = wxMin(mDuration, CalcPreviewInputLength(previewLen));
2497  }
2498 
2499  double t1 = mT0 + previewDuration;
2500 
2501  if ((t1 > mT1) && !(isNyquist && isGenerator)) {
2502  t1 = mT1;
2503  }
2504 
2505  if (t1 <= mT0)
2506  return;
2507 
2508  bool success = true;
2509  auto vr0 = valueRestorer( mT0 );
2510  auto vr1 = valueRestorer( mT1 );
2511  // Most effects should stop at t1.
2512  if (!mPreviewFullSelection)
2513  mT1 = t1;
2514 
2515  // Save the original track list
2516  TrackList *saveTracks = mTracks;
2517 
2518  auto cleanup = finally( [&] {
2519  mTracks = saveTracks;
2520 
2521  // Effect is already inited; we will call Process, End, and then Init
2522  // again, so the state is exactly the way it was before Preview
2523  // was called.
2524  if (!dryOnly) {
2525  End();
2526  GuardedCall( [&]{ Init(); } );
2527  }
2528 
2529  if (FocusDialog) {
2530  FocusDialog->SetFocus();
2531  }
2532 
2533  // In case of failed effect, be sure to free memory.
2534  ReplaceProcessedTracks( false );
2535  } );
2536 
2537  // Build NEW tracklist from rendering tracks
2538  auto uTracks = TrackList::Create();
2539  mTracks = uTracks.get();
2540 
2541  // Linear Effect preview optimised by pre-mixing to one track.
2542  // Generators need to generate per track.
2543  if (mIsLinearEffect && !isGenerator) {
2544  WaveTrack::Holder mixLeft, mixRight;
2545  MixAndRender(saveTracks, mFactory, rate, floatSample, mT0, t1, mixLeft, mixRight);
2546  if (!mixLeft)
2547  return;
2548 
2549  mixLeft->Offset(-mixLeft->GetStartTime());
2550  mixLeft->SetSelected(true);
2551  mixLeft->SetDisplay(WaveTrack::NoDisplay);
2552  mTracks->Add(std::move(mixLeft));
2553  if (mixRight) {
2554  mixRight->Offset(-mixRight->GetStartTime());
2555  mixRight->SetSelected(true);
2556  mTracks->Add(std::move(mixRight));
2557  }
2558  }
2559  else {
2560  TrackListOfKindIterator iter(Track::Wave, saveTracks);
2561  WaveTrack *src = (WaveTrack *) iter.First();
2562  while (src)
2563  {
2564  if (src->GetSelected() || mPreviewWithNotSelected) {
2565  auto dest = src->Copy(mT0, t1);
2566  dest->SetSelected(src->GetSelected());
2567  static_cast<WaveTrack*>(dest.get())->SetDisplay(WaveTrack::NoDisplay);
2568  mTracks->Add(std::move(dest));
2569  }
2570  src = (WaveTrack *) iter.Next();
2571  }
2572  }
2573 
2574  // NEW tracks start at time zero.
2575  // Adjust mT0 and mT1 to be the times to process, and to
2576  // play back in these tracks
2577  mT1 -= mT0;
2578  mT0 = 0.0;
2579 
2580 
2581  // Update track/group counts
2582  CountWaveTracks();
2583 
2584  // Apply effect
2585  if (!dryOnly) {
2586  ProgressDialog progress{
2587  GetTranslatedName(),
2588  _("Preparing preview"),
2590  }; // Have only "Stop" button.
2591  auto vr = valueRestorer( mProgress, &progress );
2592 
2593  auto vr2 = valueRestorer( mIsPreview, true );
2594 
2595  success = Process();
2596  }
2597 
2598  if (success)
2599  {
2600  WaveTrackConstArray playbackTracks;
2601  WaveTrackArray recordingTracks;
2602 
2604  WaveTrack *src = (WaveTrack *) iter.First();
2605  while (src) {
2606  playbackTracks.push_back(Track::Pointer<WaveTrack>(src));
2607  src = (WaveTrack *) iter.Next();
2608  }
2609  // Some effects (Paulstretch) may need to generate more
2610  // than previewLen, so take the min.
2611  t1 = std::min(mT0 + previewLen, mT1);
2612 
2613 #ifdef EXPERIMENTAL_MIDI_OUT
2614  NoteTrackArray empty;
2615 #endif
2616  // Start audio playing
2617  AudioIOStartStreamOptions options { rate };
2618  int token =
2619  gAudioIO->StartStream(playbackTracks, recordingTracks,
2620 #ifdef EXPERIMENTAL_MIDI_OUT
2621  empty,
2622 #endif
2623  mT0, t1, options);
2624 
2625  if (token) {
2626  auto previewing = ProgressResult::Success;
2627  // The progress dialog must be deleted before stopping the stream
2628  // to allow events to flow to the app during StopStream processing.
2629  // The progress dialog blocks these events.
2630  {
2631  ProgressDialog progress
2632  (GetTranslatedName(), _("Previewing"), pdlgHideCancelButton);
2633 
2634  while (gAudioIO->IsStreamActive(token) && previewing == ProgressResult::Success) {
2635  ::wxMilliSleep(100);
2636  previewing = progress.Update(gAudioIO->GetStreamTime() - mT0, t1 - mT0);
2637  }
2638  }
2639 
2640  gAudioIO->StopStream();
2641 
2642  while (gAudioIO->IsBusy()) {
2643  ::wxMilliSleep(100);
2644  }
2645  }
2646  else {
2647  ShowErrorDialog(FocusDialog, _("Error"),
2648  _("Error opening sound device.\nTry changing the audio host, playback device and the project sample rate."),
2649  wxT("Error_opening_sound_device"));
2650  }
2651  }
2652 }
2653 
2655 (const wxString& message, long style, const wxString &titleStr)
2656 {
2657  wxString title;
2658  if (titleStr.empty())
2659  title = GetTranslatedName();
2660  else
2661  title = wxString::Format(_("%s: %s"), GetTranslatedName(), titleStr);
2662  return AudacityMessageBox(message, title, style, mUIParent);
2663 }
2664 
2665 BEGIN_EVENT_TABLE(EffectDialog, wxDialogWrapper)
2666  EVT_BUTTON(wxID_OK, EffectDialog::OnOk)
2668 
2669 EffectDialog::EffectDialog(wxWindow * parent,
2670  const wxString & title,
2671  int type,
2672  int flags,
2673  int additionalButtons)
2674 : wxDialogWrapper(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, flags)
2675 {
2676  mType = type;
2677  mAdditionalButtons = additionalButtons;
2678 }
2679 
2681 {
2682  ShuttleGui S(this, eIsCreating);
2683 
2684  S.SetBorder(5);
2685  S.StartVerticalLay(true);
2686  {
2687  PopulateOrExchange(S);
2688 
2689  long buttons = eOkButton;
2690  if (mType != EffectTypeAnalyze)
2691  {
2692  buttons |= eCancelButton;
2693  if (mType == EffectTypeProcess)
2694  {
2695  buttons |= ePreviewButton;
2696  }
2697  }
2698  S.AddStandardButtons(buttons|mAdditionalButtons);
2699  }
2700  S.EndVerticalLay();
2701 
2702  Layout();
2703  Fit();
2704  SetMinSize(GetSize());
2705  Center();
2706 }
2707 
2712 {
2713  return;
2714 }
2715 
2717 {
2718  ShuttleGui S(this, eIsSettingToDialog);
2719  PopulateOrExchange(S);
2720 
2721  return true;
2722 }
2723 
2725 {
2727  PopulateOrExchange(S);
2728 
2729  return true;
2730 }
2731 
2733 {
2734  return true;
2735 }
2736 
2737 void EffectDialog::OnPreview(wxCommandEvent & WXUNUSED(evt))
2738 {
2739  return;
2740 }
2741 
2742 void EffectDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
2743 {
2744  // On wxGTK (wx2.8.12), the default action is still executed even if
2745  // the button is disabled. This appears to affect all wxDialogs, not
2746  // just our Effects dialogs. So, this is a only temporary workaround
2747  // for legacy effects that disable the OK button. Hopefully this has
2748  // been corrected in wx3.
2749  if (FindWindow(wxID_OK)->IsEnabled() && Validate() && TransferDataFromWindow())
2750  {
2751  EndModal(true);
2752  }
2753 
2754  return;
2755 }
2756 
2758 //
2759 // EffectPanel
2760 //
2762 
2763 class EffectPanel final : public wxPanelWrapper
2764 {
2765 public:
2766  EffectPanel(wxWindow *parent)
2767  : wxPanelWrapper(parent)
2768  {
2769  // This fools NVDA into not saying "Panel" when the dialog gets focus
2770  SetName(wxT("\a"));
2771  SetLabel(wxT("\a"));
2772 
2773  mAcceptsFocus = true;
2774  }
2775 
2776  virtual ~EffectPanel()
2777  {
2778  }
2779 
2780  // ============================================================================
2781  // wxWindow implementation
2782  // ============================================================================
2783 
2784  bool AcceptsFocus() const override
2785  {
2786  return mAcceptsFocus;
2787  }
2788 
2789  // So that wxPanel is not included in Tab traversal, when required - see wxWidgets bug 15581
2790  bool AcceptsFocusFromKeyboard() const override
2791  {
2792  return mAcceptsFocus;
2793  }
2794 
2795  // ============================================================================
2796  // EffectPanel implementation
2797  // ============================================================================
2798  void SetAccept(bool accept)
2799  {
2800  mAcceptsFocus = accept;
2801  }
2802 
2803 private:
2805 };
2806 
2808 //
2809 // EffectUIHost
2810 //
2812 
2813 #include "../../images/Effect.h"
2814 
2815 BEGIN_EVENT_TABLE(EffectUIHost, wxDialogWrapper)
2816  EVT_INIT_DIALOG(EffectUIHost::OnInitDialog)
2817  EVT_ERASE_BACKGROUND(EffectUIHost::OnErase)
2818  EVT_PAINT(EffectUIHost::OnPaint)
2819  EVT_CLOSE(EffectUIHost::OnClose)
2820  EVT_BUTTON(wxID_APPLY, EffectUIHost::OnApply)
2821  EVT_BUTTON(wxID_CANCEL, EffectUIHost::OnCancel)
2822  EVT_BUTTON(wxID_HELP, EffectUIHost::OnHelp)
2823  EVT_BUTTON(eDebugID, EffectUIHost::OnDebug)
2824  EVT_BUTTON(kMenuID, EffectUIHost::OnMenu)
2825  EVT_CHECKBOX(kEnableID, EffectUIHost::OnEnable)
2826  EVT_BUTTON(kPlayID, EffectUIHost::OnPlay)
2827  EVT_BUTTON(kRewindID, EffectUIHost::OnRewind)
2828  EVT_BUTTON(kFFwdID, EffectUIHost::OnFFwd)
2829  EVT_MENU(kSaveAsID, EffectUIHost::OnSaveAs)
2830  EVT_MENU(kImportID, EffectUIHost::OnImport)
2831  EVT_MENU(kExportID, EffectUIHost::OnExport)
2832  EVT_MENU(kOptionsID, EffectUIHost::OnOptions)
2833  EVT_MENU(kDefaultsID, EffectUIHost::OnDefaults)
2834  EVT_MENU_RANGE(kUserPresetsID, kUserPresetsID + 999, EffectUIHost::OnUserPreset)
2835  EVT_MENU_RANGE(kDeletePresetID, kDeletePresetID + 999, EffectUIHost::OnDeletePreset)
2836  EVT_MENU_RANGE(kFactoryPresetsID, kFactoryPresetsID + 999, EffectUIHost::OnFactoryPreset)
2838 
2839 EffectUIHost::EffectUIHost(wxWindow *parent,
2840  Effect *effect,
2841  EffectUIClientInterface *client)
2842 : wxDialogWrapper(parent, wxID_ANY, effect->GetTranslatedName(),
2843  wxDefaultPosition, wxDefaultSize,
2844  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX | wxMAXIMIZE_BOX)
2845 {
2846 #if defined(__WXMAC__)
2847  // Make sure the effect window actually floats above the main window
2848  [[((NSView *)GetHandle()) window] setLevel:NSFloatingWindowLevel];
2849 #endif
2850 
2851  SetName( effect->GetTranslatedName() );
2852  SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
2853 
2854  mParent = parent;
2855  mEffect = effect;
2856  mClient = client;
2857 
2858  mProject = GetActiveProject();
2859 
2860  mInitialized = false;
2861  mSupportsRealtime = false;
2862 
2863  mDisableTransport = false;
2864 
2865  mEnabled = true;
2866 
2867  mPlayPos = 0.0;
2868  mClient->SetHostUI(this);
2869 }
2870 
2872 {
2873  CleanupRealtime();
2874 
2875  if (mClient)
2876  {
2877  if (mNeedsResume)
2878  Resume();
2879 
2880  mClient->CloseUI();
2881  mClient = NULL;
2882  }
2883 }
2884 
2885 // ============================================================================
2886 // wxWindow implementation
2887 // ============================================================================
2888 
2890 {
2891  return mEffect->TransferDataToWindow();
2892 }
2893 
2895 {
2896  return mEffect->TransferDataFromWindow();
2897 }
2898 
2899 // ============================================================================
2900 // wxDialog implementation
2901 // ============================================================================
2902 
2904 {
2905 #if defined(__WXMSW__)
2906  // Swap the Close and Apply buttons
2907  wxSizer *sz = mApplyBtn->GetContainingSizer();
2908  wxASSERT(mApplyBtn->GetParent()); // To justify safenew
2909  wxButton *apply = safenew wxButton(mApplyBtn->GetParent(), wxID_APPLY);
2910  sz->Replace(mCloseBtn, apply);
2911  sz->Replace(mApplyBtn, mCloseBtn);
2912  sz->Layout();
2913  mApplyBtn->Destroy();
2914  mApplyBtn = apply;
2915  mApplyBtn->SetDefault();
2916  mApplyBtn->SetLabel(wxGetStockLabel(wxID_OK, 0));
2917  mCloseBtn->SetLabel(wxGetStockLabel(wxID_CANCEL, 0));
2918 #else
2919  mApplyBtn->SetLabel(wxGetStockLabel(wxID_OK));
2920  mCloseBtn->SetLabel(wxGetStockLabel(wxID_CANCEL));
2921 #endif
2922 
2923  Layout();
2924 
2925  return wxDialogWrapper::ShowModal();
2926 }
2927 
2928 // ============================================================================
2929 // EffectUIHost implementation
2930 // ============================================================================
2931 
2933 {
2934  EffectPanel *w = safenew EffectPanel(this);
2935  {
2936  auto vs = std::make_unique<wxBoxSizer>(wxVERTICAL);
2937  {
2938  auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
2939 
2940  // Try to give the window a sensible default/minimum size
2941  w->SetMinSize(wxSize(wxMax(600, mParent->GetSize().GetWidth() * 2 / 3),
2942  mParent->GetSize().GetHeight() / 2));
2943 
2944  mDisableTransport = !gAudioIO->IsAvailable(mProject);
2945  mPlaying = gAudioIO->IsStreamActive(); // not exactly right, but will suffice
2946  mCapturing = gAudioIO->IsStreamActive() && gAudioIO->GetNumCaptureChannels() > 0;
2947 
2948  if (!mClient->PopulateUI(w))
2949  {
2950  return false;
2951  }
2952 
2953  hs->Add(w, 1, wxEXPAND);
2954  vs->Add(hs.release(), 1, wxEXPAND);
2955  }
2956 
2957  wxPanel *buttonPanel = safenew wxPanelWrapper(this, wxID_ANY);
2958  wxPanel *const bar = safenew wxPanelWrapper(buttonPanel, wxID_ANY);
2959 
2960  // This fools NVDA into not saying "Panel" when the dialog gets focus
2961  bar->SetName(wxT("\a"));
2962  bar->SetLabel(wxT("\a"));
2963 
2964  {
2965  auto bs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
2966 
2967  mSupportsRealtime = mEffect->SupportsRealtime();
2968  mIsGUI = mClient->IsGraphicalUI();
2969  mIsBatch = mEffect->IsBatchProcessing();
2970 
2971  wxBitmapButton *bb;
2972 
2973  int margin = 0;
2974 
2975 #if defined(__WXMAC__)
2976  margin = 3; // I'm sure it's needed because of the order things are created...
2977 #endif
2978 
2979  if (!mIsGUI)
2980  {
2981  wxASSERT(bar); // To justify safenew
2982  mMenuBtn = safenew wxButton(bar, kMenuID, _("&Manage"));
2983  bs->Add(mMenuBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
2984  }
2985  else
2986  {
2987  wxASSERT(bar); // To justify safenew
2988  mMenuBtn = safenew wxBitmapButton(bar, kMenuID, CreateBitmap(effect_menu_xpm, true, false));
2989 #if defined(__WXMAC__)
2990  mMenuBtn->SetName(_("&Manage"));
2991 #else
2992  mMenuBtn->SetLabel(_("&Manage"));
2993 #endif
2994  bs->Add(mMenuBtn);
2995  }
2996  mMenuBtn->SetToolTip(_("Manage presets and options"));
2997 
2998  bs->Add(5, 5);
2999 
3000  if (!mIsBatch)
3001  {
3002  if (!mIsGUI)
3003  {
3004  if (mSupportsRealtime)
3005  {
3006  wxASSERT(bar); // To justify safenew
3007  mPlayToggleBtn = safenew wxButton(bar, kPlayID, _("Start &Playback"));
3008  mPlayToggleBtn->SetToolTip(_("Start and stop playback"));
3009  bs->Add(mPlayToggleBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
3010  }
3011  else if (mEffect->GetType() != EffectTypeAnalyze)
3012  {
3013  wxASSERT(bar); // To justify safenew
3014  mPlayToggleBtn = safenew wxButton(bar, kPlayID, _("&Preview"));
3015  mPlayToggleBtn->SetToolTip(_("Preview effect"));
3016  bs->Add(mPlayToggleBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
3017  }
3018  }
3019  else
3020  {
3021  mPlayBM = CreateBitmap(effect_play_xpm, true, false);
3022  mPlayDisabledBM = CreateBitmap(effect_play_disabled_xpm, true, false);
3023  mStopBM = CreateBitmap(effect_stop_xpm, true, false);
3024  mStopDisabledBM = CreateBitmap(effect_stop_disabled_xpm, true, false);
3025  wxASSERT(bar); // To justify safenew
3026  bb = safenew wxBitmapButton(bar, kPlayID, mPlayBM);
3027  bb->SetBitmapDisabled(mPlayDisabledBM);
3028  mPlayBtn = bb;
3029  bs->Add(mPlayBtn);
3030  if (!mSupportsRealtime)
3031  {
3032  mPlayBtn->SetToolTip(_("Preview effect"));
3033 #if defined(__WXMAC__)
3034  mPlayBtn->SetName(_("Preview effect"));
3035 #else
3036  mPlayBtn->SetLabel(_("&Preview effect"));
3037 #endif
3038  }
3039  }
3040 
3041  if (mSupportsRealtime)
3042  {
3043  if (!mIsGUI)
3044  {
3045  wxASSERT(bar); // To justify safenew
3046  mRewindBtn = safenew wxButton(bar, kRewindID, _("Skip &Backward"));
3047  bs->Add(mRewindBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
3048  }
3049  else
3050  {
3051  wxASSERT(bar); // To justify safenew
3052  bb = safenew wxBitmapButton(bar, kRewindID, CreateBitmap(effect_rewind_xpm, true, true));
3053  bb->SetBitmapDisabled(CreateBitmap(effect_rewind_disabled_xpm, true, true));
3054  mRewindBtn = bb;
3055 #if defined(__WXMAC__)
3056  mRewindBtn->SetName(_("Skip &Backward"));
3057 #else
3058  mRewindBtn->SetLabel(_("Skip &Backward"));
3059 #endif
3060  bs->Add(mRewindBtn);
3061  }
3062  mRewindBtn->SetToolTip(_("Skip backward"));
3063 
3064  if (!mIsGUI)
3065  {
3066  wxASSERT(bar); // To justify safenew
3067  mFFwdBtn = safenew wxButton(bar, kFFwdID, _("Skip &Forward"));
3068  bs->Add(mFFwdBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
3069  }
3070  else
3071  {
3072  wxASSERT(bar); // To justify safenew
3073  bb = safenew wxBitmapButton(bar, kFFwdID, CreateBitmap(effect_ffwd_xpm, true, true));
3074  bb->SetBitmapDisabled(CreateBitmap(effect_ffwd_disabled_xpm, true, true));
3075  mFFwdBtn = bb;
3076 #if defined(__WXMAC__)
3077  mFFwdBtn->SetName(_("Skip &Forward"));
3078 #else
3079  mFFwdBtn->SetLabel(_("Skip &Forward"));
3080 #endif
3081  bs->Add(mFFwdBtn);
3082  }
3083  mFFwdBtn->SetToolTip(_("Skip forward"));
3084 
3085  bs->Add(5, 5);
3086 
3087  mEnableCb = safenew wxCheckBox(bar, kEnableID, _("&Enable"));
3088  mEnableCb->SetValue(mEnabled);
3089  mEnableCb->SetName(_("Enable"));
3090  bs->Add(mEnableCb, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
3091  }
3092  }
3093 
3094  bar->SetSizerAndFit(bs.release());
3095  }
3096 
3097  long buttons;
3098  if ( mEffect->ManualPage().IsEmpty() && mEffect->HelpPage().IsEmpty()) {
3099  buttons = eApplyButton + eCloseButton;
3100  this->SetAcceleratorTable(wxNullAcceleratorTable);
3101  }
3102  else {
3103  buttons = eApplyButton + eCloseButton + eHelpButton;
3104  wxAcceleratorEntry entries[1];
3105 #if defined(__WXMAC__)
3106  // Is there a standard shortcut on Mac?
3107 #else
3108  entries[0].Set(wxACCEL_NORMAL, (int) WXK_F1, wxID_HELP);
3109 #endif
3110  wxAcceleratorTable accel(1, entries);
3111  this->SetAcceleratorTable(accel);
3112  }
3113 
3114  if (mEffect->mUIDebug) {
3115  buttons += eDebugButton;
3116  }
3117 
3118  buttonPanel->SetSizer(CreateStdButtonSizer(buttonPanel, buttons, bar).release());
3119  vs->Add(buttonPanel, 0, wxEXPAND);
3120 
3121  SetSizer(vs.release());
3122  }
3123 
3124  Layout();
3125  Fit();
3126  Center();
3127 
3128  mApplyBtn = (wxButton *) FindWindow(wxID_APPLY);
3129  mCloseBtn = (wxButton *) FindWindow(wxID_CANCEL);
3130 
3131  UpdateControls();
3132 
3133  w->SetAccept(!mIsGUI);
3134  (!mIsGUI ? w : FindWindow(wxID_APPLY))->SetFocus();
3135 
3136  LoadUserPresets();
3137 
3138  InitializeRealtime();
3139 
3140  SetMinSize(GetSize());
3141  return true;
3142 }
3143 
3144 void EffectUIHost::OnInitDialog(wxInitDialogEvent & evt)
3145 {
3146  // Do default handling
3147  wxDialogWrapper::OnInitDialog(evt);
3148 
3149 #if wxCHECK_VERSION(3, 0, 0)
3150 //#warning "check to see if this still needed in wx3"
3151 #endif
3152 
3153  // Pure hackage coming down the pike...
3154  //
3155  // I have no idea why, but if a wxTextCtrl is the first control in the
3156  // panel, then its contents will not be automatically selected when the
3157  // dialog is displayed.
3158  //
3159  // So, we do the selection manually.
3160  wxTextCtrl *focused = wxDynamicCast(FindFocus(), wxTextCtrl);
3161  if (focused)
3162  {
3163  focused->SelectAll();
3164  }
3165 }
3166 
3167 void EffectUIHost::OnErase(wxEraseEvent & WXUNUSED(evt))
3168 {
3169  // Ignore it
3170 }
3171 
3172 void EffectUIHost::OnPaint(wxPaintEvent & WXUNUSED(evt))
3173 {
3174  wxPaintDC dc(this);
3175 
3176  dc.Clear();
3177 }
3178 
3179 void EffectUIHost::OnClose(wxCloseEvent & WXUNUSED(evt))
3180 {
3181  DoCancel();
3182 
3183  CleanupRealtime();
3184 
3185  Hide();
3186 
3187  if (mNeedsResume)
3188  Resume();
3189  mClient->CloseUI();
3190  mClient = NULL;
3191 
3192  Destroy();
3193 }
3194 
3195 void EffectUIHost::OnApply(wxCommandEvent & evt)
3196 {
3197  // On wxGTK (wx2.8.12), the default action is still executed even if
3198  // the button is disabled. This appears to affect all wxDialogs, not
3199  // just our Effects dialogs. So, this is a only temporary workaround
3200  // for legacy effects that disable the OK button. Hopefully this has
3201  // been corrected in wx3.
3202  if (!FindWindow(wxID_APPLY)->IsEnabled())
3203  {
3204  return;
3205  }
3206 
3207  // Honor the "select all if none" preference...a little hackish, but whatcha gonna do...
3208  if (!mIsBatch && mEffect->GetType() != EffectTypeGenerate && mProject->mViewInfo.selectedRegion.isPoint())
3209  {
3210  auto flags = AlwaysEnabledFlag;
3211  bool allowed = mProject->ReportIfActionNotAllowed(
3212  mEffect->GetTranslatedName(),
3213  flags,
3216  if (!allowed)
3217  return;
3218  }
3219 
3220  if (!mClient->ValidateUI())
3221  {
3222  return;
3223  }
3224 
3225  // This will take care of calling TransferDataFromWindow()
3226  if (!mEffect->SaveUserPreset(mEffect->GetCurrentSettingsGroup()))
3227  {
3228  return;
3229  }
3230 
3231  mEffect->mUIResultID = evt.GetId();
3232 
3233  if (IsModal())
3234  {
3235  mDismissed = true;
3236 
3237  EndModal(true);
3238 
3239  Close();
3240 
3241  return;
3242  }
3243 
3244  // Progress dialog no longer yields, so this "shouldn't" be necessary (yet to be proven
3245  // for sure), but it is a nice visual cue that something is going on.
3246  mApplyBtn->Disable();
3247  auto cleanup = finally( [&] { mApplyBtn->Enable(); } );
3248 
3249  mEffect->Apply();
3250 }
3251 
3253 {
3254  if (!mDismissed) {
3255  mEffect->mUIResultID = wxID_CANCEL;
3256 
3257  if (IsModal())
3258  EndModal(false);
3259  else
3260  Hide();
3261 
3262  mDismissed = true;
3263  }
3264 }
3265 
3266 void EffectUIHost::OnCancel(wxCommandEvent & WXUNUSED(evt))
3267 {
3268  DoCancel();
3269  Close();
3270 }
3271 
3272 void EffectUIHost::OnHelp(wxCommandEvent & WXUNUSED(event))
3273 {
3274  if (mEffect->GetFamily().IsSameAs(NYQUISTEFFECTS_FAMILY) && (mEffect->ManualPage().IsEmpty())) {
3275  // Old ShowHelp required when there is no on-line manual.
3276  // Always use default web browser to allow full-featured HTML pages.
3277  HelpSystem::ShowHelp(FindWindow(wxID_HELP), mEffect->HelpPage(), wxEmptyString, true, true);
3278  }
3279  else {
3280  // otherwise use the NEW ShowHelp
3281  HelpSystem::ShowHelp(FindWindow(wxID_HELP), mEffect->ManualPage(), true);
3282  }
3283 }
3284 
3285 void EffectUIHost::OnDebug(wxCommandEvent & evt)
3286 {
3287  OnApply(evt);
3288  mEffect->mUIResultID = evt.GetId();
3289 }
3290 
3291 void EffectUIHost::OnMenu(wxCommandEvent & WXUNUSED(evt))
3292 {
3293  wxMenu menu;
3294 
3295  LoadUserPresets();
3296 
3297  if (mUserPresets.GetCount() == 0)
3298  {
3299  menu.Append(kUserPresetsDummyID, _("User Presets"))->Enable(false);
3300  }
3301  else
3302  {
3303  auto sub = std::make_unique<wxMenu>();
3304  for (size_t i = 0, cnt = mUserPresets.GetCount(); i < cnt; i++)
3305  {
3306  sub->Append(kUserPresetsID + i, mUserPresets[i]);
3307  }
3308  menu.Append(0, _("User Presets"), sub.release());
3309  }
3310 
3311  menu.Append(kSaveAsID, _("Save Preset..."));
3312 
3313  if (mUserPresets.GetCount() == 0)
3314  {
3315  menu.Append(kDeletePresetDummyID, _("Delete Preset"))->Enable(false);
3316  }
3317  else
3318  {
3319  auto sub = std::make_unique<wxMenu>();
3320  for (size_t i = 0, cnt = mUserPresets.GetCount(); i < cnt; i++)
3321  {
3322  sub->Append(kDeletePresetID + i, mUserPresets[i]);
3323  }
3324  menu.Append(0, _("Delete Preset"), sub.release());
3325  }
3326 
3327  menu.AppendSeparator();
3328 
3329  wxArrayString factory = mEffect->GetFactoryPresets();
3330 
3331  {
3332  auto sub = std::make_unique<wxMenu>();
3333  sub->Append(kDefaultsID, _("Defaults"));
3334  if (factory.GetCount() > 0)
3335  {
3336  sub->AppendSeparator();
3337  for (size_t i = 0, cnt = factory.GetCount(); i < cnt; i++)
3338  {
3339  wxString label = factory[i];
3340  if (label.IsEmpty())
3341  {
3342  label = _("None");
3343  }
3344 
3345  sub->Append(kFactoryPresetsID + i, label);
3346  }
3347  }
3348  menu.Append(0, _("Factory Presets"), sub.release());
3349  }
3350 
3351  menu.AppendSeparator();
3352  menu.Append(kImportID, _("Import..."))->Enable(mClient->CanExportPresets());
3353  menu.Append(kExportID, _("Export..."))->Enable(mClient->CanExportPresets());
3354  menu.AppendSeparator();
3355  menu.Append(kOptionsID, _("Options..."))->Enable(mClient->HasOptions());
3356  menu.AppendSeparator();
3357 
3358  {
3359  auto sub = std::make_unique<wxMenu>();
3360 
3361  auto type = mEffect->GetFamily();
3362  // PRL: 2.2.2 hack to change the visible name without breaking
3363  // compatibility of pluginsettings.cfg; redo this better
3364  // See also PluginDescriptor::GetTranslatedEffectFamily
3365  if (type == wxT("Audacity"))
3366  type = XO("Built-in");
3367  // And now, also, translate this (what 2.2.1 neglected)
3368  type = wxGetTranslation(type);
3369 
3370  sub->Append(kDummyID, wxString::Format(_("Type: %s"), type));
3371  sub->Append(kDummyID, wxString::Format(_("Name: %s"), mEffect->GetTranslatedName()));
3372  sub->Append(kDummyID, wxString::Format(_("Version: %s"), mEffect->GetVersion()));
3373  sub->Append(kDummyID, wxString::Format(_("Vendor: %s"), mEffect->GetVendor()));
3374  sub->Append(kDummyID, wxString::Format(_("Description: %s"), mEffect->GetDescription()));
3375 
3376  menu.Append(0, _("About"), sub.release());
3377  }
3378 
3379  wxWindow *btn = FindWindow(kMenuID);
3380  wxRect r = btn->GetRect();
3381  btn->PopupMenu(&menu, r.GetLeft(), r.GetBottom());
3382 }
3383 
3385 {
3386  if (!mClient->ValidateUI()) {
3387  // If we're previewing we should still be able to stop playback
3388  // so don't disable transport buttons.
3389  // mEffect->EnableApply(false); // currently this would also disable transport buttons.
3390  // The preferred behaviour is currently undecided, so for now
3391  // just disallow enabling until settings are valid.
3392  mEnabled = false;
3393  mEnableCb->SetValue(mEnabled);
3394  return;
3395  }
3396  mEffect->RealtimeResume();
3397 }
3398 
3399 void EffectUIHost::OnEnable(wxCommandEvent & WXUNUSED(evt))
3400 {
3401  mEnabled = mEnableCb->GetValue();
3402 
3403  if (mEnabled) {
3404  Resume();
3405  mNeedsResume = false;
3406  }
3407  else
3408  {
3409  mEffect->RealtimeSuspend();
3410  mNeedsResume = true;
3411  }
3412 
3413  UpdateControls();
3414 }
3415 
3416 void EffectUIHost::OnPlay(wxCommandEvent & WXUNUSED(evt))
3417 {
3418  if (!mSupportsRealtime)
3419  {
3420  if (!mClient->ValidateUI() || !mEffect->TransferDataFromWindow())
3421  {
3422  return;
3423  }
3424 
3425  mEffect->Preview(false);
3426 
3427  return;
3428  }
3429 
3430  if (mPlaying)
3431  {
3432  mPlayPos = gAudioIO->GetStreamTime();
3433  mProject->GetControlToolBar()->StopPlaying();
3434  }
3435  else
3436  {
3437  if (mProject->IsPlayRegionLocked())
3438  {
3439  double t0, t1;
3440  mProject->GetPlayRegion(&t0, &t1);
3441  mRegion.setTimes(t0, t1);
3442  mPlayPos = mRegion.t0();
3443  }
3444  else if (mProject->mViewInfo.selectedRegion.t0() != mRegion.t0() ||
3445  mProject->mViewInfo.selectedRegion.t1() != mRegion.t1())
3446  {
3447  mRegion = mProject->mViewInfo.selectedRegion;
3448  mPlayPos = mRegion.t0();
3449  }
3450 
3451  if (mPlayPos > mRegion.t1())
3452  {
3453  mPlayPos = mRegion.t1();
3454  }
3455 
3456  mProject->GetControlToolBar()->PlayPlayRegion
3457  (SelectedRegion(mPlayPos, mRegion.t1()),
3458  mProject->GetDefaultPlayOptions(), PlayMode::normalPlay);
3459  }
3460 }
3461 
3462 void EffectUIHost::OnRewind(wxCommandEvent & WXUNUSED(evt))
3463 {
3464  if (mPlaying)
3465  {
3466  double seek;
3467  gPrefs->Read(wxT("/AudioIO/SeekShortPeriod"), &seek, 1.0);
3468 
3469  double pos = gAudioIO->GetStreamTime();
3470  if (pos - seek < mRegion.t0())
3471  {
3472  seek = pos - mRegion.t0();
3473  }
3474 
3475  gAudioIO->SeekStream(-seek);
3476  }
3477  else
3478  {
3479  mPlayPos = mRegion.t0();
3480  }
3481 }
3482 
3483 void EffectUIHost::OnFFwd(wxCommandEvent & WXUNUSED(evt))
3484 {
3485  if (mPlaying)
3486  {
3487  double seek;
3488  gPrefs->Read(wxT("/AudioIO/SeekShortPeriod"), &seek, 1.0);
3489 
3490  double pos = gAudioIO->GetStreamTime();
3491  if (mRegion.t0() < mRegion.t1() && pos + seek > mRegion.t1())
3492  {
3493  seek = mRegion.t1() - pos;
3494  }
3495 
3496  gAudioIO->SeekStream(seek);
3497  }
3498  else
3499  {
3500  // It allows to play past end of selection...probably useless
3501  mPlayPos = mRegion.t1();
3502  }
3503 }
3504 
3505 void EffectUIHost::OnPlayback(wxCommandEvent & evt)
3506 {
3507  evt.Skip();
3508 
3509  if (evt.GetInt() != 0)
3510  {
3511  if (evt.GetEventObject() != mProject)
3512  {
3513  mDisableTransport = true;
3514  }
3515  else
3516  {
3517  mPlaying = true;
3518  }
3519  }
3520  else
3521  {
3522  mDisableTransport = false;
3523  mPlaying = false;
3524  }
3525 
3526  if (mPlaying)
3527  {
3528  mRegion = mProject->mViewInfo.selectedRegion;
3529  mPlayPos = mRegion.t0();
3530  }
3531 
3532  UpdateControls();
3533 }
3534 
3535 void EffectUIHost::OnCapture(wxCommandEvent & evt)
3536 {
3537  evt.Skip();
3538 
3539  if (evt.GetInt() != 0)
3540  {
3541  if (evt.GetEventObject() != mProject)
3542  {
3543  mDisableTransport = true;
3544  }
3545  else
3546  {
3547  mCapturing = true;
3548  }
3549  }
3550  else
3551  {
3552  mDisableTransport = false;
3553  mCapturing = false;
3554  }
3555 
3556  UpdateControls();
3557 }
3558 
3559 void EffectUIHost::OnUserPreset(wxCommandEvent & evt)
3560 {
3561  int preset = evt.GetId() - kUserPresetsID;
3562 
3563  mEffect->LoadUserPreset(mEffect->GetUserPresetsGroup(mUserPresets[preset]));
3564 
3565  return;
3566 }
3567 
3568 void EffectUIHost::OnFactoryPreset(wxCommandEvent & evt)
3569 {
3570  mEffect->LoadFactoryPreset(evt.GetId() - kFactoryPresetsID);
3571 
3572  return;
3573 }
3574 
3575 void EffectUIHost::OnDeletePreset(wxCommandEvent & evt)
3576 {
3577  wxString preset = mUserPresets[evt.GetId() - kDeletePresetID];
3578 
3579  int res = AudacityMessageBox(wxString::Format(_("Are you sure you want to delete \"%s\"?"), preset),
3580  _("Delete Preset"),
3581  wxICON_QUESTION | wxYES_NO);
3582  if (res == wxYES)
3583  {
3584  mEffect->RemovePrivateConfigSubgroup(mEffect->GetUserPresetsGroup(preset));
3585  }
3586 
3587  LoadUserPresets();
3588 
3589  return;
3590 }
3591 
3592 void EffectUIHost::OnSaveAs(wxCommandEvent & WXUNUSED(evt))
3593 {
3594  wxTextCtrl *text;
3595  wxString name;
3596  wxDialogWrapper dlg(this, wxID_ANY, wxString(_("Save Preset")));
3597 
3598  ShuttleGui S(&dlg, eIsCreating);
3599 
3600  S.StartPanel();
3601  {
3602  S.StartVerticalLay(1);
3603  {
3604  S.StartHorizontalLay(wxALIGN_LEFT, 0);
3605  {
3606  text = S.AddTextBox(_("Preset name:"), name, 30);
3607  }
3608  S.EndHorizontalLay();
3609  S.SetBorder(10);
3610  S.AddStandardButtons();
3611  }
3612  S.EndVerticalLay();
3613  }
3614  S.EndPanel();
3615 
3616  dlg.SetSize(dlg.GetSizer()->GetMinSize());
3617  dlg.Center();
3618 
3619  while (true)
3620  {
3621  int rc = dlg.ShowModal();
3622 
3623  if (rc != wxID_OK)
3624  {
3625  break;
3626  }
3627 
3628  name = text->GetValue();
3629  if (name.IsEmpty())
3630  {
3631  AudacityMessageDialog md(this,
3632  _("You must specify a name"),
3633  _("Save Preset"));
3634  md.Center();
3635  md.ShowModal();
3636  continue;
3637  }
3638 
3639  if (mUserPresets.Index(name) != wxNOT_FOUND)
3640  {
3641  AudacityMessageDialog md(this,
3642  _("Preset already exists.\n\nReplace?"),
3643  _("Save Preset"),
3644  wxYES_NO | wxCANCEL | wxICON_EXCLAMATION);
3645  md.Center();
3646  int choice = md.ShowModal();
3647  if (choice == wxID_CANCEL)
3648  {
3649  break;
3650  }
3651 
3652  if (choice == wxID_NO)
3653  {
3654  continue;
3655  }
3656  }
3657 
3658  mEffect->SaveUserPreset(mEffect->GetUserPresetsGroup(name));
3659  LoadUserPresets();
3660 
3661  break;
3662  }
3663 
3664  return;
3665 }
3666 
3667 void EffectUIHost::OnImport(wxCommandEvent & WXUNUSED(evt))
3668 {
3669  mClient->ImportPresets();
3670 
3671  LoadUserPresets();
3672 
3673  return;
3674 }
3675 
3676 void EffectUIHost::OnExport(wxCommandEvent & WXUNUSED(evt))
3677 {
3678  // may throw
3679  // exceptions are handled in AudacityApp::OnExceptionInMainLoop
3680  mClient->ExportPresets();
3681 
3682  return;
3683 }
3684 
3685 void EffectUIHost::OnOptions(wxCommandEvent & WXUNUSED(evt))
3686 {
3687  mClient->ShowOptions();
3688 
3689  return;
3690 }
3691 
3692 void EffectUIHost::OnDefaults(wxCommandEvent & WXUNUSED(evt))
3693 {
3694  mEffect->LoadFactoryDefaults();
3695 
3696  return;
3697 }
3698 
3699 wxBitmap EffectUIHost::CreateBitmap(const char *xpm[], bool up, bool pusher)
3700 {
3701  wxMemoryDC dc;
3702  wxBitmap pic(xpm);
3703 
3704  wxBitmap mod(pic.GetWidth() + 6, pic.GetHeight() + 6);
3705  dc.SelectObject(mod);
3706 
3707 #if !defined(__WXMAC__)
3708 
3709 #if defined(__WXGTK__)
3710  wxColour newColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BACKGROUND);
3711 #elif defined(__WXMSW__)
3712  wxColour newColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
3713 #endif
3714 
3715  dc.SetBackground(wxBrush(newColour));
3716  dc.Clear();
3717 #endif
3718 
3719  int offset = 3;
3720  if (pusher)
3721  {
3722  if (!up)
3723  {
3724  offset += 1;
3725  }
3726  }
3727 
3728  dc.DrawBitmap(pic, offset, offset, true);
3729 
3730  dc.SelectObject(wxNullBitmap);
3731 
3732  return mod;
3733 }
3734 
3736 {
3737  if (mIsBatch)
3738  {
3739  return;
3740  }
3741 
3742  if (mCapturing || mDisableTransport)
3743  {
3744  // Don't allow focus to get trapped
3745  wxWindow *focus = FindFocus();
3746  if (focus == mRewindBtn || focus == mFFwdBtn || focus == mPlayBtn || focus == mEnableCb)
3747  {
3748  mCloseBtn->SetFocus();
3749  }
3750  }
3751 
3752  mApplyBtn->Enable(!mCapturing);
3753  if (mEffect->GetType() != EffectTypeAnalyze)
3754  {
3755  (!mIsGUI ? mPlayToggleBtn : mPlayBtn)->Enable(!(mCapturing || mDisableTransport));
3756  }
3757 
3758  if (mSupportsRealtime)
3759  {
3760  mRewindBtn->Enable(!(mCapturing || mDisableTransport));
3761  mFFwdBtn->Enable(!(mCapturing || mDisableTransport));
3762  mEnableCb->Enable(!(mCapturing || mDisableTransport));
3763 
3764  wxBitmapButton *bb;
3765 
3766  if (mPlaying)
3767  {
3768  if (!mIsGUI)
3769  {
3770  /* i18n-hint: The access key "&P" should be the same in
3771  "Stop &Playback" and "Start &Playback" */
3772  mPlayToggleBtn->SetLabel(_("Stop &Playback"));
3773  mPlayToggleBtn->Refresh();
3774  }
3775  else
3776  {
3777  bb = (wxBitmapButton *) mPlayBtn;
3778  bb->SetBitmapLabel(mStopBM);
3779  bb->SetBitmapDisabled(mStopDisabledBM);
3780  bb->SetToolTip(_("Stop"));
3781 #if defined(__WXMAC__)
3782  bb->SetName(_("Stop &Playback"));
3783 #else
3784  bb->SetLabel(_("Stop &Playback"));
3785 #endif
3786  }
3787  }
3788  else
3789  {
3790  if (!mIsGUI)
3791  {
3792  /* i18n-hint: The access key "&P" should be the same in
3793  "Stop &Playback" and "Start &Playback" */
3794  mPlayToggleBtn->SetLabel(_("Start &Playback"));
3795  mPlayToggleBtn->Refresh();
3796  }
3797  else
3798  {
3799  bb = (wxBitmapButton *) mPlayBtn;
3800  bb->SetBitmapLabel(mPlayBM);
3801  bb->SetBitmapDisabled(mPlayDisabledBM);
3802  bb->SetToolTip(_("Play"));
3803 #if defined(__WXMAC__)
3804  bb->SetName(_("Start &Playback"));
3805 #else
3806  bb->SetLabel(_("Start &Playback"));
3807 #endif
3808  }
3809  }
3810  }
3811 }
3812 
3814 {
3815  mUserPresets.Clear();
3816 
3817  mEffect->GetPrivateConfigSubgroups(mEffect->GetUserPresetsGroup(wxEmptyString), mUserPresets);
3818 
3819  mUserPresets.Sort();
3820 
3821  return;
3822 }
3823 
3825 {
3826  if (mSupportsRealtime && !mInitialized)
3827  {
3829 
3830  wxTheApp->Connect(EVT_AUDIOIO_PLAYBACK,
3831  wxCommandEventHandler(EffectUIHost::OnPlayback),
3832  NULL,
3833  this);
3834 
3835  wxTheApp->Connect(EVT_AUDIOIO_CAPTURE,
3836  wxCommandEventHandler(EffectUIHost::OnCapture),
3837  NULL,
3838  this);
3839 
3840  mInitialized = true;
3841  }
3842 }
3843 
3845 {
3846  if (mSupportsRealtime && mInitialized)
3847  {
3848  wxTheApp->Disconnect(EVT_AUDIOIO_PLAYBACK,
3849  wxCommandEventHandler(EffectUIHost::OnPlayback),
3850  NULL,
3851  this);
3852 
3853  wxTheApp->Disconnect(EVT_AUDIOIO_CAPTURE,
3854  wxCommandEventHandler(EffectUIHost::OnCapture),
3855  NULL,
3856  this);
3857 
3859 
3860  mInitialized = false;
3861  }
3862 }
3863 
3865 //
3866 // EffectPresetsDialog
3867 //
3869 
3870 enum
3871 {
3872  ID_Type = 10000
3873 };
3874 
3875 BEGIN_EVENT_TABLE(EffectPresetsDialog, wxDialogWrapper)
3876  EVT_CHOICE(ID_Type, EffectPresetsDialog::OnType)
3877  EVT_LISTBOX_DCLICK(wxID_ANY, EffectPresetsDialog::OnOk)
3878  EVT_BUTTON(wxID_OK, EffectPresetsDialog::OnOk)
3879  EVT_BUTTON(wxID_CANCEL, EffectPresetsDialog::OnCancel)
3881 
3883 : wxDialogWrapper(parent, wxID_ANY, wxString(_("Select Preset")))
3884 {
3885  ShuttleGui S(this, eIsCreating);
3886  S.StartVerticalLay();
3887  {
3888  S.StartTwoColumn();
3889  S.SetStretchyCol(1);
3890  {
3891  wxArrayString empty;
3892 
3893  S.AddPrompt(_("Type:"));
3894  mType = S.Id(ID_Type).AddChoice( {}, wxT(""), &empty);
3895  mType->SetSelection(0);
3896 
3897  S.AddPrompt(_("&Preset:"));
3898  mPresets = S.AddListBox(&empty, wxLB_SINGLE | wxLB_NEEDED_SB );
3899  }
3900  S.EndTwoColumn();
3901 
3902  S.AddStandardButtons();
3903  }
3904  S.EndVerticalLay();
3905 
3906  mUserPresets = effect->GetUserPresets();
3907  mFactoryPresets = effect->GetFactoryPresets();
3908 
3909  if (mUserPresets.GetCount() > 0)
3910  {
3911  mType->Append(_("User Presets"));
3912  }
3913 
3914  if (mFactoryPresets.GetCount() > 0)
3915  {
3916  mType->Append(_("Factory Presets"));
3917  }
3918 
3919  if (effect->HasCurrentSettings())
3920  {
3921  mType->Append(_("Current Settings"));
3922  }
3923 
3924  if (effect->HasFactoryDefaults())
3925  {
3926  mType->Append(_("Factory Defaults"));
3927  }
3928 
3929  UpdateUI();
3930 }
3931 
3933 {
3934 }
3935 
3937 {
3938  return mSelection;
3939 }
3940 
3941 void EffectPresetsDialog::SetSelected(const wxString & parms)
3942 {
3943  wxString preset = parms;
3944  if (preset.StartsWith(Effect::kUserPresetIdent))
3945  {
3946  preset.Replace(Effect::kUserPresetIdent, wxEmptyString, false);
3947  SetPrefix(_("User Presets"), preset);
3948  }
3949  else if (preset.StartsWith(Effect::kFactoryPresetIdent))
3950  {
3951  preset.Replace(Effect::kFactoryPresetIdent, wxEmptyString, false);
3952  SetPrefix(_("Factory Presets"), preset);
3953  }
3954  else if (preset.StartsWith(Effect::kCurrentSettingsIdent))
3955  {
3956  SetPrefix(_("Current Settings"), wxEmptyString);
3957  }
3958  else if (preset.StartsWith(Effect::kFactoryDefaultsIdent))
3959  {
3960  SetPrefix(_("Factory Defaults"), wxEmptyString);
3961  }
3962 }
3963 
3964 void EffectPresetsDialog::SetPrefix(const wxString & type, const wxString & prefix)
3965 {
3966  mType->SetStringSelection(type);
3967 
3968  if (type.IsSameAs(_("User Presets")))
3969  {
3970  mPresets->Clear();
3971  mPresets->Append(mUserPresets);
3972  mPresets->Enable(true);
3973  mPresets->SetStringSelection(prefix);
3974  if (mPresets->GetSelection() == wxNOT_FOUND)
3975  {
3976  mPresets->SetSelection(0);
3977  }
3978  mSelection = Effect::kUserPresetIdent + mPresets->GetStringSelection();
3979  }
3980  else if (type.IsSameAs(_("Factory Presets")))
3981  {
3982  mPresets->Clear();
3983  for (size_t i = 0, cnt = mFactoryPresets.GetCount(); i < cnt; i++)
3984  {
3985  wxString label = mFactoryPresets[i];
3986  if (label.IsEmpty())
3987  {
3988  label = _("None");
3989  }
3990  mPresets->Append(label);
3991  }
3992  mPresets->Enable(true);
3993  mPresets->SetStringSelection(prefix);
3994  if (mPresets->GetSelection() == wxNOT_FOUND)
3995  {
3996  mPresets->SetSelection(0);
3997  }
3998  mSelection = Effect::kFactoryPresetIdent + mPresets->GetStringSelection();
3999  }
4000  else if (type.IsSameAs(_("Current Settings")))
4001  {
4002  mPresets->Clear();
4003  mPresets->Enable(false);
4004  mSelection = Effect::kCurrentSettingsIdent;
4005  }
4006  else if (type.IsSameAs(_("Factory Defaults")))
4007  {
4008  mPresets->Clear();
4009  mPresets->Enable(false);
4010  mSelection = Effect::kFactoryDefaultsIdent;
4011  }
4012 }
4013 
4015 {
4016  int selected = mType->GetSelection();
4017  if (selected == wxNOT_FOUND)
4018  {
4019  selected = 0;
4020  mType->SetSelection(selected);
4021  }
4022  wxString type = mType->GetString(selected);
4023 
4024  if (type.IsSameAs(_("User Presets")))
4025  {
4026  selected = mPresets->GetSelection();
4027  if (selected == wxNOT_FOUND)
4028  {
4029  selected = 0;
4030  }
4031 
4032  mPresets->Clear();
4033  mPresets->Append(mUserPresets);
4034  mPresets->Enable(true);
4035  mPresets->SetSelection(selected);
4036  mSelection = Effect::kUserPresetIdent + mPresets->GetString(selected);
4037  }
4038  else if (type.IsSameAs(_("Factory Presets")))
4039  {
4040  selected = mPresets->GetSelection();
4041  if (selected == wxNOT_FOUND)
4042  {
4043  selected = 0;
4044  }
4045 
4046  mPresets->Clear();
4047  for (size_t i = 0, cnt = mFactoryPresets.GetCount(); i < cnt; i++)
4048  {
4049  wxString label = mFactoryPresets[i];
4050  if (label.IsEmpty())
4051  {
4052  label = _("None");
4053  }
4054  mPresets->Append(label);
4055  }
4056  mPresets->Enable(true);
4057  mPresets->SetSelection(selected);
4058  mSelection = Effect::kFactoryPresetIdent + mPresets->GetString(selected);
4059  }
4060  else if (type.IsSameAs(_("Current Settings")))
4061  {
4062  mPresets->Clear();
4063  mPresets->Enable(false);
4064  mSelection = Effect::kCurrentSettingsIdent;
4065  }
4066  else if (type.IsSameAs(_("Factory Defaults")))
4067  {
4068  mPresets->Clear();
4069  mPresets->Enable(false);
4070  mSelection = Effect::kFactoryDefaultsIdent;
4071  }
4072 }
4073 
4074 void EffectPresetsDialog::OnType(wxCommandEvent & WXUNUSED(evt))
4075 {
4076  UpdateUI();
4077 }
4078 
4079 void EffectPresetsDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
4080 {
4081  UpdateUI();
4082 
4083  EndModal(true);
4084 }
4085 
4086 void EffectPresetsDialog::OnCancel(wxCommandEvent & WXUNUSED(evt))
4087 {
4088  mSelection = wxEmptyString;
4089 
4090  EndModal(false);
4091 }
wxArrayInt mGroupProcessor
Definition: Effect.h:534
wxString GetUserPresetsGroup(const wxString &name) override
Definition: Effect.cpp:803
void OnExport(const wxString &Format)
std::unordered_map< void *, bool > t2bHash
Definition: Effect.cpp:95
void OnDeletePreset(wxCommandEvent &evt)
Definition: Effect.cpp:3575
Effect()
Definition: Effect.cpp:97
static bool IsInstanceCreated()
returns whether or not the singleton instance was created yet
Definition: ODManager.cpp:205
void OnSaveAs(const CommandContext &)
wxString GetSymbol() override
Definition: Effect.cpp:166
std::unique_ptr< wxSizer > CreateStdButtonSizer(wxWindow *parent, long buttons, wxWindow *extra)
double mT1
Definition: Effect.h:460
A list of TrackListNode items.
Definition: Track.h:553
void StopStream()
Stop recording, playback or input monitoring.
Definition: AudioIO.cpp:2521
#define AUDACITY_VERSION_STRING
Definition: Audacity.h:81
void OnCapture(wxCommandEvent &evt)
Definition: Effect.cpp:3535
static ODManager *(* Instance)()
Definition: ODManager.h:49
unsigned GetAudioInCount() override
Definition: Effect.cpp:297
#define BUILTIN_EFFECT_PREFIX
Definition: Effect.h:47
static const int kConfigured
Definition: Project.h:478
std::unique_ptr< LabelTrack > Holder
Definition: LabelTrack.h:163
bool SaveUserPreset(const wxString &name) override
Definition: Effect.cpp:615
void CountWaveTracks()
Definition: Effect.cpp:2249
int MessageBox(const wxString &message, long style=DefaultMessageBoxStyle, const wxString &titleStr=wxString{})
Definition: Effect.cpp:2655
virtual void SetBatchProcessing(bool start)
Definition: Effect.cpp:1137
void SetOffset(double dOffset) override
Definition: LabelTrack.cpp:145
void OnInitDialog(wxInitDialogEvent &evt)
Definition: Effect.cpp:3144
Track * AddToOutputTracks(std::unique_ptr< Track > &&t)
Definition: Effect.cpp:2060
bool TrackProgress(int whichTrack, double frac, const wxString &=wxEmptyString)
Definition: Effect.cpp:1978
double t0() const
virtual bool TransferDataFromWindow()
Definition: Effect.cpp:1874
bool TotalProgress(double frac)
Definition: Effect.cpp:1970
bool GetAutomationParameters(EffectAutomationParameters &parms) override
Definition: Effect.cpp:579
static const int kMenuID
Definition: Effect.cpp:79
static const int kDeletePresetID
Definition: Effect.cpp:87
void UpdateControls()
Definition: Effect.cpp:3735
static PluginID GetID(ModuleInterface *module)
void OnUserPreset(wxCommandEvent &evt)
Definition: Effect.cpp:3559
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
double GetDuration() override
Definition: Effect.cpp:737
root of a hierarchy of classes that are thrown and caught by Audacity.
bool RemoveSharedConfig(const PluginID &ID, const wxString &group, const wxString &key) override
ProgressDialog Class.
bool GetSharedConfigSubgroups(const PluginID &ID, const wxString &group, wxArrayString &subgroups) override
ProgressDialog * mProgress
Definition: Effect.h:452
bool Get(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true) const
Definition: WaveTrack.cpp:1950
double GetStreamTime()
During playback, the (unwarped) track time most recently played.
Definition: AudioIO.cpp:2968
void InitializeRealtime()
Definition: Effect.cpp:3824
void SetPreviewFullSelectionFlag(bool previewDurationFlag)
Definition: Effect.cpp:1959
TrackList * mTracks
Definition: Effect.h:504
bool GetPrivateConfig(const wxString &group, const wxString &key, wxString &value, const wxString &defval=wxEmptyString) override
Definition: Effect.cpp:910
bool SetSharedConfig(const wxString &group, const wxString &key, const wxString &value) override
Definition: Effect.cpp:865
int mPass
Definition: Effect.h:467
wxString GetCurrentSettingsGroup() override
Definition: Effect.cpp:814
void OnRewind(wxCommandEvent &evt)
Definition: Effect.cpp:3462
EffectPanel(wxWindow *parent)
Definition: Effect.cpp:2766
void CopyInputTracks()
Definition: Effect.cpp:2029
bool GetSelected() const
Definition: Track.h:217
bool IsStreamActive()
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2898
virtual ~EffectPresetsDialog()
Definition: Effect.cpp:3932
void SetLinearEffectFlag(bool linearEffectFlag)
Definition: Effect.cpp:1954
int GetMidiInCount() override
Definition: Effect.cpp:317
wxString GetDurationFormat() override
Definition: Effect.cpp:747
bool RealtimeProcessEnd() override
Definition: Effect.cpp:519
size_t SetBlockSize(size_t maxBlockSize) override
Definition: Effect.cpp:347
int mOutputTracksType
Definition: Effect.h:477
bool mPreviewFullSelection
Definition: Effect.h:509
bool AcceptsFocus() const override
Definition: Effect.cpp:2784
void ReplaceWaveTrack(WaveTrack *oldTrack, WaveTrack *newTrack)
replace the wavetrack whose wavecache the gui watches for updates
Definition: ODManager.cpp:384
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:499
bool mAcceptsFocus
Definition: Effect.cpp:2804
virtual bool Init()
Definition: Effect.cpp:1257
virtual bool TransferDataToWindow()
Definition: Effect.cpp:1869
void OnFactoryPreset(wxCommandEvent &evt)
Definition: Effect.cpp:3568
void OnCancel(wxCommandEvent &evt)
Definition: Effect.cpp:4086
bool IsRealtimeActive()
Definition: Effect.cpp:2460
#define QUANTIZED_TIME(time, rate)
Definition: Audacity.h:207
bool RemovePrivateConfigSubgroup(const wxString &group) override
Definition: Effect.cpp:960
virtual PluginID GetID()
Definition: Effect.cpp:972
bool mIsPreview
Definition: Effect.h:515
bool IsSyncLockSelected() const
Definition: Track.cpp:232
wxString GetFamily() override
Definition: Effect.cpp:216
bool IsAvailable(AudacityProject *projecT)
Function to automatically set an acceptable volume.
Definition: AudioIO.cpp:2473
Track * Add(std::unique_ptr< TrackKind > &&t)
Add this Track or all children of this TrackList.
Definition: Track.cpp:843
void ReplaceProcessedTracks(const bool bGoodResult)
Definition: Effect.cpp:2160
EffectClientInterface * mClient
Definition: Effect.h:526
static const int kPlayID
Definition: Effect.cpp:81
unsigned GetNumCaptureChannels() const
Definition: AudioIO.h:373
void Offset(double t)
Definition: Track.h:226
bool HasPrivateConfigGroup(const PluginID &ID, const wxString &group)
bool TransferDataFromWindow() override
Definition: Effect.cpp:2894
virtual void EnableDebug(bool enable=true)
Definition: Effect.cpp:1949
void SetPresetParameters(const wxArrayString *Names, const wxArrayString *Values)
Definition: Effect.h:239
virtual wxString ManualPage()
Definition: Effect.cpp:1122
wxString label
Definition: Tags.cpp:727
size_t RealtimeProcess(int group, float **inbuf, float **outbuf, size_t numSamples) override
Definition: Effect.cpp:506
void Init()
Definition: Effect.cpp:2680
wxString mDurationFormat
Definition: Effect.h:513
wxString GetName() override
Definition: Effect.cpp:176
bool GetLinked() const
Definition: Track.h:218
void ClearAndPaste(double t0, double t1, const Track *src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=NULL)
Definition: WaveTrack.cpp:759
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
Definition: WaveTrack.cpp:599
wxPanel * StartPanel(int iStyle=0)
Definition: ShuttleGui.cpp:789
static const int kCaptureID
Definition: Effect.cpp:85
bool RealtimeSuspend() override
Definition: Effect.cpp:452
bool DoEffect(wxWindow *parent, double projectRate, TrackList *list, TrackFactory *factory, SelectedRegion *selectedRegion, bool shouldPrompt=true)
Definition: Effect.cpp:1151
virtual wxString GetPreset(wxWindow *parent, const wxString &parms)
Definition: Effect.cpp:1105
bool HasPrivateConfigGroup(const wxString &group) override
Definition: Effect.cpp:900
Base class for many of the effects in Audacity.
Definition: Effect.h:62
#define XO(s)
Definition: Internat.h:30
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
virtual bool HasCurrentSettings()
Definition: Effect.cpp:1095
bool RemoveSharedConfig(const wxString &group, const wxString &key) override
Definition: Effect.cpp:895
virtual bool ProcessPass()
Definition: Effect.cpp:1309
New (Jun-2006) base class for effects dialogs. Likely to get greater use in future.
Definition: Effect.h:559
void OnErase(wxEraseEvent &evt)
Definition: Effect.cpp:3167
size_t GetTailSize() override
Definition: Effect.cpp:369
virtual bool Process()
Definition: Effect.cpp:1283
double GetStartTime() const override
virtual void PopulateOrExchange(ShuttleGui &S)
Definition: Effect.cpp:2711
std::shared_ptr< AddedAnalysisTrack > AddAnalysisTrack(const wxString &name=wxString())
Definition: Effect.cpp:2097
static const int kPlaybackID
Definition: Effect.cpp:84
static const int kUserPresetsID
Definition: Effect.cpp:86
bool IsBusy()
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIO.cpp:2890
static const int kFFwdID
Definition: Effect.cpp:83
bool RealtimeProcessStart() override
Definition: Effect.cpp:496
void ShowOptions() override
Definition: Effect.cpp:726
double t1() const
double GetEndTime() const override
bool SetPrivateConfig(const wxString &group, const wxString &key, const wxString &value) override
Definition: Effect.cpp:935
void OnMenu(wxCommandEvent &evt)
Definition: Effect.cpp:3291
void ShowErrorDialog(wxWindow *parent, const wxString &dlogTitle, const wxString &message, const wxString &helpPage, const bool Close)
Displays an error dialog with a button that offers help.
size_t mBufferSize
Definition: Effect.h:530
double mSampleRate
Definition: Effect.h:455
void SetSampleRate(double rate) override
Definition: Effect.cpp:337
bool CanExportPresets() override
Definition: Effect.cpp:708
void OnClose(wxCloseEvent &evt)
Definition: Effect.cpp:3179
virtual ~EffectPanel()
Definition: Effect.cpp:2776
wxString GetDescription() override
Definition: Effect.cpp:206
bool mIsSelection
Definition: Effect.h:511
bool GetSharedConfig(const wxString &group, const wxString &key, wxString &value, const wxString &defval=wxEmptyString) override
Definition: Effect.cpp:840
int GetWaveColorIndex() const
Definition: WaveTrack.h:137
ModifiedAnalysisTrack ModifyAnalysisTrack(const LabelTrack *pOrigTrack, const wxString &name=wxString())
Definition: Effect.cpp:2153
bool LoadUserPreset(const wxString &name) override
Definition: Effect.cpp:599
bool SetSharedConfig(const PluginID &ID, const wxString &group, const wxString &key, const wxString &value) override
#define safenew
Definition: Audacity.h:223
void GetSamples(const WaveTrack *track, sampleCount *start, sampleCount *len)
Definition: Effect.cpp:1994
static const int kUserPresetsDummyID
Definition: Effect.cpp:77
size_t mNumAudioIn
Definition: Effect.h:527
wxCriticalSection mRealtimeSuspendLock
Definition: Effect.h:537
LabelTrack * mpTrack
Definition: Effect.h:397
virtual int GetKind() const
Definition: Track.h:267
static std::shared_ptr< TrackList > Create()
Definition: Track.cpp:733
Used to create a WaveTrack, or a LabelTrack.. Implementation of the functions of this class are dispe...
Definition: Track.h:708
void InsertSilence(double t, double len) override
Definition: WaveTrack.cpp:1364
double mF0
Definition: Effect.h:462
void EndHorizontalLay()
Definition: ShuttleGui.cpp:975
Track * Next(bool skiplinked=false) override
Definition: Track.cpp:513
size_t mNumAudioOut
Definition: Effect.h:528
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:114
double f0() const
virtual bool HasFactoryDefaults()
Definition: Effect.cpp:1100
void AddPrompt(const wxString &Prompt)
Right aligned text string.
Definition: ShuttleGui.cpp:215
void OnCancel(wxCommandEvent &evt)
Definition: Effect.cpp:3266
void Preview() override
Definition: Effect.cpp:784
int GetMidiOutCount() override
Definition: Effect.cpp:327
static const int kRewindID
Definition: Effect.cpp:82
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper, LinearInputRateSlideTimeWarper, LinearOutputRateSlideTimeWarper, LinearInputInverseRateTimeWarper, GeometricInputRateTimeWarper, GeometricOutputRateTimeWarper classes.
bool GetPrivateConfigSubgroups(const wxString &group, wxArrayString &subgroups) override
Definition: Effect.cpp:905
bool HasSharedConfigGroup(const wxString &group) override
Definition: Effect.cpp:830
bool SetHost(EffectHostInterface *host) override
Definition: Effect.cpp:287
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:161
wxString GetSelected() const
Definition: Effect.cpp:3936
void EndVerticalLay()
Definition: ShuttleGui.cpp:991
void OnFFwd(wxCommandEvent &evt)
Definition: Effect.cpp:3483
void SetPrefix(const wxString &type, const wxString &prefix)
Definition: Effect.cpp:3964
bool IsGraphicalUI() override
Definition: Effect.cpp:682
bool HasSharedConfigGroup(const PluginID &ID, const wxString &group)
static const int kDummyID
Definition: Effect.cpp:71
static const int kDeletePresetDummyID
Definition: Effect.cpp:78
virtual bool InitPass2()
Definition: Effect.cpp:1278
EffectType GetType() override
Definition: Effect.cpp:146
wxFileConfig * gPrefs
Definition: Prefs.cpp:72
wxTextCtrl * AddTextBox(const wxString &Caption, const wxString &Value, const int nChars)
Definition: ShuttleGui.cpp:493
std::vector< Track * > mOMap
Definition: Effect.h:520
bool IsReady() override
Definition: Effect.cpp:379
bool TransferDataFromWindow() override
Definition: Effect.cpp:2724
wxString GetVersion() override
Definition: Effect.cpp:196
void OnHelp(wxCommandEvent &evt)
Definition: Effect.cpp:3272
void OnPaint(wxPaintEvent &evt)
Definition: Effect.cpp:3172
std::unique_ptr< WaveTrack > Holder
Definition: WaveTrack.h:84
wxArrayString GetFactoryPresets() override
Definition: Effect.cpp:631
void SetSelected(const wxString &parms)
Definition: Effect.cpp:3941
Defines a selected portion of a project.
bool ProcessInitialize(sampleCount totalLen, ChannelNames chanMap=NULL) override
Definition: Effect.cpp:389
void OnPlayback(wxCommandEvent &evt)
Definition: Effect.cpp:3505
void Set(samplePtr buffer, sampleFormat format, sampleCount start, size_t len)
Definition: WaveTrack.cpp:2027
void StartTwoColumn()
Definition: ShuttleGui.h:125
void ExportPresets() override
Definition: Effect.cpp:713
virtual wxString GetSelectionFormat()
Definition: Effect.cpp:752
void DoCancel()
Definition: Effect.cpp:3252
static const int kExportID
Definition: Effect.cpp:74
bool TransferDataToWindow() override
Definition: Effect.cpp:2889
bool SetPrivateConfig(const PluginID &ID, const wxString &group, const wxString &key, const wxString &value) override
std::vector< std::shared_ptr< WaveTrack > > WaveTrackArray
Definition: AudioIO.h:64
void OnOk(wxCommandEvent &evt)
Definition: Effect.cpp:4079
bool ValidateUI() override
Definition: Effect.cpp:687
static const wxString kUserPresetIdent
Definition: Effect.h:540
struct holding stream options, including a pointer to the TimeTrack and AudioIOListener and whether t...
Definition: AudioIO.h:110
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:966
size_t mBlockSize
Definition: Effect.h:531
virtual bool InitPass1()
Definition: Effect.cpp:1273
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:65
virtual void End()
Definition: Effect.cpp:1860
wxChoice * AddChoice(const wxString &Prompt, const wxString &Selected, const wxArrayString *pChoices)
Definition: ShuttleGui.cpp:331
int mNumTracks
Definition: Effect.h:522
static const int kImportID
Definition: Effect.cpp:73
ListOfTracks::value_type Replace(Track *t, ListOfTracks::value_type &&with)
Replace first track with second track, give back a holder.
Definition: Track.cpp:895
bool RealtimeFinalize() override
Definition: Effect.cpp:442
void OnApply(wxCommandEvent &evt)
Definition: Effect.cpp:3195
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
ShuttleGui & Id(int id)
bool ProcessFinalize() override
Definition: Effect.cpp:399
void OnOptions(wxCommandEvent &evt)
Definition: Effect.cpp:3685
wxString GetVendor() override
Definition: Effect.cpp:186
virtual double CalcPreviewInputLength(double previewLength)
Definition: Effect.cpp:2272
bool Delegate(Effect &delegate, wxWindow *parent, SelectedRegion *selectedRegion, bool shouldPrompt)
Definition: Effect.cpp:1249
bool PopulateUI(wxWindow *parent) override
Definition: Effect.cpp:667
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:67
ProgressResult Update(int value, const wxString &message=wxEmptyString)
void RealtimeRemoveEffect(Effect *effect)
bool RealtimeAddProcessor(unsigned numChannels, float sampleRate) override
Definition: Effect.cpp:432
void CleanupRealtime()
Definition: Effect.cpp:3844
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
void LoadUserPresets()
Definition: Effect.cpp:3813
void OnImport(const CommandContext &)
bool mIsLinearEffect
Definition: Effect.h:507
void OnEnable(wxCommandEvent &evt)
Definition: Effect.cpp:3399
int mRealtimeSuspendCount
Definition: Effect.h:538
bool RemoveSharedConfigSubgroup(const PluginID &ID, const wxString &group) override
std::vector< Track * > mIMap
Definition: Effect.h:519
static void ShowHelp(wxWindow *parent, const wxString &localFileName, const wxString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:201
int min(int a, int b)
bool IsLegacy() override
Definition: Effect.cpp:255
static const int kDefaultsID
Definition: Effect.cpp:75
void SetDuration(double duration) override
Definition: Effect.cpp:757
void OnExport(wxCommandEvent &evt)
Definition: Effect.cpp:3676
double GetDefaultDuration() override
Definition: Effect.cpp:732
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), const F3 &delayedHandler={})
void IncludeNotSelectedPreviewTracks(bool includeNotSelected)
Definition: Effect.cpp:1965
void OnImport(wxCommandEvent &evt)
Definition: Effect.cpp:3667
void ImportPresets() override
Definition: Effect.cpp:717
bool mPreviewWithNotSelected
Definition: Effect.h:508
#define NYQUISTEFFECTS_FAMILY
Definition: Nyquist.h:31
size_t GetMaxBlockSize() const
Definition: WaveTrack.cpp:1604
std::vector< std::shared_ptr< NoteTrack > > NoteTrackArray
Definition: Track.h:53
wxBitmap CreateBitmap(const char *xpm[], bool up, bool pusher)
Definition: Effect.cpp:3699
static EffectManager & Get()
static const int kFactoryPresetsID
Definition: Effect.cpp:88
void SetAccept(bool accept)
Definition: Effect.cpp:2798
bool RealtimeInitialize() override
Definition: Effect.cpp:419
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
bool IsInteractive() override
Definition: Effect.cpp:235
bool RemovePrivateConfig(const wxString &group, const wxString &key) override
Definition: Effect.cpp:965
int StartStream(const WaveTrackConstArray &playbackTracks, const WaveTrackArray &captureTracks, double t0, double t1, const AudioIOStartStreamOptions &options)
Start recording or playing back audio.
Definition: AudioIO.cpp:1861
void OnDebug(wxCommandEvent &evt)
Definition: Effect.cpp:3285
void OnPlay(wxCommandEvent &evt)
Definition: Effect.cpp:3416
virtual ~Effect()
Definition: Effect.cpp:136
bool DoEffect(const PluginID &ID, int flags)
Definition: Menus.cpp:4328
std::unique_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:78
wxWindow * mUIParent
Definition: Effect.h:471
bool LoadFactoryPreset(int id) override
Definition: Effect.cpp:641
An iterator for a TrackList.
Definition: Track.h:339
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
bool GetSharedConfigSubgroups(const wxString &group, wxArrayString &subgroups) override
Definition: Effect.cpp:835
bool Apply() override
Definition: Effect.cpp:776
bool RealtimeResume() override
Definition: Effect.cpp:474
double mProjectRate
Definition: Effect.h:453
bool setTimes(double t0, double t1)
TrackNodePointer Remove(Track *t)
Definition: Track.cpp:916
unsigned mNumChannels
Definition: Effect.h:532
TrackFactory * mFactory
Definition: Effect.h:456
ValueRestorer< T > valueRestorer(T &var)
Definition: MemoryX.h:875
bool IsDefault() override
Definition: Effect.cpp:245
AudioIO * gAudioIO
Definition: AudioIO.cpp:481
virtual bool IsHidden()
Definition: Effect.cpp:2465
bool ProcessTrack(int count, ChannelNames map, WaveTrack *left, WaveTrack *right, sampleCount leftStart, sampleCount rightStart, sampleCount len, FloatBuffers &inBuffer, FloatBuffers &outBuffer, ArrayOf< float * > &inBufPos, ArrayOf< float * > &outBufPos)
Definition: Effect.cpp:1479
sampleCount GetLatency() override
Definition: Effect.cpp:359
wxDialog * mUIDialog
Definition: Effect.h:470
bool mUIDebug
Definition: Effect.h:517
void SetName(const wxString &n)
Definition: Track.h:213
int mCurrentProcessor
Definition: Effect.h:535
static const int kEnableID
Definition: Effect.cpp:80
void MixAndRender(TrackList *tracks, TrackFactory *trackFactory, double rate, sampleFormat format, double startTime, double endTime, WaveTrack::Holder &uLeft, WaveTrack::Holder &uRight)
Mixes together all input tracks, applying any envelopes, amplitude gain, panning, and real-time effec...
Definition: Mix.cpp:44
void reinit(Integral count)
Definition: MemoryX.h:547
const wxChar * name
Definition: Distortion.cpp:94
bool Validate() override
Definition: Effect.cpp:2732
wxListBox * AddListBox(const wxArrayString *pChoices, long style=0)
Definition: ShuttleGui.cpp:584
int ShowModal() override
Definition: Effect.cpp:2903
static const int kSaveAsID
Definition: Effect.cpp:72
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: WaveTrack.cpp:1822
bool SetAutomationParameters(EffectAutomationParameters &parms) override
Definition: Effect.cpp:589
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:302
bool TransferDataToWindow() override
Definition: Effect.cpp:2716
bool ShowInterface(wxWindow *parent, bool forceModal=false) override
Definition: Effect.cpp:529
sampleFormat GetSampleFormat() const
Definition: WaveTrack.h:140
bool RemovePrivateConfigSubgroup(const PluginID &ID, const wxString &group) override
Memory.h template class for making an array of float, bool, etc.
Definition: MemoryX.h:469
const wxString & GetSelectionFormat() const
Definition: Project.cpp:1661
bool LoadFactoryDefaults() override
Definition: Effect.cpp:651
virtual int GetPass()
Definition: Effect.cpp:1268
static const wxString kFactoryPresetIdent
Definition: Effect.h:541
bool RemoveSharedConfigSubgroup(const wxString &group) override
Definition: Effect.cpp:890
bool GetPrivateConfigSubgroups(const PluginID &ID, const wxString &group, wxArrayString &subgroups) override
Track * First(TrackList *val=NULL) override
Definition: Track.cpp:502
bool SupportsAutomation() override
Definition: Effect.cpp:275
static const wxString kCurrentSettingsIdent
Definition: Effect.h:542
wxDialog * CreateUI(wxWindow *parent, EffectUIClientInterface *client) override
Definition: Effect.cpp:789
bool SupportsRealtime() override
Definition: Effect.cpp:265
double GetEndTime() const
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:1852
bool TrackGroupProgress(int whichGroup, double frac, const wxString &=wxEmptyString)
Definition: Effect.cpp:1986
double f1() const
double mDuration
Definition: Effect.h:512
virtual bool IsBatchProcessing()
Definition: Effect.cpp:1132
bool RemovePrivateConfig(const PluginID &ID, const wxString &group, const wxString &key) override
bool CloseUI() override
Definition: Effect.cpp:697
bool GetSharedConfig(const PluginID &ID, const wxString &group, const wxString &key, wxString &value, const wxString &defval=_T("")) override
sampleCount mSampleCnt
Definition: Effect.h:474
bool Initialize()
Definition: Effect.cpp:2932
std::unique_ptr< T, Destroyer< T >> Destroy_ptr
Definition: MemoryX.h:814
void OnType(wxCommandEvent &evt)
Definition: Effect.cpp:4074
virtual void OnPreview(wxCommandEvent &evt)
Definition: Effect.cpp:2737
bool HideUI() override
Definition: Effect.cpp:692
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
static bool MayCapture(wxDialog *pDlg)
double GetRate() const
Definition: Project.h:184
void RealtimeAddEffect(Effect *effect)
void OnDefaults(wxCommandEvent &evt)
Definition: Effect.cpp:3692
unsigned GetAudioOutCount() override
Definition: Effect.cpp:307
END_EVENT_TABLE()
double GetRate() const
Definition: WaveTrack.cpp:397
virtual void SyncLockAdjust(double oldT1, double newT1)
Definition: Track.cpp:257
double mF1
Definition: Effect.h:463
double GetSel1() const
Definition: Project.h:190
bool GetPrivateConfig(const PluginID &ID, const wxString &group, const wxString &key, wxString &value, const wxString &defval=_T("")) override
size_t ProcessBlock(float **inBlock, float **outBlock, size_t blockLen) override
Definition: Effect.cpp:409
virtual void OnOk(wxCommandEvent &evt)
Definition: Effect.cpp:2742
static const int kOptionsID
Definition: Effect.cpp:76
static PluginManager & Get()
std::unique_ptr< LabelTrack > NewLabelTrack()
Definition: LabelTrack.cpp:99
bool mIsBatch
Definition: Effect.h:506
double duration() const
void SetBorder(int Border)
Definition: ShuttleGui.h:251
virtual bool PromptUser(wxWindow *parent)
Definition: Effect.cpp:1263
void OnClose(const CommandContext &)
void SeekStream(double seconds)
Move the playback / recording position of the current stream by the specified amount from where it is...
Definition: AudioIO.h:183
void SetHostUI(EffectUIHostInterface *host) override
Definition: Effect.cpp:663
void EndTwoColumn()
Definition: ShuttleGui.h:126
virtual wxString GetSavedStateGroup()
Definition: Effect.cpp:824
virtual void PopulateOrExchange(ShuttleGui &S)
Definition: Effect.cpp:1864
bool AcceptsFocusFromKeyboard() const override
Definition: Effect.cpp:2790
static const int UndefinedFrequency
void OnSaveAs(wxCommandEvent &evt)
Definition: Effect.cpp:3592
std::shared_ptr< TrackList > mOutputTracks
Definition: Effect.h:458
virtual bool CheckWhetherSkipEffect()
Definition: Effect.h:297
virtual ~EffectUIHost()
Definition: Effect.cpp:2871
virtual wxArrayString GetUserPresets()
Definition: Effect.cpp:1084
virtual int GetChannel() const override
Definition: WaveTrack.cpp:209
void SetStretchyCol(int i)
Used to modify an already placed FlexGridSizer to make a column stretchy.
Definition: ShuttleGui.cpp:192
virtual bool EnableApply(bool enable=true)
Definition: Effect.cpp:1879
wxString GetFactoryDefaultsGroup() override
Definition: Effect.cpp:819
void Resume()
Definition: Effect.cpp:3384
double mT0
Definition: Effect.h:459
wxString GetPath() override
Definition: Effect.cpp:156
double GetStartTime() const
Get the time at which the first clip in the track starts.
Definition: WaveTrack.cpp:1832
virtual bool Startup()
Definition: Effect.cpp:1010
virtual bool EnablePreview(bool enable=true)
Definition: Effect.cpp:1910
bool HasOptions() override
Definition: Effect.cpp:721
int mNumGroups
Definition: Effect.h:523
static const wxString kFactoryDefaultsIdent
Definition: Effect.h:543
virtual wxString HelpPage()
Definition: Effect.cpp:1127
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:982