Audacity 3.2.0
EffectUI.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 EffectUI.cpp
6
7 Leland Lucius
8
9 Audacity(R) is copyright (c) 1999-2008 Audacity Team.
10 License: GPL v2 or later. See License.txt.
11
12**********************************************************************/
13#include "EffectUI.h"
14#include "Effect.h"
16#include "EffectEditor.h"
17
18#include "AllThemeResources.h"
19#include "widgets/BasicMenu.h"
20#include "BasicUI.h"
21#include "ConfigInterface.h"
22#include "EffectManager.h"
23#include "PluginManager.h"
24#include "ProjectAudioIO.h"
25#include "ProjectHistory.h"
26#include "../ProjectWindowBase.h"
27#include "../TrackPanelAx.h"
28#include "RealtimeEffectList.h"
30#include "RealtimeEffectState.h"
31#include "Theme.h"
33
35{
36 return PluginManager::GetID(&effect.GetDefinition());
37}
38
40//
41// EffectPanel
42//
44
45class EffectPanel final : public wxPanelWrapper
46{
47public:
48 EffectPanel(wxWindow *parent)
49 : wxPanelWrapper(parent)
50 {
51 // This fools NVDA into not saying "Panel" when the dialog gets focus
54
55 mAcceptsFocus = true;
56 }
57
58 virtual ~EffectPanel()
59 {
60 }
61
62 // ============================================================================
63 // wxWindow implementation
64 // ============================================================================
65
66 bool AcceptsFocus() const override
67 {
68 return mAcceptsFocus;
69 }
70
71 // So that wxPanel is not included in Tab traversal, when required - see wxWidgets bug 15581
72 bool AcceptsFocusFromKeyboard() const override
73 {
74 return mAcceptsFocus;
75 }
76
77 // ============================================================================
78 // EffectPanel implementation
79 // ============================================================================
80 void SetAccept(bool accept)
81 {
82 mAcceptsFocus = accept;
83 }
84
85private:
87};
88
90//
91// EffectUIHost
92//
94
95#include "../../images/Effect.h"
96#include "AudioIO.h"
97#include "../CommonCommandFlags.h"
98#include "../Menus.h"
99#include "../prefs/GUISettings.h" // for RTL_WORKAROUND
100#include "Project.h"
101#include "../ProjectAudioManager.h"
102#include "ShuttleGui.h"
103#include "ViewInfo.h"
104#include "../commands/AudacityCommand.h"
105#include "../commands/CommandContext.h"
106#include "AudacityMessageBox.h"
107#include "HelpSystem.h"
108#include "../widgets/AButton.h"
109
110#include <wx/button.h>
111#include <wx/checkbox.h>
112#include <wx/dcclient.h>
113#include <wx/dcmemory.h>
114#include <wx/menu.h>
115#include <wx/settings.h>
116#include <wx/sizer.h>
117#include <wx/textctrl.h>
118
119#if defined(__WXMAC__)
120#include <Cocoa/Cocoa.h>
121#endif
122
123static const int kDummyID = 20000;
124static const int kSaveAsID = 20001;
125static const int kImportID = 20002;
126static const int kExportID = 20003;
127static const int kDefaultsID = 20004;
128static const int kOptionsID = 20005;
129static const int kUserPresetsDummyID = 20006;
130static const int kDeletePresetDummyID = 20007;
131static const int kMenuID = 20100;
132static const int kEnableID = 20101;
134static const int kPlaybackID = 20105;
135static const int kCaptureID = 20106;
136static const int kUserPresetsID = 21000;
137static const int kDeletePresetID = 22000;
138static const int kFactoryPresetsID = 23000;
139
140BEGIN_EVENT_TABLE(EffectUIHost, wxDialogWrapper)
141EVT_INIT_DIALOG(EffectUIHost::OnInitDialog)
142EVT_ERASE_BACKGROUND(EffectUIHost::OnErase)
143EVT_PAINT(EffectUIHost::OnPaint)
144EVT_CLOSE(EffectUIHost::OnClose)
159EVT_IDLE(EffectUIHost::OnIdle)
160EVT_CHAR_HOOK(EffectUIHost::OnCharHook)
162
163namespace {
166
168public:
170 const std::shared_ptr<EffectSettingsAccess> &pSide = {});
171 const EffectSettings &Get() override;
173 std::unique_ptr<Message> pMessage) override;
174 void Set(std::unique_ptr<Message> pMessage) override;
175 void Flush() override;
176 bool IsSameAs(const EffectSettingsAccess &other) const override;
177private:
179 const std::shared_ptr<EffectSettingsAccess> mpMain;
180 const std::weak_ptr<EffectSettingsAccess> mwSide;
181};
182}
183
184EffectSettingsAccessTee::EffectSettingsAccessTee(
186 const std::shared_ptr<EffectSettingsAccess> &pSide
187) : mpMain{ main.shared_from_this() }
188 , mwSide{ pSide }
189{
190}
191
193 return mpMain->Get();
194}
195
197 std::unique_ptr<Message> pMessage)
198{
199 // Move copies of the given settings and message into the side
200 if (auto pSide = mwSide.lock())
201 pSide->Set(EffectSettings{ settings },
202 pMessage ? pMessage->Clone() : nullptr);
203 // Move the given settings and message through
204 mpMain->Set(std::move(settings), std::move(pMessage));
205}
206
207void EffectSettingsAccessTee::Set(std::unique_ptr<Message> pMessage)
208{
209 // Move copies of the given message into the side
210 if (auto pSide = mwSide.lock())
211 pSide->Set(pMessage ? pMessage->Clone() : nullptr);
212 // Move the given message through
213 mpMain->Set(std::move(pMessage));
214}
215
217{
218 mpMain->Flush();
219 if (auto pSide = mwSide.lock())
220 pSide->Flush();
221}
222
224 const EffectSettingsAccess &other) const
225{
226 return mpMain->IsSameAs(other);
227}
228
230 AudacityProject &project, EffectPlugin &effect,
231 EffectUIServices &client, std::shared_ptr<EffectInstance> &pInstance,
232 EffectSettingsAccess &access,
233 const std::shared_ptr<RealtimeEffectState> &pPriorState)
234: wxDialogWrapper(parent, wxID_ANY, effect.GetDefinition().GetName(),
235 wxDefaultPosition, wxDefaultSize,
236 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX | wxMAXIMIZE_BOX)
237, mEffectUIHost{ effect }
238, mClient{ client }
239// Grab a pointer to the access object,
240// extending its lifetime while this remains:
241, mpGivenAccess{ access.shared_from_this() }
242, mpAccess{ mpGivenAccess }
243, mwState{ pPriorState }
244, mProject{ project }
245, mParent{ parent }
246, mSupportsRealtime{ mEffectUIHost.GetDefinition().SupportsRealtime() }
247, mHadPriorState{ (pPriorState != nullptr) }
248, mpInstance{ InitializeInstance() }
249, mpOutputs{ pPriorState ? pPriorState->GetOutputs() : nullptr }
250{
251 // Assign the out parameter
252 pInstance = mpInstance;
253#if defined(__WXMAC__)
254 // Make sure the effect window actually floats above the main window
255 [ [((NSView *)GetHandle()) window] setLevel:NSFloatingWindowLevel];
256#endif
257
258 SetName( effect.GetDefinition().GetName() );
259
260 // This style causes Validate() and TransferDataFromWindow() to visit
261 // sub-windows recursively, applying any wxValidators
262 SetExtraStyle(GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY);
263}
264
266{
267 if (mpEditor)
268 mpEditor->Disconnect();
269 DestroyChildren();
270 wxASSERT(mClosed);
271}
272
273// ============================================================================
274// wxWindow implementation
275// ============================================================================
276
278{
279 // Transfer-to takes const reference to settings
280 const auto pServices =
282 return (!pServices || pServices->TransferDataToWindow(mpAccess->Get())) &&
284 mpEditor->UpdateUI() &&
286 wxDialogWrapper::TransferDataToWindow();
287}
288
290{
292 if (!wxDialogWrapper::Validate())
293 return false;
294
296 if (!wxDialogWrapper::TransferDataFromWindow())
297 return false;
298
300 if (!mpEditor->ValidateUI())
301 return false;
302
303 // Transfer-from takes non-const reference to settings
304 bool result = true;
305 mpAccess->ModifySettings([&](EffectSettings &settings){
306 const auto pServices =
308 // Allow other transfers, and reassignment of settings
309 result = (!pServices || pServices->TransferDataFromWindow(settings));
310 if (result) {
311 auto &definition = mEffectUIHost.GetDefinition();
312 if (definition.GetType() == EffectTypeGenerate) {
313 const auto seconds = settings.extra.GetDuration();
314 // Updating of the last-used generator duration in the config
317 seconds);
318 }
319 }
320 return nullptr;
321 });
322 mpAccess->Flush();
323 return result;
324}
325
326// ============================================================================
327// wxDialog implementation
328// ============================================================================
329
331{
333 {
334 mApplyBtn->SetLabel(XXO("&Generate").Translation());
335 }
336
337 Layout();
338
339 return wxDialogWrapper::ShowModal();
340}
341
342// ============================================================================
343// EffectUIHost implementation
344// ============================================================================
345
346namespace {
348 const wxImage& ImageOn, const wxImage& ImageOff)
349{
350 auto pBtn = safenew AButton(parent, kEnableID,
351 wxDefaultPosition, wxDefaultSize, true);
352 pBtn->SetImages(ImageOff, ImageOff, ImageOn, ImageOn, ImageOff);
353 return pBtn;
354}
355}
356
358{
359 mIsGUI = graphicalUI;
361
362 constexpr int margin = 3;
363
364 S.StartPanel();
365 {
366 S.SetBorder( margin );
367
368 S.StartHorizontalLay(wxEXPAND, 0);
369 {
371 {
372 mEnableBtn = MakeBitmapToggleButton(S.GetParent(),
373 theTheme.Image(bmpEffectOn), theTheme.Image(bmpEffectOff));
374 S
375 .Position(wxALIGN_CENTER | wxTOP | wxBOTTOM)
376 .Name(XO("Power"))
377 .AddWindow(mEnableBtn);
378 }
379
380 mMenuBtn = S.Id( kMenuID )
381 .ToolTip(XO("Manage presets and options"))
382 .AddButton( XO("Presets && settings"), wxALIGN_CENTER | wxTOP | wxBOTTOM );
383
384 S.AddSpace(1, 0, 1);
385
386 if (!mIsBatch)
387 {
389 {
391 {
393 .ToolTip(XO("Start and stop preview"))
394 .AddButton( { },
395 wxALIGN_CENTER | wxTOP | wxBOTTOM );
396 }
397 }
398 else if (
401 {
403 .ToolTip(XO("Preview effect"))
404 .AddButton( { },
405 wxALIGN_CENTER | wxTOP | wxBOTTOM );
406 }
407 if(mPlayToggleBtn != nullptr)
408 {
409 //wxButton does not implement GetSizeFromText
410 //set button minimum size so that largest text fits
411 mPlayToggleBtn->SetLabel(_("Stop &Preview"));
412 auto a = mPlayToggleBtn->GetBestSize();
413 mPlayToggleBtn->SetLabel(_("&Preview"));
414 auto b = mPlayToggleBtn->GetBestSize();
415 mPlayToggleBtn->SetMinSize(a.x > b.x ? a : b);
416 }
417 }
418
420 {
421 mApplyBtn = S.Id(wxID_APPLY)
422 .AddButton( XXO("&Apply"),
423 wxALIGN_CENTER | wxTOP | wxBOTTOM );
424 mApplyBtn->SetDefault();
425 }
426
428 {
429 mDebugBtn = S.Id(eDebugID)
430 .AddButton( XXO("Debu&g"),
431 wxALIGN_CENTER | wxTOP | wxBOTTOM );
432 }
433 }
434 S.EndHorizontalLay();
435 }
436 S.EndPanel();
437}
438
440{
441 mEnabled = mpAccess->Get().extra.GetActive();
442
443 // Build a "host" dialog, framing a panel that the client fills in.
444 // The frame includes buttons to preview, apply, load and save presets, etc.
445 EffectPanel *w {};
446 ShuttleGui S{ this, eIsCreating };
447 {
448 // Make the panel for the client
449 Destroy_ptr<EffectPanel> uw{ safenew EffectPanel( S.GetParent() ) };
450 RTL_WORKAROUND(uw.get());
451
452 // Try to give the window a sensible default/minimum size
453 uw->SetMinSize(wxSize(wxMax(600, mParent->GetSize().GetWidth() * 2 / 3),
454 mParent->GetSize().GetHeight() / 2));
455
456 // Let the client add things to the panel
457 ShuttleGui S1{ uw.get(), eIsCreating };
460 if (!mpEditor)
461 return false;
462
463 BuildButtonBar(S, mpEditor->IsGraphicalUI());
464
465 S.StartHorizontalLay( wxEXPAND );
466 {
467 S.Prop( 1 )
468 .Position(wxEXPAND)
469 .AddWindow((w = uw.release()));
470 }
471 S.EndHorizontalLay();
472 }
473
474 Layout();
475 Fit();
476 Center();
477
479
480 w->SetAccept(!mIsGUI);
481
482 if (!mIsGUI)
483 {
484 w->SetFocus();
485 }
486 else if (!IsOpenedFromEffectPanel())
487 {
488 mApplyBtn->SetFocus();
489 }
490
492
493 SetMinSize(GetSize());
494 return true;
495}
496
498{
499 return !IsModal();
500}
501
502
503void EffectUIHost::OnInitDialog(wxInitDialogEvent & evt)
504{
505 // Do default handling
506 wxDialogWrapper::OnInitDialog(evt);
507
508#if wxCHECK_VERSION(3, 0, 0)
509 //#warning "check to see if this still needed in wx3"
510#endif
511
512 // Pure hackage coming down the pike...
513 //
514 // I have no idea why, but if a wxTextCtrl is the first control in the
515 // panel, then its contents will not be automatically selected when the
516 // dialog is displayed.
517 //
518 // So, we do the selection manually.
519 wxTextCtrl *focused = wxDynamicCast(FindFocus(), wxTextCtrl);
520 if (focused)
521 {
522 focused->SelectAll();
523 }
524}
525
526void EffectUIHost::OnErase(wxEraseEvent & WXUNUSED(evt))
527{
528 // Ignore it
529}
530
531void EffectUIHost::OnPaint(wxPaintEvent & WXUNUSED(evt))
532{
533 wxPaintDC dc(this);
534
535 dc.Clear();
536}
537
538void EffectUIHost::OnClose(wxCloseEvent & WXUNUSED(evt))
539{
540 if (mPlaying)
541 StopPlayback();
542
543 DoCancel();
545
546 if (mpEditor)
547 mpEditor->OnClose();
548
549 Hide();
550 Destroy();
551
552#if wxDEBUG_LEVEL
553 mClosed = true;
554#endif
555}
556
557void EffectUIHost::OnApply(wxCommandEvent & evt)
558{
559 auto &project = mProject;
560
561 // On wxGTK (wx2.8.12), the default action is still executed even if
562 // the button is disabled. This appears to affect all wxDialogs, not
563 // just our Effects dialogs. So, this is a only temporary workaround
564 // for legacy effects that disable the OK button. Hopefully this has
565 // been corrected in wx3.
566 if (!mApplyBtn->IsEnabled())
567 {
568 return;
569 }
570
571 if (mPlaying)
572 StopPlayback();
573
574 // Honor the "select all if none" preference...a little hackish, but whatcha gonna do...
575 if (!mIsBatch &&
579 {
580 auto flags = AlwaysEnabledFlag;
581 bool allowed =
584 flags,
586 if (!allowed)
587 return;
588 }
589
590 if (!TransferDataFromWindow() ||
591 // This is the main place where there is a side-effect on the config
592 // file to remember the last-used settings of an effect, just before
593 // applying the effect destructively.
596 return;
597
598 if (IsModal())
599 {
600 mDismissed = true;
601
602 EndModal(evt.GetId());
603
604 Close();
605
606 return;
607 }
608
609 // Progress dialog no longer yields, so this "shouldn't" be necessary (yet to be proven
610 // for sure), but it is a nice visual cue that something is going on.
611 mApplyBtn->Disable();
612 auto cleanup = finally( [&] { mApplyBtn->Enable(); } );
613
614 CommandContext context( project );
615 // This is absolute hackage...but easy and I can't think of another way just now.
616 //
617 // It should callback to the EffectManager to kick off the processing
620}
621
623{
624 if (!mDismissed) {
625 if (!mHadPriorState) {
626 // For the destructive effect dialog only
627 // Restore effect state from last updated preferences
628 mpAccess->ModifySettings([&](EffectSettings &settings) {
629 // ignore failure
630 return mEffectUIHost.GetDefinition().LoadUserPreset(
631 CurrentSettingsGroup(), settings).value_or(nullptr);
632 });
633 }
634 if (IsModal())
635 EndModal(0);
636 else
637 Hide();
638
639 mDismissed = true;
640 }
641}
642
643void EffectUIHost::OnCancel(wxCommandEvent & WXUNUSED(evt))
644{
645 DoCancel();
646 Close();
647}
648
649void EffectUIHost::OnDebug(wxCommandEvent & evt)
650{
651 OnApply(evt);
652}
653
654namespace {
656{
657 static const auto specialVersion = XO("n/a");
658 auto result = definition.GetVersion();
659 if (result == specialVersion.MSGID())
660 result = specialVersion.Translation();
661 return result;
662}
663}
664
665void EffectUIHost::OnMenu(wxCommandEvent & WXUNUSED(evt))
666{
667 wxMenu menu;
668 menu.Bind(wxEVT_MENU, [](auto&){}, kUserPresetsDummyID);
669 menu.Bind(wxEVT_MENU, [](auto&){}, kDeletePresetDummyID);
671
672 if (mUserPresets.size() == 0)
673 {
674 menu.Append(kUserPresetsDummyID, _("User Presets"))->Enable(false);
675 }
676 else
677 {
678 auto sub = std::make_unique<wxMenu>();
679 for (size_t i = 0, cnt = mUserPresets.size(); i < cnt; i++)
680 {
681 sub->Append(kUserPresetsID + i, mUserPresets[i]);
682 }
683 menu.Append(0, _("User Presets"), sub.release());
684 }
685
686 menu.Append(kSaveAsID, _("Save Preset..."));
687
688 if (mUserPresets.size() == 0)
689 {
690 menu.Append(kDeletePresetDummyID, _("Delete Preset"))->Enable(false);
691 }
692 else
693 {
694 auto sub = std::make_unique<wxMenu>();
695 for (size_t i = 0, cnt = mUserPresets.size(); i < cnt; i++)
696 {
697 sub->Append(kDeletePresetID + i, mUserPresets[i]);
698 }
699 menu.Append(0, _("Delete Preset"), sub.release());
700 }
701
702 menu.AppendSeparator();
703
705
706 {
707 auto sub = std::make_unique<wxMenu>();
708 sub->Append(kDefaultsID, _("Defaults"));
709 if (factory.size() > 0)
710 {
711 sub->AppendSeparator();
712 for (size_t i = 0, cnt = factory.size(); i < cnt; i++)
713 {
714 auto label = factory[i];
715 if (label.empty())
716 {
717 label = _("None");
718 }
719
720 sub->Append(kFactoryPresetsID + i, label);
721 }
722 }
723 menu.Append(0, _("Factory Presets"), sub.release());
724 }
725
726 menu.AppendSeparator();
727 menu.Append(kImportID, _("Import..."))
729 menu.Append(kExportID, _("Export..."))
731 menu.AppendSeparator();
732 menu.Append(kOptionsID, _("Options..."))
733 ->Enable(mEffectUIHost.HasOptions());
734 menu.AppendSeparator();
735
736 {
737 auto sub = std::make_unique<wxMenu>();
738
739 auto &definition = mEffectUIHost.GetDefinition();
740 sub->Append(kDummyID, wxString::Format(_("Type: %s"),
741 ::wxGetTranslation( definition.GetFamily().Translation() )));
742 sub->Append(kDummyID, wxString::Format(_("Name: %s"), definition.GetName().Translation()));
743 sub->Append(kDummyID, wxString::Format(_("Version: %s"),
744 GetVersionForDisplay(definition)));
745 sub->Append(kDummyID, wxString::Format(_("Vendor: %s"), definition.GetVendor().Translation()));
746 sub->Append(kDummyID, wxString::Format(_("Description: %s"), definition.GetDescription().Translation()));
747 sub->Bind(wxEVT_MENU, [](auto&){}, kDummyID);
748
749 menu.Append(0, _("About"), sub.release());
750 }
751
752 wxWindow *btn = FindWindow(kMenuID);
753 wxRect r = btn->GetRect();
754 BasicMenu::Handle{ &menu }.Popup(
756 { r.GetLeft(), r.GetBottom() }
757 );
758}
759
760void EffectUIHost::OnEnable(wxCommandEvent & WXUNUSED(evt))
761{
763
764 auto mpState = mwState.lock();
765 if (mpState)
766 mpState->SetActive(mEnabled);
767
769}
770
771void EffectUIHost::OnPlay(wxCommandEvent & WXUNUSED(evt))
772{
774 {
776 return;
777
778 auto updater = [this]{ TransferDataToWindow(); };
780 // After restoration of settings and effect state:
781 // In case any dialog control depends on mT1 or mDuration:
782 updater();
783
784 return;
785 }
786
787 if (mPlaying)
788 {
789 StopPlayback();
790 }
791 else
792 {
793 auto &viewInfo = ViewInfo::Get( mProject );
794 const auto &selectedRegion = viewInfo.selectedRegion;
795 const auto &playRegion = viewInfo.playRegion;
796 if ( playRegion.Active() )
797 {
798 mRegion.setTimes(playRegion.GetStart(), playRegion.GetEnd());
799 mPlayPos = mRegion.t0();
800 }
801 else if (selectedRegion.t0() != mRegion.t0() ||
802 selectedRegion.t1() != mRegion.t1())
803 {
804 mRegion = selectedRegion;
805 mPlayPos = mRegion.t0();
806 }
807
808 if (mPlayPos > mRegion.t1())
809 {
810 mPlayPos = mRegion.t1();
811 }
812
813 auto &projectAudioManager = ProjectAudioManager::Get( mProject );
814 projectAudioManager.PlayPlayRegion(
818 }
819}
820
822{
823 if (evt.on) {
824 if (evt.pProject != &mProject)
825 mDisableTransport = true;
826 else
827 mPlaying = true;
828 }
829 else {
830 mDisableTransport = false;
831 mPlaying = false;
832 }
833
834 if (mPlaying) {
836 mPlayPos = mRegion.t0();
837 }
839}
840
842{
843 if (evt.on) {
844 if (evt.pProject != &mProject)
845 mDisableTransport = true;
846 else
847 mCapturing = true;
848 }
849 else {
850 mDisableTransport = false;
851 mCapturing = false;
852 }
854}
855
856void EffectUIHost::OnUserPreset(wxCommandEvent & evt)
857{
858 int preset = evt.GetId() - kUserPresetsID;
859
860 mpAccess->ModifySettings([&](EffectSettings &settings){
861 // ignore failure
862 return mEffectUIHost.GetDefinition().LoadUserPreset(
863 UserPresetsGroup(mUserPresets[preset]), settings).value_or(nullptr);
864 });
866 return;
867}
868
869void EffectUIHost::OnFactoryPreset(wxCommandEvent & evt)
870{
871 mpAccess->ModifySettings([&](EffectSettings &settings){
873 return mEffectUIHost.GetDefinition().LoadFactoryPreset(
874 evt.GetId() - kFactoryPresetsID, settings).value_or(nullptr);
875 });
877 return;
878}
879
880void EffectUIHost::OnDeletePreset(wxCommandEvent & evt)
881{
882 auto preset = mUserPresets[evt.GetId() - kDeletePresetID];
883
884 int res = AudacityMessageBox(
885 XO("Are you sure you want to delete \"%s\"?").Format( preset ),
886 XO("Delete Preset"),
887 wxICON_QUESTION | wxYES_NO);
888 if (res == wxYES)
889 {
892 }
893
895
896 return;
897}
898
899void EffectUIHost::OnSaveAs(wxCommandEvent & WXUNUSED(evt))
900{
901 wxTextCtrl *text;
902 wxString name;
903 wxDialogWrapper dlg(this, wxID_ANY, XO("Save Preset"));
904
905 ShuttleGui S(&dlg, eIsCreating);
906
907 S.StartPanel();
908 {
909 S.StartVerticalLay(1);
910 {
911 S.StartHorizontalLay(wxALIGN_LEFT, 0);
912 {
913 text = S.AddTextBox(XXO("Preset name:"), name, 30);
914 }
915 S.EndHorizontalLay();
916 S.SetBorder(10);
917 S.AddStandardButtons();
918 }
919 S.EndVerticalLay();
920 }
921 S.EndPanel();
922
923 dlg.SetSize(dlg.GetSizer()->GetMinSize());
924 dlg.Center();
925 dlg.Fit();
926
927 while (true)
928 {
929 int rc = dlg.ShowModal();
930
931 if (rc != wxID_OK)
932 {
933 break;
934 }
935
936 name = text->GetValue();
937 if (name.empty())
938 {
940 this,
941 XO("You must specify a name"),
942 XO("Save Preset") );
943 md.Center();
944 md.ShowModal();
945 continue;
946 }
947
948 if ( make_iterator_range( mUserPresets ).contains( name ) )
949 {
951 this,
952 XO("Preset already exists.\n\nReplace?"),
953 XO("Save Preset"),
954 wxYES_NO | wxCANCEL | wxICON_EXCLAMATION );
955 md.Center();
956 int choice = md.ShowModal();
957 if (choice == wxID_CANCEL)
958 {
959 break;
960 }
961
962 if (choice == wxID_NO)
963 {
964 continue;
965 }
966 }
967
972
973 break;
974 }
975
976 return;
977}
978
979void EffectUIHost::OnImport(wxCommandEvent & WXUNUSED(evt))
980{
981 mpAccess->ModifySettings([&](EffectSettings &settings){
982 // ignore failure
983 return mClient.ImportPresets(mEffectUIHost, settings).value_or(nullptr);
984 });
987
988 return;
989}
990
991void EffectUIHost::OnExport(wxCommandEvent & WXUNUSED(evt))
992{
993 // may throw
994 // exceptions are handled in AudacityApp::OnExceptionInMainLoop
997
998 return;
999}
1000
1001void EffectUIHost::OnOptions(wxCommandEvent & WXUNUSED(evt))
1002{
1004
1005 return;
1006}
1007
1008void EffectUIHost::OnDefaults(wxCommandEvent & WXUNUSED(evt))
1009{
1010 mpAccess->ModifySettings([&](EffectSettings &settings){
1011 // ignore failure
1012 return mEffectUIHost.GetDefinition().LoadFactoryDefaults(settings)
1013 .value_or(nullptr);
1014 });
1016 return;
1017}
1018
1019void EffectUIHost::OnIdle(wxIdleEvent &evt)
1020{
1021 evt.Skip();
1022 if (mpAccess)
1023 mpAccess->Flush();
1024}
1025
1026void EffectUIHost::OnCharHook(wxKeyEvent& evt)
1027{
1028 if (!IsEscapeKey(evt))
1029 {
1030 evt.Skip();
1031 return;
1032 }
1033
1035 Close();
1036 else
1037 {
1038 wxCommandEvent cancelEvt { wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL };
1039
1040 OnCancel(cancelEvt);
1041 }
1042}
1043
1045{
1046 return (mpTempProjectState == nullptr && mSupportsRealtime);
1047}
1048
1049wxBitmap EffectUIHost::CreateBitmap(const char * const xpm[], bool up, bool pusher)
1050{
1051 wxMemoryDC dc;
1052 wxBitmap pic(xpm);
1053
1054 wxBitmap mod(pic.GetWidth() + 6, pic.GetHeight() + 6, 24);
1055 dc.SelectObject(mod);
1056
1057#if defined(__WXGTK__)
1058 wxColour newColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BACKGROUND);
1059#else
1060 wxColour newColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
1061#endif
1062
1063 dc.SetBackground(wxBrush(newColour));
1064 dc.Clear();
1065
1066 int offset = 3;
1067 if (pusher)
1068 {
1069 if (!up)
1070 {
1071 offset += 1;
1072 }
1073 }
1074
1075 dc.DrawBitmap(pic, offset, offset, true);
1076
1077 dc.SelectObject(wxNullBitmap);
1078
1079 return mod;
1080}
1081
1083{
1084 if (mIsBatch)
1085 {
1086 return;
1087 }
1088
1090 {
1092 return;
1093 }
1094
1095 mApplyBtn->Enable(!mCapturing);
1096
1098 {
1100
1101 if (mPlaying)
1102 {
1103 /* i18n-hint: The access key "&P" should be the same in
1104 "Stop &Preview" and "Start &Preview" */
1105 mPlayToggleBtn->SetLabel(_("Stop &Preview"));
1106 mPlayToggleBtn->Refresh();
1107 }
1108 else
1109 {
1110 /* i18n-hint: The access key "&P" should be the same in
1111 "Stop &Preview" and "Start &Preview" */
1112 mPlayToggleBtn->SetLabel(_("&Preview"));
1113 mPlayToggleBtn->Refresh();
1114 }
1115 }
1116}
1117
1119{
1120 mUserPresets.clear();
1121
1124
1125 std::sort( mUserPresets.begin(), mUserPresets.end() );
1126
1127 return;
1128}
1129
1130std::shared_ptr<EffectInstance> EffectUIHost::InitializeInstance()
1131{
1132 // We are still constructing and the return initializes a const member
1133 std::shared_ptr<EffectInstance> result;
1134
1135 auto mpState = mwState.lock();
1136
1137 bool priorState = (mpState != nullptr);
1138 if (!priorState) {
1139 auto gAudioIO = AudioIO::Get();
1140 mDisableTransport = !gAudioIO->IsAvailable(mProject);
1141 mPlaying = gAudioIO->IsStreamActive(); // not exactly right, but will suffice
1142 mCapturing = gAudioIO->IsStreamActive() && gAudioIO->GetNumCaptureChannels() > 0 && !gAudioIO->IsMonitoring();
1143 }
1144
1146 if (!priorState)
1147 mwState = mpState = mpTempProjectState =
1149 if (mpState) {
1150 // Find the right instance to connect to the dialog
1151 if (!result)
1152 result = mpState->GetInstance();
1153
1154 mpAccess2 = mpState->GetAccess();
1155 if (!(mpAccess2->IsSameAs(*mpAccess)))
1156 // Decorate the given access object
1157 mpAccess = std::make_shared<EffectSettingsAccessTee>(
1159
1160 mEffectStateSubscription = mpState->Subscribe([this](RealtimeEffectStateChange state) {
1163 });
1164 }
1165
1166 if (!priorState) {
1168 switch (event.type) {
1169 case AudioIOEvent::PLAYBACK:
1170 OnPlayback(event); break;
1171 case AudioIOEvent::CAPTURE:
1172 OnCapture(event); break;
1173 default:
1174 break;
1175 }
1176 });
1177 }
1178
1179 mInitialized = true;
1180 }
1181 else {
1182 result = mEffectUIHost.MakeInstance();
1183 if (auto pInstanceEx =
1184 std::dynamic_pointer_cast<EffectInstanceEx>(result)
1185 ; pInstanceEx && !pInstanceEx->Init())
1186 result.reset();
1187 }
1188
1189 return result;
1190}
1191
1193{
1195
1197 if (!IsOpenedFromEffectPanel()) {
1200 mpTempProjectState.reset();
1201 /*
1202 ProjectHistory::Get(mProject).PushState(
1203 XO("Removed %s effect").Format(mpState->GetEffect()->GetName()),
1204 XO("Removed Effect"),
1205 UndoPush::NONE
1206 );
1207 */
1208 }
1209 mInitialized = false;
1210 }
1211}
1212
1214{
1215 if (!mPlaying)
1216 return;
1217
1218 auto gAudioIO = AudioIO::Get();
1219 mPlayPos = gAudioIO->GetStreamTime();
1220 auto& projectAudioManager = ProjectAudioManager::Get(mProject);
1221 projectAudioManager.Stop();
1222}
1223
1225 EffectPlugin &host, EffectUIServices &client,
1226 EffectSettingsAccess &access)
1227{
1228 // Make sure there is an associated project, whose lifetime will
1229 // govern the lifetime of the dialog, even when the dialog is
1230 // non-modal, as for realtime effects
1231 auto project = FindProjectFromWindow(&parent);
1232 if ( !project )
1233 return {};
1234 std::shared_ptr<EffectInstance> pInstance;
1236 *project, host, client, pInstance, access } };
1237 if (!pInstance) {
1238 dlg->SetClosed();
1239 return {};
1240 }
1241 if (dlg->Initialize()) {
1242 auto pEditor = dlg->GetEditor();
1243 // release() is safe because parent will own it
1244 return { dlg.release(), pInstance, pEditor };
1245 }
1246 return {};
1247}
1248
1249#include "PluginManager.h"
1250#include "ProjectRate.h"
1251#include "../ProjectWindow.h"
1252#include "../SelectUtilities.h"
1253#include "../TrackPanel.h"
1254#include "WaveTrack.h"
1255#include "../commands/CommandManager.h"
1256
1260// parameters, whether to save the state to history and whether to allow
1262
1263/* static */ bool EffectUI::DoEffect(
1264 const PluginID & ID, const CommandContext &context, unsigned flags )
1265{
1266 AudacityProject &project = context.project;
1267 auto &tracks = TrackList::Get( project );
1268 auto &trackPanel = TrackPanel::Get( project );
1269 auto &trackFactory = WaveTrackFactory::Get( project );
1270 auto rate = ProjectRate::Get(project).GetRate();
1271 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
1272 auto &commandManager = CommandManager::Get( project );
1273 auto &window = ProjectWindow::Get( project );
1274
1275 const PluginDescriptor *plug = PluginManager::Get().GetPlugin(ID);
1276
1277 if (!plug || !PluginManager::IsPluginAvailable(*plug))
1278 {
1280 XO("This plugin could not be loaded.\nIt may have been deleted."),
1282 .Caption(XO("Plugin Error")));
1283
1284 return false;
1285 }
1286
1287 EffectType type = plug->GetEffectType();
1288
1289 // Make sure there's no activity since the effect is about to be applied
1290 // to the project's tracks. Mainly for Apply during RTP, but also used
1291 // for batch commands
1292 if (flags & EffectManager::kConfigured)
1293 {
1294 ProjectAudioManager::Get( project ).Stop();
1295 //Don't Select All if repeating Generator Effect
1296 if (!(flags & EffectManager::kConfigured)) {
1298 }
1299 }
1300
1301 auto nTracksOriginally = tracks.size();
1302 wxWindow *focus = wxWindow::FindFocus();
1303 wxWindow *parent = nullptr;
1304 if (focus != nullptr) {
1305 parent = focus->GetParent();
1306 }
1307
1308 bool success = false;
1309 auto cleanup = finally( [&] {
1310
1311 if (!success) {
1312 // For now, we're limiting realtime preview to a single effect, so
1313 // make sure the menus reflect that fact that one may have just been
1314 // opened.
1315 MenuManager::Get(project).UpdateMenus( false );
1316 }
1317
1318 } );
1319
1320 int count = 0;
1321 bool clean = true;
1322 for (auto t : tracks.Selected< const WaveTrack >()) {
1323 if (t->GetEndTime() != 0.0)
1324 clean = false;
1325 count++;
1326 }
1327
1329
1330 em.SetSkipStateFlag( false );
1331 success = false;
1332 if (auto effect = dynamic_cast<Effect*>(em.GetEffect(ID))) {
1333 if (const auto pSettings = em.GetDefaultSettings(ID)) {
1334 const auto pAccess =
1335 std::make_shared<SimpleEffectSettingsAccess>(*pSettings);
1336 const auto finder =
1337 [effect, &window, pAccess, flags] (EffectSettings &settings)
1338 -> std::optional<std::shared_ptr<EffectInstanceEx>>
1339 {
1340 // Prompting will be bypassed when applying an effect that has
1341 // already been configured, e.g. repeating the last effect on a
1342 // different selection. Prompting may call EffectBase::Preview
1343 std::shared_ptr<EffectInstance> pInstance;
1344 std::shared_ptr<EffectInstanceEx> pInstanceEx;
1345 if ((flags & EffectManager::kConfigured) == 0 && pAccess) {
1346 const auto pServices = dynamic_cast<EffectUIServices *>(effect);
1347 if (!pServices ||
1348 !pServices->ShowHostInterface(*effect,
1349 window, DialogFactory, pInstance, *pAccess, true)
1350 )
1351 return {};
1352 else if (!(pInstanceEx =
1353 std::dynamic_pointer_cast<EffectInstanceEx>(pInstance)
1354 ))
1355 return {};
1356 else
1357 // Retrieve again after the dialog modified settings
1358 settings = pAccess->Get();
1359 }
1360 return { pInstanceEx };
1361 };
1362 pAccess->ModifySettings([&](EffectSettings &settings){
1363 success = effect->DoEffect(settings, finder,
1364 rate,
1365 &tracks,
1366 &trackFactory,
1367 selectedRegion,
1368 flags,
1369 pAccess);
1370 return nullptr;
1371 });
1372 }
1373 }
1374
1375 if (!success)
1376 return false;
1377
1378 if (em.GetSkipStateFlag())
1379 flags = flags | EffectManager::kSkipState;
1380
1381 if (!(flags & EffectManager::kSkipState))
1382 {
1383 auto shortDesc = em.GetCommandName(ID);
1384 auto longDesc = em.GetCommandDescription(ID);
1385 ProjectHistory::Get( project ).PushState(longDesc, shortDesc);
1386 }
1387
1388 if (!(flags & EffectManager::kDontRepeatLast))
1389 {
1390 // Remember a successful generator, effect, analyzer, or tool Process
1391 auto shortDesc = em.GetCommandName(ID);
1392 /* i18n-hint: %s will be the name of the effect which will be
1393 * repeated if this menu item is chosen */
1394 auto lastEffectDesc = XO("Repeat %s").Format(shortDesc);
1395 auto& menuManager = MenuManager::Get(project);
1396 switch ( type ) {
1397 case EffectTypeGenerate:
1398 commandManager.Modify(wxT("RepeatLastGenerator"), lastEffectDesc);
1399 menuManager.mLastGenerator = ID;
1400 menuManager.mRepeatGeneratorFlags = EffectManager::kConfigured;
1401 break;
1402 case EffectTypeProcess:
1403 commandManager.Modify(wxT("RepeatLastEffect"), lastEffectDesc);
1404 menuManager.mLastEffect = ID;
1405 menuManager.mRepeatEffectFlags = EffectManager::kConfigured;
1406 break;
1407 case EffectTypeAnalyze:
1408 commandManager.Modify(wxT("RepeatLastAnalyzer"), lastEffectDesc);
1409 menuManager.mLastAnalyzer = ID;
1410 menuManager.mLastAnalyzerRegistration = MenuCreator::repeattypeplugin;
1411 menuManager.mRepeatAnalyzerFlags = EffectManager::kConfigured;
1412 break;
1413 case EffectTypeTool:
1414 commandManager.Modify(wxT("RepeatLastTool"), lastEffectDesc);
1415 menuManager.mLastTool = ID;
1416 menuManager.mLastToolRegistration = MenuCreator::repeattypeplugin;
1417 menuManager.mRepeatToolFlags = EffectManager::kConfigured;
1418 if (shortDesc == NYQUIST_PROMPT_NAME) {
1419 menuManager.mRepeatToolFlags = EffectManager::kRepeatNyquistPrompt; //Nyquist Prompt is not configured
1420 }
1421 break;
1422 }
1423 }
1424
1425 //STM:
1426 //The following automatically re-zooms after sound was generated.
1427 // IMO, it was disorienting, removing to try out without re-fitting
1428 //mchinen:12/14/08 reapplying for generate effects
1429 if (type == EffectTypeGenerate)
1430 {
1431 if (count == 0 || (clean && selectedRegion.t0() == 0.0))
1432 window.DoZoomFit();
1433 // trackPanel->Refresh(false);
1434 }
1435
1436 // PRL: RedrawProject explicitly because sometimes history push is skipped
1437 window.RedrawProject();
1438
1439 if (focus != nullptr && focus->GetParent()==parent) {
1440 focus->SetFocus();
1441 }
1442
1443 // A fix for Bug 63
1444 // New tracks added? Scroll them into view so that user sees them.
1445 // Don't care what track type. An analyser might just have added a
1446 // Label track and we want to see it.
1447 if( tracks.size() > nTracksOriginally ){
1448 // 0.0 is min scroll position, 1.0 is max scroll position.
1449 trackPanel.VerticalScroll( 1.0 );
1450 }
1451 else {
1452 auto pTrack = *tracks.Selected().begin();
1453 if (!pTrack)
1454 pTrack = *tracks.Any().begin();
1455 if (pTrack) {
1456 TrackFocus::Get(project).Set(pTrack);
1457 pTrack->EnsureVisible();
1458 }
1459 }
1460
1461 return true;
1462}
1463
1465BEGIN_EVENT_TABLE(EffectDialog, wxDialogWrapper)
1468
1469EffectDialog::EffectDialog(wxWindow * parent,
1470 const TranslatableString & title,
1471 int type,
1472 int flags,
1473 int additionalButtons)
1474: wxDialogWrapper(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, flags)
1475{
1476 mType = type;
1477 mAdditionalButtons = additionalButtons;
1478}
1479
1481{
1482 long buttons = eOkButton;
1484 {
1485 buttons |= eCancelButton;
1486 if (mType == EffectTypeProcess)
1487 {
1488 buttons |= ePreviewButton;
1489 }
1490 }
1491
1492 ShuttleGui S(this, eIsCreating);
1493
1494 S.SetBorder(5);
1495 S.StartVerticalLay(true);
1496 {
1498 S.AddStandardButtons(buttons|mAdditionalButtons);
1499 }
1500 S.EndVerticalLay();
1501
1502 Layout();
1503 Fit();
1504 SetMinSize(GetSize());
1505 Center();
1506}
1507
1512{
1513 return;
1514}
1515
1517{
1520
1521 return true;
1522}
1523
1525{
1528
1529 return true;
1530}
1531
1533{
1534 return true;
1535}
1536
1537void EffectDialog::OnPreview(wxCommandEvent & WXUNUSED(evt))
1538{
1539 return;
1540}
1541
1542void EffectDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
1543{
1544 // On wxGTK (wx2.8.12), the default action is still executed even if
1545 // the button is disabled. This appears to affect all wxDialogs, not
1546 // just our Effects dialogs. So, this is a only temporary workaround
1547 // for legacy effects that disable the OK button. Hopefully this has
1548 // been corrected in wx3.
1549 if (FindWindow(wxID_OK)->IsEnabled() && Validate() && TransferDataFromWindow())
1550 {
1551 EndModal(wxID_OK);
1552 }
1553
1554 return;
1555}
1556
1558#include "RealtimeEffectState.h"
1559static RealtimeEffectState::EffectFactory::Scope
EVT_MENU(OnSetPlayRegionToSelectionID, AdornedRulerPanel::OnSetPlayRegionToSelection) EVT_COMMAND(OnTogglePinnedStateID
wxEVT_COMMAND_BUTTON_CLICKED
wxImage(22, 22)
wxT("CloseDown"))
int main(int argc, char *argv[])
EVT_MENU_RANGE(FileHistory::ID_RECENT_FIRST, FileHistory::ID_RECENT_LAST, AudacityApp::OnMRUFile) bool AudacityApp
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Abstractions of menus and their items.
Toolkit-neutral facade for basic user interface services.
END_EVENT_TABLE()
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:34
const ReservedCommandFlag & TimeSelectedFlag()
const ReservedCommandFlag & WaveTracksSelectedFlag()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
Definition: Distortion.cpp:76
RegistryPath UserPresetsGroup(const RegistryPath &name)
Compute part of a registry path, given a name which may be empty.
const RegistryPath & CurrentSettingsGroup()
Component of a configuration key path, for last-used destructive settings.
EffectType
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeTool
@ EffectTypeProcess
wxString PluginID
Definition: EffectManager.h:30
static PluginID GetID(EffectPlugin &effect)
Definition: EffectUI.cpp:34
static const int kImportID
Definition: EffectUI.cpp:125
static const int kExportID
Definition: EffectUI.cpp:126
static const int kOptionsID
Definition: EffectUI.cpp:128
static const int kCaptureID
Definition: EffectUI.cpp:135
static RealtimeEffectState::EffectFactory::Scope scope
Inject a factory for realtime effects.
Definition: EffectUI.cpp:1560
static const int kDefaultsID
Definition: EffectUI.cpp:127
static const int kDummyID
Definition: EffectUI.cpp:123
static const int kPlaybackID
Definition: EffectUI.cpp:134
static const int kPlayID
Definition: EffectUI.cpp:133
static const int kSaveAsID
Definition: EffectUI.cpp:124
static const int kUserPresetsDummyID
Definition: EffectUI.cpp:129
static const int kFactoryPresetsID
Definition: EffectUI.cpp:138
static const int kEnableID
Definition: EffectUI.cpp:132
static const int kMenuID
Definition: EffectUI.cpp:131
static const int kDeletePresetDummyID
Definition: EffectUI.cpp:130
static const int kUserPresetsID
Definition: EffectUI.cpp:136
static const int kDeletePresetID
Definition: EffectUI.cpp:137
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define RTL_WORKAROUND(pWnd)
Definition: GUISettings.h:20
#define _(s)
Definition: Internat.h:73
#define safenew
Definition: MemoryX.h:10
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:448
std::unique_ptr< T, Destroyer< T > > Destroy_ptr
a convenience for using Destroyer
Definition: MemoryX.h:162
static const auto title
#define NYQUIST_PROMPT_NAME
an object holding per-project preferred sample rate
AudacityProject * FindProjectFromWindow(wxWindow *pWindow)
RealtimeEffectStateChange
EffectReverbSettings preset
Definition: Reverb.cpp:44
@ eIsSettingToDialog
Definition: ShuttleGui.h:39
@ eIsCreating
Definition: ShuttleGui.h:37
@ eIsGettingFromDialog
Definition: ShuttleGui.h:38
@ eOkButton
Definition: ShuttleGui.h:594
@ eCancelButton
Definition: ShuttleGui.h:595
@ ePreviewButton
Definition: ShuttleGui.h:599
@ eDebugID
Definition: ShuttleGui.h:613
TranslatableString label
Definition: TagsEditor.cpp:164
THEME_API Theme theTheme
Definition: Theme.cpp:82
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:87
static CustomUpdaterValue updater
A wxButton with mouse-over behaviour.
Definition: AButton.h:104
void PushDown()
Definition: AButton.cpp:577
bool IsDown()
Definition: AButton.h:208
void PopUp()
Definition: AButton.cpp:585
Wrap wxMessageDialog so that caption IS translatable.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
static AudioIO * Get()
Definition: AudioIO.cpp:147
std::shared_ptr< RealtimeEffectState > AddState(AudacityProject &project, Track *pTrack, const PluginID &id)
Forwards to RealtimeEffectManager::AddState with proper init scope.
Definition: AudioIO.cpp:369
void RemoveState(AudacityProject &project, Track *pTrack, std::shared_ptr< RealtimeEffectState > pState)
Forwards to RealtimeEffectManager::RemoveState with proper init scope.
Definition: AudioIO.cpp:390
void Popup(const BasicUI::WindowPlacement &window, const Point &pos={})
Display the menu at pos, invoke at most one action, then hide it.
Definition: BasicMenu.cpp:209
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
static CommandManager & Get(AudacityProject &project)
virtual wxString GetVersion() const =0
TranslatableString GetName() const
EffectDefinitionInterface is a ComponentInterface that adds some basic read-only information about ef...
virtual EffectType GetType() const =0
Type determines how it behaves.
virtual bool EnablesDebug() const
Whether the effect dialog should have a Debug button; default, always false.
bool Validate() override
Definition: EffectUI.cpp:1532
bool TransferDataToWindow() override
Definition: EffectUI.cpp:1516
bool TransferDataFromWindow() override
Definition: EffectUI.cpp:1524
virtual void OnPreview(wxCommandEvent &evt)
Definition: EffectUI.cpp:1537
virtual void OnOk(wxCommandEvent &evt)
Definition: EffectUI.cpp:1542
virtual void PopulateOrExchange(ShuttleGui &S)
Definition: EffectUI.cpp:1511
int mAdditionalButtons
Definition: EffectUI.h:210
static constexpr int kPlayID
Definition: EffectEditor.h:76
Base class for many of the effects in Audacity.
Definition: Effect.h:26
virtual std::shared_ptr< EffectInstance > MakeInstance() const =0
Make an object maintaining short-term state of an Effect.
EffectManager is the class that handles effects and effect categories.
Definition: EffectManager.h:48
bool GetSkipStateFlag()
void SetSkipStateFlag(bool flag)
EffectPlugin * GetEffect(const PluginID &ID)
static const EffectInstanceFactory * GetInstanceFactory(const PluginID &ID)
static EffectManager & Get()
EffectSettings * GetDefaultSettings(const PluginID &ID)
TranslatableString GetCommandName(const PluginID &ID)
TranslatableString GetCommandDescription(const PluginID &ID)
virtual ~EffectPanel()
Definition: EffectUI.cpp:58
void SetAccept(bool accept)
Definition: EffectUI.cpp:80
bool AcceptsFocus() const override
Definition: EffectUI.cpp:66
bool AcceptsFocusFromKeyboard() const override
Definition: EffectUI.cpp:72
EffectPanel(wxWindow *parent)
Definition: EffectUI.cpp:48
bool mAcceptsFocus
Definition: EffectUI.cpp:86
Factory of instances of an effect.
Definition: EffectPlugin.h:36
virtual bool HasOptions() const =0
virtual bool CanExportPresets() const =0
Whether the effect supports export of presets to files, and importing too.
virtual const EffectSettingsManager & GetDefinition() const =0
virtual bool IsBatchProcessing() const =0
virtual void Preview(EffectSettingsAccess &access, std::function< void()> updateUI, bool dryOnly)=0
Calculate temporary tracks of limited length with effect applied and play.
static const RegistryPath & DurationKey()
virtual RegistryPaths GetFactoryPresets() const =0
Report names of factory presets.
virtual bool SaveUserPreset(const RegistryPath &name, const EffectSettings &settings) const =0
Save settings in the configuration file as a user-named preset.
EffectPlugin & mEffectUIHost
Definition: EffectUI.h:120
void OnEnable(wxCommandEvent &evt)
Definition: EffectUI.cpp:760
void OnFactoryPreset(wxCommandEvent &evt)
Definition: EffectUI.cpp:869
RegistryPaths mUserPresets
Definition: EffectUI.h:130
void OnDefaults(wxCommandEvent &evt)
Definition: EffectUI.cpp:1008
Observer::Subscription mAudioIOSubscription
Definition: EffectUI.h:116
bool HandleCommandKeystrokes() override
Definition: EffectUI.cpp:497
void UpdateControls()
Definition: EffectUI.cpp:1082
wxPanel * BuildButtonBar(wxWindow *parent, bool graphicalUI)
bool mIsBatch
Definition: EffectUI.h:134
bool mCapturing
Definition: EffectUI.h:146
wxButton * mMenuBtn
Definition: EffectUI.h:137
virtual ~EffectUIHost()
Definition: EffectUI.cpp:265
void OnErase(wxEraseEvent &evt)
Definition: EffectUI.cpp:526
void OnPlayback(AudioIOEvent)
Definition: EffectUI.cpp:821
void CleanupRealtime()
Definition: EffectUI.cpp:1192
AudacityProject & mProject
Definition: EffectUI.h:118
std::shared_ptr< RealtimeEffectState > mpTempProjectState
Definition: EffectUI.h:128
bool mIsGUI
Definition: EffectUI.h:133
bool TransferDataToWindow() override
Definition: EffectUI.cpp:277
EffectPlugin::EffectSettingsAccessPtr mpAccess
Definition: EffectUI.h:124
const EffectOutputs *const mpOutputs
Definition: EffectUI.h:160
void OnUserPreset(wxCommandEvent &evt)
Definition: EffectUI.cpp:856
void OnDeletePreset(wxCommandEvent &evt)
Definition: EffectUI.cpp:880
bool mPlaying
Definition: EffectUI.h:145
void OnIdle(wxIdleEvent &evt)
Definition: EffectUI.cpp:1019
wxButton * mPlayToggleBtn
Definition: EffectUI.h:140
void StopPlayback()
Definition: EffectUI.cpp:1213
int ShowModal() override
Definition: EffectUI.cpp:330
bool mDisableTransport
Definition: EffectUI.h:144
Observer::Subscription mEffectStateSubscription
Definition: EffectUI.h:116
SelectedRegion mRegion
Definition: EffectUI.h:148
void DoCancel()
Definition: EffectUI.cpp:622
void OnCapture(AudioIOEvent)
Definition: EffectUI.cpp:841
EffectUIServices & mClient
Definition: EffectUI.h:121
double mPlayPos
Definition: EffectUI.h:149
void OnClose(wxCloseEvent &evt)
Definition: EffectUI.cpp:538
void OnExport(wxCommandEvent &evt)
Definition: EffectUI.cpp:991
AButton * mEnableBtn
Definition: EffectUI.h:138
void OnSaveAs(wxCommandEvent &evt)
Definition: EffectUI.cpp:899
EffectUIHost(wxWindow *parent, AudacityProject &project, EffectPlugin &effect, EffectUIServices &client, std::shared_ptr< EffectInstance > &pInstance, EffectSettingsAccess &access, const std::shared_ptr< RealtimeEffectState > &pPriorState={})
Definition: EffectUI.cpp:229
wxButton * mApplyBtn
Definition: EffectUI.h:136
const bool mHadPriorState
Definition: EffectUI.h:152
void OnOptions(wxCommandEvent &evt)
Definition: EffectUI.cpp:1001
void LoadUserPresets()
Definition: EffectUI.cpp:1118
void OnInitDialog(wxInitDialogEvent &evt)
Definition: EffectUI.cpp:503
void OnMenu(wxCommandEvent &evt)
Definition: EffectUI.cpp:665
void OnDebug(wxCommandEvent &evt)
Definition: EffectUI.cpp:649
void OnCharHook(wxKeyEvent &evt)
Definition: EffectUI.cpp:1026
bool mEnabled
Definition: EffectUI.h:142
EffectPlugin::EffectSettingsAccessPtr mpAccess2
Definition: EffectUI.h:125
void OnImport(wxCommandEvent &evt)
Definition: EffectUI.cpp:979
std::unique_ptr< EffectEditor > mpEditor
Definition: EffectUI.h:162
std::shared_ptr< EffectInstance > InitializeInstance()
Definition: EffectUI.cpp:1130
void OnApply(wxCommandEvent &evt)
Definition: EffectUI.cpp:557
const bool mSupportsRealtime
Definition: EffectUI.h:132
bool Initialize()
Definition: EffectUI.cpp:439
void OnPlay(wxCommandEvent &evt)
Definition: EffectUI.cpp:771
const std::shared_ptr< EffectInstance > mpInstance
Definition: EffectUI.h:159
void OnCancel(wxCommandEvent &evt)
Definition: EffectUI.cpp:643
bool mInitialized
Definition: EffectUI.h:131
std::weak_ptr< RealtimeEffectState > mwState
Definition: EffectUI.h:126
wxWindow *const mParent
Definition: EffectUI.h:119
wxButton * mDebugBtn
Definition: EffectUI.h:139
wxBitmap CreateBitmap(const char *const xpm[], bool up, bool pusher)
Definition: EffectUI.cpp:1049
bool IsOpenedFromEffectPanel() const
Definition: EffectUI.cpp:1044
bool TransferDataFromWindow() override
Definition: EffectUI.cpp:289
void OnPaint(wxPaintEvent &evt)
Definition: EffectUI.cpp:531
bool mDismissed
Definition: EffectUI.h:151
virtual void ShowOptions(const EffectPlugin &plugin) const =0
virtual std::unique_ptr< EffectEditor > PopulateUI(const EffectPlugin &plugin, ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs) const =0
Adds controls to a panel that is given as the parent window of S
virtual OptionalMessage ImportPresets(const EffectPlugin &plugin, EffectSettings &settings) const =0
virtual void ExportPresets(const EffectPlugin &plugin, const EffectSettings &settings) const =0
Abstract base class used in importing a file.
@ repeattypeplugin
Definition: Menus.h:61
static MenuManager & Get(AudacityProject &project)
Definition: Menus.cpp:69
bool ReportIfActionNotAllowed(const TranslatableString &Name, CommandFlag &flags, CommandFlag flagsRqd)
Definition: Menus.cpp:639
void UpdateMenus(bool checkActive=true)
Definition: Menus.cpp:577
bool isPoint() const
Definition: ViewInfo.h:40
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
void Reset() noexcept
Breaks the connection (constant time)
Definition: Observer.cpp:101
EffectType GetEffectType() const
static PluginID GetID(PluginProvider *provider)
static bool IsPluginAvailable(const PluginDescriptor &plug)
const PluginDescriptor * GetPlugin(const PluginID &ID) const
static PluginManager & Get()
static AudioIOStartStreamOptions GetDefaultOptions(AudacityProject &project, bool newDefaults=false)
Invoke the global hook, supplying a default argument.
void Stop(bool stopStream=true)
static ProjectAudioManager & Get(AudacityProject &project)
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
double GetRate() const
Definition: ProjectRate.cpp:53
static ProjectWindow & Get(AudacityProject &project)
Defines a selected portion of a project.
double t1() const
bool setTimes(double t0, double t1)
double t0() const
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:625
wxImage & Image(int iIndex)
Track * Get()
void EnsureVisible(bool modifyState=false)
Definition: Track.cpp:98
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:487
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:231
Holds a msgid for the translation catalog; may also bind format arguments.
static const TranslatableString Inaudible
A special string value that will have no screen reader pronunciation.
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:219
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:2536
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
void Set(EffectSettings &&settings, std::unique_ptr< Message > pMessage) override
const std::weak_ptr< EffectSettingsAccess > mwSide
Definition: EffectUI.cpp:180
void Set(std::unique_ptr< Message > pMessage) override
Message-only overload of Set(). In future, this should be the only one.
const std::shared_ptr< EffectSettingsAccess > mpMain
Definition: EffectUI.cpp:179
void Flush() override
Make the last Set changes "persistent" in underlying storage.
Definition: EffectUI.cpp:216
bool IsSameAs(const EffectSettingsAccess &other) const override
Definition: EffectUI.cpp:223
void SetLabel(const TranslatableString &label)
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:196
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:274
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
Definition: BasicUI.h:343
AUDACITY_DLL_API bool DoEffect(const PluginID &ID, const CommandContext &context, unsigned flags)
'Repeat Last Effect'.
Definition: EffectUI.cpp:1263
AUDACITY_DLL_API DialogFactoryResults DialogFactory(wxWindow &parent, EffectPlugin &host, EffectUIServices &client, EffectSettingsAccess &access)
Definition: EffectUI.cpp:1224
bool RemoveConfigSubgroup(const EffectDefinitionInterface &ident, PluginSettings::ConfigurationType type, const RegistryPath &group)
bool GetConfigSubgroups(const EffectDefinitionInterface &ident, PluginSettings::ConfigurationType type, const RegistryPath &group, RegistryPaths &subgroups)
bool SetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, const Value &value)
void SelectAllIfNone(AudacityProject &project)
AButton * MakeBitmapToggleButton(wxWindow *parent, const wxImage &ImageOn, const wxImage &ImageOff)
Definition: EffectUI.cpp:347
wxString GetVersionForDisplay(const EffectDefinitionInterface &definition)
Definition: EffectUI.cpp:655
static RegisteredToolbarFactory factory
bool on
Definition: AudioIO.h:77
enum AudioIOEvent::Type type
AudacityProject * pProject
Definition: AudioIO.h:71
Externalized state of a plug-in.
Window placement information for wxWidgetsBasicUI can be constructed from a wxWindow pointer.