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