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
14
15#include "EffectUI.h"
16
17#include "widgets/BasicMenu.h"
18#include "ConfigInterface.h"
19#include "EffectManager.h"
20#include "PluginManager.h"
21#include "ProjectHistory.h"
22#include "../ProjectWindowBase.h"
23#include "../TrackPanelAx.h"
24#include "RealtimeEffectList.h"
26#include "RealtimeEffectState.h"
28
30{
31 return PluginManager::GetID(&effect.GetDefinition());
32}
33
35//
36// EffectPanel
37//
39
40class EffectPanel final : public wxPanelWrapper
41{
42public:
43 EffectPanel(wxWindow *parent)
44 : wxPanelWrapper(parent)
45 {
46 // This fools NVDA into not saying "Panel" when the dialog gets focus
49
50 mAcceptsFocus = true;
51 }
52
53 virtual ~EffectPanel()
54 {
55 }
56
57 // ============================================================================
58 // wxWindow implementation
59 // ============================================================================
60
61 bool AcceptsFocus() const override
62 {
63 return mAcceptsFocus;
64 }
65
66 // So that wxPanel is not included in Tab traversal, when required - see wxWidgets bug 15581
67 bool AcceptsFocusFromKeyboard() const override
68 {
69 return mAcceptsFocus;
70 }
71
72 // ============================================================================
73 // EffectPanel implementation
74 // ============================================================================
75 void SetAccept(bool accept)
76 {
77 mAcceptsFocus = accept;
78 }
79
80private:
82};
83
85//
86// EffectUIHost
87//
89
90#include "../../images/Effect.h"
91#include "../AudioIO.h"
92#include "../CommonCommandFlags.h"
93#include "../Menus.h"
94#include "../prefs/GUISettings.h" // for RTL_WORKAROUND
95#include "Project.h"
96#include "../ProjectAudioManager.h"
97#include "../ShuttleGui.h"
98#include "ViewInfo.h"
99#include "../commands/AudacityCommand.h"
100#include "../commands/CommandContext.h"
101#include "../widgets/AudacityMessageBox.h"
102#include "../widgets/HelpSystem.h"
103
104#include <wx/bmpbuttn.h>
105#include <wx/checkbox.h>
106#include <wx/dcclient.h>
107#include <wx/dcmemory.h>
108#include <wx/menu.h>
109#include <wx/settings.h>
110#include <wx/sizer.h>
111#include <wx/textctrl.h>
112
113#if defined(__WXMAC__)
114#include <Cocoa/Cocoa.h>
115#endif
116
117static const int kDummyID = 20000;
118static const int kSaveAsID = 20001;
119static const int kImportID = 20002;
120static const int kExportID = 20003;
121static const int kDefaultsID = 20004;
122static const int kOptionsID = 20005;
123static const int kUserPresetsDummyID = 20006;
124static const int kDeletePresetDummyID = 20007;
125static const int kMenuID = 20100;
126static const int kEnableID = 20101;
127static const int kPlayID = 20102;
128static const int kRewindID = 20103;
129static const int kFFwdID = 20104;
130static const int kPlaybackID = 20105;
131static const int kCaptureID = 20106;
132static const int kUserPresetsID = 21000;
133static const int kDeletePresetID = 22000;
134static const int kFactoryPresetsID = 23000;
135
136BEGIN_EVENT_TABLE(EffectUIHost, wxDialogWrapper)
137EVT_INIT_DIALOG(EffectUIHost::OnInitDialog)
138EVT_ERASE_BACKGROUND(EffectUIHost::OnErase)
139EVT_PAINT(EffectUIHost::OnPaint)
140EVT_CLOSE(EffectUIHost::OnClose)
159
160namespace {
163
165public:
167 const std::shared_ptr<EffectSettingsAccess> &pSide = {});
168 const EffectSettings &Get() override;
169 void Set(EffectSettings &&settings) override;
170 void Flush() override;
171 bool IsSameAs(const EffectSettingsAccess &other) const override;
172private:
174 const std::shared_ptr<EffectSettingsAccess> mpMain;
175 const std::weak_ptr<EffectSettingsAccess> mwSide;
176};
177}
178
179EffectSettingsAccessTee::EffectSettingsAccessTee(
181 const std::shared_ptr<EffectSettingsAccess> &pSide
182) : mpMain{ main.shared_from_this() }
183 , mwSide{ pSide }
184{
185}
186
188 return mpMain->Get();
189}
190
192 // Move a copy of the given settings into the side
193 if (auto pSide = mwSide.lock())
194 pSide->Set(EffectSettings{ settings });
195 // Move the given settings through
196 mpMain->Set(std::move(settings));
197}
198
200{
201 mpMain->Flush();
202 if (auto pSide = mwSide.lock())
203 pSide->Flush();
204}
205
207 const EffectSettingsAccess &other) const
208{
209 return mpMain->IsSameAs(other);
210}
211
213 AudacityProject &project, EffectPlugin &effect,
214 EffectUIClientInterface &client, std::shared_ptr<EffectInstance> &pInstance,
215 EffectSettingsAccess &access,
216 const std::shared_ptr<RealtimeEffectState> &pPriorState)
217: wxDialogWrapper(parent, wxID_ANY, effect.GetDefinition().GetName(),
218 wxDefaultPosition, wxDefaultSize,
219 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX | wxMAXIMIZE_BOX)
220, mEffectUIHost{ effect }
221, mClient{ client }
222// Grab a pointer to the access object,
223// extending its lifetime while this remains:
224, mpGivenAccess{ access.shared_from_this() }
225, mpAccess{ mpGivenAccess }
226, mpState{ pPriorState }
227, mProject{ project }
228, mParent{ parent }
229, mSupportsRealtime{ mEffectUIHost.GetDefinition().SupportsRealtime() }
230, mpInstance{ InitializeInstance() }
231{
232 // Assign the out parameter
233 pInstance = mpInstance;
234#if defined(__WXMAC__)
235 // Make sure the effect window actually floats above the main window
236 [ [((NSView *)GetHandle()) window] setLevel:NSFloatingWindowLevel];
237#endif
238
239 SetName( effect.GetDefinition().GetName() );
240
241 // This style causes Validate() and TransferDataFromWindow() to visit
242 // sub-windows recursively, applying any wxValidators
243 SetExtraStyle(GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY);
244}
245
247{
248 wxASSERT(mClosed);
249}
250
251// ============================================================================
252// wxWindow implementation
253// ============================================================================
254
256{
257 // Transfer-to takes const reference to settings
260 mpValidator->UpdateUI() &&
262 wxDialogWrapper::TransferDataToWindow();
263}
264
266{
268 if (!wxDialogWrapper::Validate())
269 return false;
270
272 if (!wxDialogWrapper::TransferDataFromWindow())
273 return false;
274
276 if (!mpValidator->ValidateUI())
277 return false;
278
279 // Transfer-from takes non-const reference to settings
280 bool result = true;
281 mpAccess->ModifySettings([&](EffectSettings &settings){
282 // Allow other transfers, and reassignment of settings
284 if (result) {
285 auto &definition = mEffectUIHost.GetDefinition();
286 if (definition.GetType() == EffectTypeGenerate) {
287 const auto seconds = settings.extra.GetDuration();
288 // Updating of the last-used generator duration in the config
289 SetConfig(definition, PluginSettings::Private,
290 CurrentSettingsGroup(), EffectSettingsExtra::DurationKey(),
291 seconds);
292 }
293 }
294 });
295 mpAccess->Flush();
296 return result;
297}
298
299// ============================================================================
300// wxDialog implementation
301// ============================================================================
302
304{
305#if defined(__WXMSW__)
306 // Swap the Close and Apply buttons
307 wxSizer *sz = mApplyBtn->GetContainingSizer();
308 wxASSERT(mApplyBtn->GetParent()); // To justify safenew
309 wxButton *apply = safenew wxButton(mApplyBtn->GetParent(), wxID_APPLY);
310 sz->Replace(mCloseBtn, apply);
311 sz->Replace(mApplyBtn, mCloseBtn);
312 sz->Layout();
313 mApplyBtn->Destroy();
314 mApplyBtn = apply;
315 mApplyBtn->SetDefault();
316 mApplyBtn->SetLabel(wxGetStockLabel(wxID_OK, 0));
317 mCloseBtn->SetLabel(wxGetStockLabel(wxID_CANCEL, 0));
318#else
319 mApplyBtn->SetLabel(wxGetStockLabel(wxID_OK));
320 mCloseBtn->SetLabel(wxGetStockLabel(wxID_CANCEL));
321#endif
322
323 Layout();
324
325 return wxDialogWrapper::ShowModal();
326}
327
328// ============================================================================
329// EffectUIHost implementation
330// ============================================================================
331
332wxPanel *EffectUIHost::BuildButtonBar(wxWindow *parent)
333{
336
337 int margin = 0;
338#if defined(__WXMAC__)
339 margin = 3; // I'm sure it's needed because of the order things are created...
340#endif
341
342 const auto bar = safenew wxPanelWrapper(parent, wxID_ANY);
343
344 // This fools NVDA into not saying "Panel" when the dialog gets focus
345 bar->SetName(TranslatableString::Inaudible);
346 bar->SetLabel(TranslatableString::Inaudible);
347
349 false /* horizontal */,
350 { -1, -1 } /* minimum size */
351 };
352 {
353 S.SetBorder( margin );
354
355 if (!mIsGUI)
356 {
357 mMenuBtn = S.Id( kMenuID )
358 .ToolTip(XO("Manage presets and options"))
359 .AddButton( XXO("&Manage"), wxALIGN_CENTER | wxTOP | wxBOTTOM );
360 }
361 else
362 {
363 mMenuBtn = S.Id( kMenuID )
364 .ToolTip(XO("Manage presets and options"))
365 .Name(XO("&Manage"))
366 .AddBitmapButton( CreateBitmap(effect_menu_xpm, true, true) );
367 mMenuBtn->SetBitmapPressed(CreateBitmap(effect_menu_xpm, false, true));
368 }
369
370 S.AddSpace( 5, 5 );
371
372 if (!mIsBatch)
373 {
374 if (!mIsGUI)
375 {
377 {
378 mPlayToggleBtn = S.Id( kPlayID )
379 .ToolTip(XO("Start and stop playback"))
380 .AddButton( XXO("Start &Playback"),
381 wxALIGN_CENTER | wxTOP | wxBOTTOM );
382 }
383 else if (
386 {
387 mPlayToggleBtn = S.Id( kPlayID )
388 .ToolTip(XO("Preview effect"))
389 .AddButton( XXO("&Preview"),
390 wxALIGN_CENTER | wxTOP | wxBOTTOM );
391 }
392 }
393 else
394 {
395 mPlayBM = CreateBitmap(effect_play_xpm, true, false);
396 mPlayDisabledBM = CreateBitmap(effect_play_disabled_xpm, true, true);
397 mStopBM = CreateBitmap(effect_stop_xpm, true, false);
398 mStopDisabledBM = CreateBitmap(effect_stop_disabled_xpm, true, false);
399 mPlayBtn = S.Id( kPlayID ).AddBitmapButton( mPlayBM );
400 mPlayBtn->SetBitmapDisabled(mPlayDisabledBM);
401 mPlayBtn->SetBitmapPressed(CreateBitmap(effect_play_xpm, false, true));
403 {
404 mPlayBtn->SetToolTip(_("Preview effect"));
405#if defined(__WXMAC__)
406 mPlayBtn->SetName(_("Preview effect"));
407#else
408 mPlayBtn->SetLabel(_("&Preview effect"));
409#endif
410 }
411 }
412
414 {
415 if (!mIsGUI)
416 {
417 mRewindBtn = S.Id( kRewindID )
418 .ToolTip(XO("Skip backward"))
419 .AddButton( XXO("Skip &Backward"),
420 wxALIGN_CENTER | wxTOP | wxBOTTOM );
421 }
422 else
423 {
424 mRewindBtn = S.Id( kRewindID )
425 .ToolTip(XO("Skip backward"))
426 .Name(XO("Skip &Backward"))
427 .AddBitmapButton( CreateBitmap(
428 effect_rewind_xpm, true, true) );
429 mRewindBtn->SetBitmapDisabled(
430 CreateBitmap(effect_rewind_disabled_xpm, true, false));
431 mRewindBtn->SetBitmapPressed(CreateBitmap(effect_rewind_xpm, false, true));
432 }
433
434 if (!mIsGUI)
435 {
436 mFFwdBtn = S.Id( kFFwdID )
437 .ToolTip(XO("Skip forward"))
438 .AddButton( XXO("Skip &Forward"),
439 wxALIGN_CENTER | wxTOP | wxBOTTOM );
440 }
441 else
442 {
443 mFFwdBtn = S.Id( kFFwdID )
444 .ToolTip(XO("Skip forward"))
445 .Name(XO("Skip &Forward"))
446 .AddBitmapButton( CreateBitmap(
447 effect_ffwd_xpm, true, true) );
448 mFFwdBtn->SetBitmapDisabled(
449 CreateBitmap(effect_ffwd_disabled_xpm, true, false));
450 mFFwdBtn->SetBitmapPressed(CreateBitmap(effect_ffwd_xpm, false, true));
451 }
452
453 S.AddSpace( 5, 5 );
454
455 mEnableCb = S.Id( kEnableID )
456 .Position(wxALIGN_CENTER | wxTOP | wxBOTTOM)
457 .Name(XO("Enable"))
458 .AddCheckBox( XXO("&Enable"), mEnabled );
459 //
460 }
461 }
462 }
463
464 bar->GetSizer()->SetSizeHints( bar );
465
466 return bar;
467}
468
470{
471 // Build a "host" dialog, framing a panel that the client fills in.
472 // The frame includes buttons to preview, apply, load and save presets, etc.
473 EffectPanel *w {};
474 ShuttleGui S{ this, eIsCreating };
475 {
476 S.StartHorizontalLay( wxEXPAND );
477 {
478 // Make the panel for the client
479 Destroy_ptr<EffectPanel> uw{ safenew EffectPanel( S.GetParent() ) };
480 RTL_WORKAROUND(uw.get());
481
482 // Try to give the window a sensible default/minimum size
483 uw->SetMinSize(wxSize(wxMax(600, mParent->GetSize().GetWidth() * 2 / 3),
484 mParent->GetSize().GetHeight() / 2));
485
486 // Let the client add things to the panel
487 ShuttleGui S1{ uw.get(), eIsCreating };
489 if (!mpValidator)
490 return false;
491
492 S.Prop( 1 )
493 .Position(wxEXPAND)
494 .AddWindow((w = uw.release()));
495 }
496 S.EndHorizontalLay();
497
498 S.StartPanel();
499 {
500 const auto bar = BuildButtonBar( S.GetParent() );
501
502 long buttons;
504 buttons = eApplyButton | eCloseButton;
505 this->SetAcceleratorTable(wxNullAcceleratorTable);
506 }
507 else {
509 wxAcceleratorEntry entries[1];
510#if defined(__WXMAC__)
511 // Is there a standard shortcut on Mac?
512#else
513 entries[0].Set(wxACCEL_NORMAL, (int) WXK_F1, wxID_HELP);
514#endif
515 wxAcceleratorTable accel(1, entries);
516 this->SetAcceleratorTable(accel);
517 }
518
520 buttons |= eDebugButton;
521
522 S.AddStandardButtons(buttons, bar);
523 }
524 S.EndPanel();
525 }
526
527 Layout();
528 Fit();
529 Center();
530
531 mApplyBtn = (wxButton *) FindWindow(wxID_APPLY);
532 mCloseBtn = (wxButton *) FindWindow(wxID_CANCEL);
533
535
536 w->SetAccept(!mIsGUI);
537 (!mIsGUI ? w : FindWindow(wxID_APPLY))->SetFocus();
538
540
541 SetMinSize(GetSize());
542 return true;
543}
544
545void EffectUIHost::OnInitDialog(wxInitDialogEvent & evt)
546{
547 // Do default handling
548 wxDialogWrapper::OnInitDialog(evt);
549
550#if wxCHECK_VERSION(3, 0, 0)
551 //#warning "check to see if this still needed in wx3"
552#endif
553
554 // Pure hackage coming down the pike...
555 //
556 // I have no idea why, but if a wxTextCtrl is the first control in the
557 // panel, then its contents will not be automatically selected when the
558 // dialog is displayed.
559 //
560 // So, we do the selection manually.
561 wxTextCtrl *focused = wxDynamicCast(FindFocus(), wxTextCtrl);
562 if (focused)
563 {
564 focused->SelectAll();
565 }
566}
567
568void EffectUIHost::OnErase(wxEraseEvent & WXUNUSED(evt))
569{
570 // Ignore it
571}
572
573void EffectUIHost::OnPaint(wxPaintEvent & WXUNUSED(evt))
574{
575 wxPaintDC dc(this);
576
577 dc.Clear();
578}
579
580void EffectUIHost::OnClose(wxCloseEvent & WXUNUSED(evt))
581{
582 DoCancel();
583
585
586 Hide();
587
588 mSuspensionScope.reset();
589 mpValidator.reset();
590
591 Destroy();
592#if wxDEBUG_LEVEL
593 mClosed = true;
594#endif
595}
596
597void EffectUIHost::OnApply(wxCommandEvent & evt)
598{
599 auto &project = mProject;
600
601 // On wxGTK (wx2.8.12), the default action is still executed even if
602 // the button is disabled. This appears to affect all wxDialogs, not
603 // just our Effects dialogs. So, this is a only temporary workaround
604 // for legacy effects that disable the OK button. Hopefully this has
605 // been corrected in wx3.
606 if (!FindWindow(wxID_APPLY)->IsEnabled())
607 {
608 return;
609 }
610
611 // Honor the "select all if none" preference...a little hackish, but whatcha gonna do...
612 if (!mIsBatch &&
616 {
617 auto flags = AlwaysEnabledFlag;
618 bool allowed =
621 flags,
623 if (!allowed)
624 return;
625 }
626
627 if (!TransferDataFromWindow() ||
628 // This is the main place where there is a side-effect on the config
629 // file to remember the last-used settings of an effect, just before
630 // applying the effect destructively.
633 return;
634
635 if (IsModal())
636 {
637 mDismissed = true;
638
639 EndModal(evt.GetId());
640
641 Close();
642
643 return;
644 }
645
646 // Progress dialog no longer yields, so this "shouldn't" be necessary (yet to be proven
647 // for sure), but it is a nice visual cue that something is going on.
648 mApplyBtn->Disable();
649 auto cleanup = finally( [&] { mApplyBtn->Enable(); } );
650
651 CommandContext context( project );
652 // This is absolute hackage...but easy and I can't think of another way just now.
653 //
654 // It should callback to the EffectManager to kick off the processing
657}
658
660{
661 if (!mDismissed) {
662 if (IsModal())
663 EndModal(0);
664 else
665 Hide();
666
667 mDismissed = true;
668 }
669}
670
671void EffectUIHost::OnCancel(wxCommandEvent & WXUNUSED(evt))
672{
673 DoCancel();
674 Close();
675}
676
677void EffectUIHost::OnHelp(wxCommandEvent & WXUNUSED(event))
678{
680 // No manual page, so use help page
681
682 const auto &helpPage = mEffectUIHost.GetDefinition().HelpPage();
683 // It was guaranteed in Initialize() that there is no help
684 // button when neither manual nor help page is specified, so this
685 // event handler it not reachable in that case.
686 wxASSERT(!helpPage.empty());
687
688 // Old ShowHelp required when there is no on-line manual.
689 // Always use default web browser to allow full-featured HTML pages.
690 HelpSystem::ShowHelp(FindWindow(wxID_HELP), helpPage, wxEmptyString, true, true);
691 }
692 else {
693 // otherwise use the NEW ShowHelp
694 HelpSystem::ShowHelp(FindWindow(wxID_HELP), mEffectUIHost.GetDefinition().ManualPage(), true);
695 }
696}
697
698void EffectUIHost::OnDebug(wxCommandEvent & evt)
699{
700 OnApply(evt);
701}
702
703namespace {
705{
706 static const auto specialVersion = XO("n/a");
707 auto result = definition.GetVersion();
708 if (result == specialVersion.MSGID())
709 result = specialVersion.Translation();
710 return result;
711}
712}
713
714void EffectUIHost::OnMenu(wxCommandEvent & WXUNUSED(evt))
715{
716 wxMenu menu;
717 menu.Bind(wxEVT_MENU, [](auto&){}, kUserPresetsDummyID);
718 menu.Bind(wxEVT_MENU, [](auto&){}, kDeletePresetDummyID);
720
721 if (mUserPresets.size() == 0)
722 {
723 menu.Append(kUserPresetsDummyID, _("User Presets"))->Enable(false);
724 }
725 else
726 {
727 auto sub = std::make_unique<wxMenu>();
728 for (size_t i = 0, cnt = mUserPresets.size(); i < cnt; i++)
729 {
730 sub->Append(kUserPresetsID + i, mUserPresets[i]);
731 }
732 menu.Append(0, _("User Presets"), sub.release());
733 }
734
735 menu.Append(kSaveAsID, _("Save Preset..."));
736
737 if (mUserPresets.size() == 0)
738 {
739 menu.Append(kDeletePresetDummyID, _("Delete Preset"))->Enable(false);
740 }
741 else
742 {
743 auto sub = std::make_unique<wxMenu>();
744 for (size_t i = 0, cnt = mUserPresets.size(); i < cnt; i++)
745 {
746 sub->Append(kDeletePresetID + i, mUserPresets[i]);
747 }
748 menu.Append(0, _("Delete Preset"), sub.release());
749 }
750
751 menu.AppendSeparator();
752
754
755 {
756 auto sub = std::make_unique<wxMenu>();
757 sub->Append(kDefaultsID, _("Defaults"));
758 if (factory.size() > 0)
759 {
760 sub->AppendSeparator();
761 for (size_t i = 0, cnt = factory.size(); i < cnt; i++)
762 {
763 auto label = factory[i];
764 if (label.empty())
765 {
766 label = _("None");
767 }
768
769 sub->Append(kFactoryPresetsID + i, label);
770 }
771 }
772 menu.Append(0, _("Factory Presets"), sub.release());
773 }
774
775 menu.AppendSeparator();
776 menu.Append(kImportID, _("Import..."))->Enable(mClient.CanExportPresets());
777 menu.Append(kExportID, _("Export..."))->Enable(mClient.CanExportPresets());
778 menu.AppendSeparator();
779 menu.Append(kOptionsID, _("Options..."))->Enable(mClient.HasOptions());
780 menu.AppendSeparator();
781
782 {
783 auto sub = std::make_unique<wxMenu>();
784
785 auto &definition = mEffectUIHost.GetDefinition();
786 sub->Append(kDummyID, wxString::Format(_("Type: %s"),
787 ::wxGetTranslation( definition.GetFamily().Translation() )));
788 sub->Append(kDummyID, wxString::Format(_("Name: %s"), definition.GetName().Translation()));
789 sub->Append(kDummyID, wxString::Format(_("Version: %s"),
790 GetVersionForDisplay(definition)));
791 sub->Append(kDummyID, wxString::Format(_("Vendor: %s"), definition.GetVendor().Translation()));
792 sub->Append(kDummyID, wxString::Format(_("Description: %s"), definition.GetDescription().Translation()));
793 sub->Bind(wxEVT_MENU, [](auto&){}, kDummyID);
794
795 menu.Append(0, _("About"), sub.release());
796 }
797
798 wxWindow *btn = FindWindow(kMenuID);
799 wxRect r = btn->GetRect();
800 BasicMenu::Handle{ &menu }.Popup(
802 { r.GetLeft(), r.GetBottom() }
803 );
804}
805
806void EffectUIHost::OnEnable(wxCommandEvent & WXUNUSED(evt))
807{
808 mEnabled = mEnableCb->GetValue();
809
810 if (mEnabled)
811 mSuspensionScope.reset();
812 else
813 mSuspensionScope.emplace(AudioIO::Get()->SuspensionScope());
814
816}
817
818void EffectUIHost::OnPlay(wxCommandEvent & WXUNUSED(evt))
819{
821 {
823 return;
824
826
827 return;
828 }
829
830 if (mPlaying)
831 {
832 auto gAudioIO = AudioIO::Get();
833 mPlayPos = gAudioIO->GetStreamTime();
834 auto &projectAudioManager = ProjectAudioManager::Get( mProject );
835 projectAudioManager.Stop();
836 }
837 else
838 {
839 auto &viewInfo = ViewInfo::Get( mProject );
840 const auto &selectedRegion = viewInfo.selectedRegion;
841 const auto &playRegion = viewInfo.playRegion;
842 if ( playRegion.Active() )
843 {
844 mRegion.setTimes(playRegion.GetStart(), playRegion.GetEnd());
845 mPlayPos = mRegion.t0();
846 }
847 else if (selectedRegion.t0() != mRegion.t0() ||
848 selectedRegion.t1() != mRegion.t1())
849 {
850 mRegion = selectedRegion;
851 mPlayPos = mRegion.t0();
852 }
853
854 if (mPlayPos > mRegion.t1())
855 {
856 mPlayPos = mRegion.t1();
857 }
858
859 auto &projectAudioManager = ProjectAudioManager::Get( mProject );
860 projectAudioManager.PlayPlayRegion(
864 }
865}
866
867void EffectUIHost::OnRewind(wxCommandEvent & WXUNUSED(evt))
868{
869 if (mPlaying)
870 {
871 auto gAudioIO = AudioIO::Get();
872 double seek;
873 gPrefs->Read(wxT("/AudioIO/SeekShortPeriod"), &seek, 1.0);
874
875 double pos = gAudioIO->GetStreamTime();
876 if (pos - seek < mRegion.t0())
877 {
878 seek = pos - mRegion.t0();
879 }
880
881 gAudioIO->SeekStream(-seek);
882 }
883 else
884 {
885 mPlayPos = mRegion.t0();
886 }
887}
888
889void EffectUIHost::OnFFwd(wxCommandEvent & WXUNUSED(evt))
890{
891 if (mPlaying)
892 {
893 double seek;
894 gPrefs->Read(wxT("/AudioIO/SeekShortPeriod"), &seek, 1.0);
895
896 auto gAudioIO = AudioIO::Get();
897 double pos = gAudioIO->GetStreamTime();
898 if (mRegion.t0() < mRegion.t1() && pos + seek > mRegion.t1())
899 {
900 seek = mRegion.t1() - pos;
901 }
902
903 gAudioIO->SeekStream(seek);
904 }
905 else
906 {
907 // It allows to play past end of selection...probably useless
908 mPlayPos = mRegion.t1();
909 }
910}
911
913{
914 if (evt.on) {
915 if (evt.pProject != &mProject)
916 mDisableTransport = true;
917 else
918 mPlaying = true;
919 }
920 else {
921 mDisableTransport = false;
922 mPlaying = false;
923 }
924
925 if (mPlaying) {
927 mPlayPos = mRegion.t0();
928 }
930}
931
933{
934 if (evt.on) {
935 if (evt.pProject != &mProject)
936 mDisableTransport = true;
937 else
938 mCapturing = true;
939 }
940 else {
941 mDisableTransport = false;
942 mCapturing = false;
943 }
945}
946
947void EffectUIHost::OnUserPreset(wxCommandEvent & evt)
948{
949 int preset = evt.GetId() - kUserPresetsID;
950
951 mpAccess->ModifySettings([&](EffectSettings &settings){
953 .LoadUserPreset(UserPresetsGroup(mUserPresets[preset]), settings);
954 });
956 return;
957}
958
959void EffectUIHost::OnFactoryPreset(wxCommandEvent & evt)
960{
961 mpAccess->ModifySettings([&](EffectSettings &settings){
963 .LoadFactoryPreset(evt.GetId() - kFactoryPresetsID, settings);
964 });
966 return;
967}
968
969void EffectUIHost::OnDeletePreset(wxCommandEvent & evt)
970{
971 auto preset = mUserPresets[evt.GetId() - kDeletePresetID];
972
973 int res = AudacityMessageBox(
974 XO("Are you sure you want to delete \"%s\"?").Format( preset ),
975 XO("Delete Preset"),
976 wxICON_QUESTION | wxYES_NO);
977 if (res == wxYES)
978 {
981 }
982
984
985 return;
986}
987
988void EffectUIHost::OnSaveAs(wxCommandEvent & WXUNUSED(evt))
989{
990 wxTextCtrl *text;
991 wxString name;
992 wxDialogWrapper dlg(this, wxID_ANY, XO("Save Preset"));
993
994 ShuttleGui S(&dlg, eIsCreating);
995
996 S.StartPanel();
997 {
998 S.StartVerticalLay(1);
999 {
1000 S.StartHorizontalLay(wxALIGN_LEFT, 0);
1001 {
1002 text = S.AddTextBox(XXO("Preset name:"), name, 30);
1003 }
1004 S.EndHorizontalLay();
1005 S.SetBorder(10);
1006 S.AddStandardButtons();
1007 }
1008 S.EndVerticalLay();
1009 }
1010 S.EndPanel();
1011
1012 dlg.SetSize(dlg.GetSizer()->GetMinSize());
1013 dlg.Center();
1014 dlg.Fit();
1015
1016 while (true)
1017 {
1018 int rc = dlg.ShowModal();
1019
1020 if (rc != wxID_OK)
1021 {
1022 break;
1023 }
1024
1025 name = text->GetValue();
1026 if (name.empty())
1027 {
1029 this,
1030 XO("You must specify a name"),
1031 XO("Save Preset") );
1032 md.Center();
1033 md.ShowModal();
1034 continue;
1035 }
1036
1037 if ( make_iterator_range( mUserPresets ).contains( name ) )
1038 {
1040 this,
1041 XO("Preset already exists.\n\nReplace?"),
1042 XO("Save Preset"),
1043 wxYES_NO | wxCANCEL | wxICON_EXCLAMATION );
1044 md.Center();
1045 int choice = md.ShowModal();
1046 if (choice == wxID_CANCEL)
1047 {
1048 break;
1049 }
1050
1051 if (choice == wxID_NO)
1052 {
1053 continue;
1054 }
1055 }
1056
1061
1062 break;
1063 }
1064
1065 return;
1066}
1067
1068void EffectUIHost::OnImport(wxCommandEvent & WXUNUSED(evt))
1069{
1070 mpAccess->ModifySettings([&](EffectSettings &settings){
1072 });
1075
1076 return;
1077}
1078
1079void EffectUIHost::OnExport(wxCommandEvent & WXUNUSED(evt))
1080{
1081 // may throw
1082 // exceptions are handled in AudacityApp::OnExceptionInMainLoop
1085
1086 return;
1087}
1088
1089void EffectUIHost::OnOptions(wxCommandEvent & WXUNUSED(evt))
1090{
1092
1093 return;
1094}
1095
1096void EffectUIHost::OnDefaults(wxCommandEvent & WXUNUSED(evt))
1097{
1098 mpAccess->ModifySettings([&](EffectSettings &settings){
1099 mEffectUIHost.GetDefinition().LoadFactoryDefaults(settings);
1100 });
1102 return;
1103}
1104
1105wxBitmap EffectUIHost::CreateBitmap(const char * const xpm[], bool up, bool pusher)
1106{
1107 wxMemoryDC dc;
1108 wxBitmap pic(xpm);
1109
1110 wxBitmap mod(pic.GetWidth() + 6, pic.GetHeight() + 6, 24);
1111 dc.SelectObject(mod);
1112
1113#if defined(__WXGTK__)
1114 wxColour newColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BACKGROUND);
1115#else
1116 wxColour newColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
1117#endif
1118
1119 dc.SetBackground(wxBrush(newColour));
1120 dc.Clear();
1121
1122 int offset = 3;
1123 if (pusher)
1124 {
1125 if (!up)
1126 {
1127 offset += 1;
1128 }
1129 }
1130
1131 dc.DrawBitmap(pic, offset, offset, true);
1132
1133 dc.SelectObject(wxNullBitmap);
1134
1135 return mod;
1136}
1137
1139{
1140 if (mIsBatch)
1141 {
1142 return;
1143 }
1144
1146 {
1147 // Don't allow focus to get trapped
1148 wxWindow *focus = FindFocus();
1149 if (focus == mRewindBtn || focus == mFFwdBtn || focus == mPlayBtn || focus == mEnableCb)
1150 {
1151 mCloseBtn->SetFocus();
1152 }
1153 }
1154
1155 mApplyBtn->Enable(!mCapturing);
1158 {
1160 }
1161
1163 {
1165 mFFwdBtn->Enable(!(mCapturing || mDisableTransport));
1166 mEnableCb->Enable(!(mCapturing || mDisableTransport));
1167
1168 wxBitmapButton *bb;
1169
1170 if (mPlaying)
1171 {
1172 if (!mIsGUI)
1173 {
1174 /* i18n-hint: The access key "&P" should be the same in
1175 "Stop &Playback" and "Start &Playback" */
1176 mPlayToggleBtn->SetLabel(_("Stop &Playback"));
1177 mPlayToggleBtn->Refresh();
1178 }
1179 else
1180 {
1181 bb = (wxBitmapButton *) mPlayBtn;
1182 bb->SetBitmapLabel(mStopBM);
1183 bb->SetBitmapDisabled(mStopDisabledBM);
1184 bb->SetToolTip(_("Stop"));
1185#if defined(__WXMAC__)
1186 bb->SetName(_("Stop &Playback"));
1187#else
1188 bb->SetLabel(_("Stop &Playback"));
1189#endif
1190 }
1191 }
1192 else
1193 {
1194 if (!mIsGUI)
1195 {
1196 /* i18n-hint: The access key "&P" should be the same in
1197 "Stop &Playback" and "Start &Playback" */
1198 mPlayToggleBtn->SetLabel(_("Start &Playback"));
1199 mPlayToggleBtn->Refresh();
1200 }
1201 else
1202 {
1203 bb = (wxBitmapButton *) mPlayBtn;
1204 bb->SetBitmapLabel(mPlayBM);
1205 bb->SetBitmapDisabled(mPlayDisabledBM);
1206 bb->SetToolTip(_("Play"));
1207#if defined(__WXMAC__)
1208 bb->SetName(_("Start &Playback"));
1209#else
1210 bb->SetLabel(_("Start &Playback"));
1211#endif
1212 }
1213 }
1214 }
1215}
1216
1218{
1219 mUserPresets.clear();
1220
1223
1224 std::sort( mUserPresets.begin(), mUserPresets.end() );
1225
1226 return;
1227}
1228
1229std::shared_ptr<EffectInstance> EffectUIHost::InitializeInstance()
1230{
1231 // We are still constructing and the return initializes a const member
1232 std::shared_ptr<EffectInstance> result;
1233
1234 bool priorState = (mpState != nullptr);
1235 if (!priorState) {
1236 auto gAudioIO = AudioIO::Get();
1237 mDisableTransport = !gAudioIO->IsAvailable(mProject);
1238 mPlaying = gAudioIO->IsStreamActive(); // not exactly right, but will suffice
1239 mCapturing = gAudioIO->IsStreamActive() && gAudioIO->GetNumCaptureChannels() > 0 && !gAudioIO->IsMonitoring();
1240 }
1241
1243 if (!priorState)
1244 mpState =
1246 if (mpState) {
1247 // Find the right instance to connect to the dialog
1248 if (!result) {
1249 result = mpState->GetInstance();
1250 if (result && !result->Init())
1251 result.reset();
1252 }
1253
1254 mpAccess2 = mpState->GetAccess();
1255 if (!(mpAccess2->IsSameAs(*mpAccess)))
1256 // Decorate the given access object
1257 mpAccess = std::make_shared<EffectSettingsAccessTee>(
1259 }
1260 if (!priorState) {
1262 switch (event.type) {
1263 case AudioIOEvent::PLAYBACK:
1264 OnPlayback(event); break;
1265 case AudioIOEvent::CAPTURE:
1266 OnCapture(event); break;
1267 default:
1268 break;
1269 }
1270 });
1271 }
1272
1273 mInitialized = true;
1274 }
1275 else {
1276 result = mEffectUIHost.MakeInstance();
1277 if (result && !result->Init())
1278 result.reset();
1279 }
1280
1281 return result;
1282}
1283
1285{
1286 bool noPriorState(mSubscription);
1289 if (noPriorState && mpState) {
1291 mpState.reset();
1292 /*
1293 ProjectHistory::Get(mProject).PushState(
1294 XO("Removed %s effect").Format(mpState->GetEffect()->GetName()),
1295 XO("Removed Effect"),
1296 UndoPush::NONE
1297 );
1298 */
1299 }
1300 mInitialized = false;
1301 }
1302}
1303
1304wxDialog *EffectUI::DialogFactory( wxWindow &parent,
1305 EffectPlugin &host,
1307 std::shared_ptr<EffectInstance> &pInstance,
1308 EffectSettingsAccess &access)
1309{
1310 // Make sure there is an associated project, whose lifetime will
1311 // govern the lifetime of the dialog, even when the dialog is
1312 // non-modal, as for realtime effects
1313 auto project = FindProjectFromWindow(&parent);
1314 if ( !project )
1315 return nullptr;
1317 *project, host, client, pInstance, access } };
1318 if (dlg->Initialize())
1319 // release() is safe because parent will own it
1320 return dlg.release();
1321 return nullptr;
1322}
1323
1324#include "PluginManager.h"
1325#include "ProjectRate.h"
1326#include "../ProjectWindow.h"
1327#include "../SelectUtilities.h"
1328#include "../TrackPanel.h"
1329#include "../WaveTrack.h"
1330#include "../commands/CommandManager.h"
1331
1335// parameters, whether to save the state to history and whether to allow
1337
1338/* static */ bool EffectUI::DoEffect(
1339 const PluginID & ID, const CommandContext &context, unsigned flags )
1340{
1341 AudacityProject &project = context.project;
1342 auto &tracks = TrackList::Get( project );
1343 auto &trackPanel = TrackPanel::Get( project );
1344 auto &trackFactory = WaveTrackFactory::Get( project );
1345 auto rate = ProjectRate::Get(project).GetRate();
1346 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
1347 auto &commandManager = CommandManager::Get( project );
1348 auto &window = ProjectWindow::Get( project );
1349
1350 const PluginDescriptor *plug = PluginManager::Get().GetPlugin(ID);
1351 if (!plug)
1352 return false;
1353
1354 EffectType type = plug->GetEffectType();
1355
1356 // Make sure there's no activity since the effect is about to be applied
1357 // to the project's tracks. Mainly for Apply during RTP, but also used
1358 // for batch commands
1359 if (flags & EffectManager::kConfigured)
1360 {
1361 ProjectAudioManager::Get( project ).Stop();
1362 //Don't Select All if repeating Generator Effect
1363 if (!(flags & EffectManager::kConfigured)) {
1365 }
1366 }
1367
1368 auto nTracksOriginally = tracks.size();
1369 wxWindow *focus = wxWindow::FindFocus();
1370 wxWindow *parent = nullptr;
1371 if (focus != nullptr) {
1372 parent = focus->GetParent();
1373 }
1374
1375 bool success = false;
1376 auto cleanup = finally( [&] {
1377
1378 if (!success) {
1379 // For now, we're limiting realtime preview to a single effect, so
1380 // make sure the menus reflect that fact that one may have just been
1381 // opened.
1382 MenuManager::Get(project).UpdateMenus( false );
1383 }
1384
1385 } );
1386
1387 int count = 0;
1388 bool clean = true;
1389 for (auto t : tracks.Selected< const WaveTrack >()) {
1390 if (t->GetEndTime() != 0.0)
1391 clean = false;
1392 count++;
1393 }
1394
1396
1397 em.SetSkipStateFlag( false );
1398 success = false;
1399 if (auto effect = em.GetEffect(ID)) {
1400 if (const auto pSettings = em.GetDefaultSettings(ID)) {
1401 const auto pAccess =
1402 std::make_shared<SimpleEffectSettingsAccess>(*pSettings);
1403 pAccess->ModifySettings([&](EffectSettings &settings){
1404 success = effect->DoEffect(settings,
1405 rate,
1406 &tracks,
1407 &trackFactory,
1408 selectedRegion,
1409 flags,
1410 &window,
1411 (flags & EffectManager::kConfigured) == 0
1413 : nullptr,
1414 pAccess);
1415 });
1416 }
1417 }
1418
1419 if (!success)
1420 return false;
1421
1422 if (em.GetSkipStateFlag())
1423 flags = flags | EffectManager::kSkipState;
1424
1425 if (!(flags & EffectManager::kSkipState))
1426 {
1427 auto shortDesc = em.GetCommandName(ID);
1428 auto longDesc = em.GetCommandDescription(ID);
1429 ProjectHistory::Get( project ).PushState(longDesc, shortDesc);
1430 }
1431
1432 if (!(flags & EffectManager::kDontRepeatLast))
1433 {
1434 // Remember a successful generator, effect, analyzer, or tool Process
1435 auto shortDesc = em.GetCommandName(ID);
1436 /* i18n-hint: %s will be the name of the effect which will be
1437 * repeated if this menu item is chosen */
1438 auto lastEffectDesc = XO("Repeat %s").Format(shortDesc);
1439 auto& menuManager = MenuManager::Get(project);
1440 switch ( type ) {
1441 case EffectTypeGenerate:
1442 commandManager.Modify(wxT("RepeatLastGenerator"), lastEffectDesc);
1443 menuManager.mLastGenerator = ID;
1444 menuManager.mRepeatGeneratorFlags = EffectManager::kConfigured;
1445 break;
1446 case EffectTypeProcess:
1447 commandManager.Modify(wxT("RepeatLastEffect"), lastEffectDesc);
1448 menuManager.mLastEffect = ID;
1449 menuManager.mRepeatEffectFlags = EffectManager::kConfigured;
1450 break;
1451 case EffectTypeAnalyze:
1452 commandManager.Modify(wxT("RepeatLastAnalyzer"), lastEffectDesc);
1453 menuManager.mLastAnalyzer = ID;
1454 menuManager.mLastAnalyzerRegistration = MenuCreator::repeattypeplugin;
1455 menuManager.mRepeatAnalyzerFlags = EffectManager::kConfigured;
1456 break;
1457 case EffectTypeTool:
1458 commandManager.Modify(wxT("RepeatLastTool"), lastEffectDesc);
1459 menuManager.mLastTool = ID;
1460 menuManager.mLastToolRegistration = MenuCreator::repeattypeplugin;
1461 menuManager.mRepeatToolFlags = EffectManager::kConfigured;
1462 if (shortDesc == NYQUIST_PROMPT_NAME) {
1463 menuManager.mRepeatToolFlags = EffectManager::kRepeatNyquistPrompt; //Nyquist Prompt is not configured
1464 }
1465 break;
1466 }
1467 }
1468
1469 //STM:
1470 //The following automatically re-zooms after sound was generated.
1471 // IMO, it was disorienting, removing to try out without re-fitting
1472 //mchinen:12/14/08 reapplying for generate effects
1473 if (type == EffectTypeGenerate)
1474 {
1475 if (count == 0 || (clean && selectedRegion.t0() == 0.0))
1476 window.DoZoomFit();
1477 // trackPanel->Refresh(false);
1478 }
1479
1480 // PRL: RedrawProject explicitly because sometimes history push is skipped
1481 window.RedrawProject();
1482
1483 if (focus != nullptr && focus->GetParent()==parent) {
1484 focus->SetFocus();
1485 }
1486
1487 // A fix for Bug 63
1488 // New tracks added? Scroll them into view so that user sees them.
1489 // Don't care what track type. An analyser might just have added a
1490 // Label track and we want to see it.
1491 if( tracks.size() > nTracksOriginally ){
1492 // 0.0 is min scroll position, 1.0 is max scroll position.
1493 trackPanel.VerticalScroll( 1.0 );
1494 }
1495 else {
1496 auto pTrack = *tracks.Selected().begin();
1497 if (!pTrack)
1498 pTrack = *tracks.Any().begin();
1499 if (pTrack) {
1500 TrackFocus::Get(project).Set(pTrack);
1501 pTrack->EnsureVisible();
1502 }
1503 }
1504
1505 return true;
1506}
1507
1509BEGIN_EVENT_TABLE(EffectDialog, wxDialogWrapper)
1512
1513EffectDialog::EffectDialog(wxWindow * parent,
1514 const TranslatableString & title,
1515 int type,
1516 int flags,
1517 int additionalButtons)
1518: wxDialogWrapper(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, flags)
1519{
1520 mType = type;
1521 mAdditionalButtons = additionalButtons;
1522}
1523
1525{
1526 long buttons = eOkButton;
1528 {
1529 buttons |= eCancelButton;
1530 if (mType == EffectTypeProcess)
1531 {
1532 buttons |= ePreviewButton;
1533 }
1534 }
1535
1536 ShuttleGui S(this, eIsCreating);
1537
1538 S.SetBorder(5);
1539 S.StartVerticalLay(true);
1540 {
1542 S.AddStandardButtons(buttons|mAdditionalButtons);
1543 }
1544 S.EndVerticalLay();
1545
1546 Layout();
1547 Fit();
1548 SetMinSize(GetSize());
1549 Center();
1550}
1551
1556{
1557 return;
1558}
1559
1561{
1564
1565 return true;
1566}
1567
1569{
1572
1573 return true;
1574}
1575
1577{
1578 return true;
1579}
1580
1581void EffectDialog::OnPreview(wxCommandEvent & WXUNUSED(evt))
1582{
1583 return;
1584}
1585
1586void EffectDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
1587{
1588 // On wxGTK (wx2.8.12), the default action is still executed even if
1589 // the button is disabled. This appears to affect all wxDialogs, not
1590 // just our Effects dialogs. So, this is a only temporary workaround
1591 // for legacy effects that disable the OK button. Hopefully this has
1592 // been corrected in wx3.
1593 if (FindWindow(wxID_OK)->IsEnabled() && Validate() && TransferDataFromWindow())
1594 {
1595 EndModal(wxID_OK);
1596 }
1597
1598 return;
1599}
1600
1602#include "RealtimeEffectState.h"
1603static RealtimeEffectState::EffectFactory::Scope
1605
1606/* The following registration objects need a home at a higher level to avoid
1607 dependency either way between WaveTrack or RealtimeEffectList, which need to
1608 be in different libraries that do not depend either on the other.
1609
1610 WaveTrack, like AudacityProject, has a registry for attachment of serializable
1611 data. RealtimeEffectList exposes an interface for serialization. This is
1612 where we connect them.
1613 */
1614#include "RealtimeEffectList.h"
1617 [](AudacityProject &project) { return &RealtimeEffectList::Get(project); }
1618};
1619
1621[](const AudacityProject &project, XMLWriter &xmlFile){
1622 RealtimeEffectList::Get(project).WriteXML(xmlFile);
1623} };
1624
1627 [](WaveTrack &track) { return &RealtimeEffectList::Get(track); }
1628};
1629
1631[](const WaveTrack &track, auto &xmlFile) {
1632 if (track.IsLeader())
1633 RealtimeEffectList::Get(track).WriteXML(xmlFile);
1634} };
EVT_MENU(OnSetPlayRegionToSelectionID, AdornedRulerPanel::OnSetPlayRegionToSelection) EVT_COMMAND(OnTogglePinnedStateID
EVT_MENU_RANGE(FileHistory::ID_RECENT_FIRST, FileHistory::ID_RECENT_LAST, AudacityApp::OnMRUFile) bool AudacityApp
IMPLEMENT_WX_THEME_SUPPORT int main(int argc, char *argv[])
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
static RegisteredToolbarFactory factory
Abstractions of menus and their items.
END_EVENT_TABLE()
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:35
const ReservedCommandFlag & TimeSelectedFlag()
const ReservedCommandFlag & WaveTracksSelectedFlag()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
Definition: Distortion.cpp:82
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:29
static ProjectFileIORegistry::ObjectReaderEntry projectAccessor
Definition: EffectUI.cpp:1615
static ProjectFileIORegistry::ObjectWriterEntry projectWriter
Definition: EffectUI.cpp:1620
static const int kImportID
Definition: EffectUI.cpp:119
static const int kExportID
Definition: EffectUI.cpp:120
static WaveTrackIORegistry::ObjectWriterEntry waveTrackWriter
Definition: EffectUI.cpp:1630
static const int kOptionsID
Definition: EffectUI.cpp:122
static const int kCaptureID
Definition: EffectUI.cpp:131
static RealtimeEffectState::EffectFactory::Scope scope
Inject a factory for realtime effects.
Definition: EffectUI.cpp:1604
static const int kDefaultsID
Definition: EffectUI.cpp:121
static const int kFFwdID
Definition: EffectUI.cpp:129
static const int kDummyID
Definition: EffectUI.cpp:117
static const int kPlaybackID
Definition: EffectUI.cpp:130
static WaveTrackIORegistry::ObjectReaderEntry waveTrackAccessor
Definition: EffectUI.cpp:1625
static const int kRewindID
Definition: EffectUI.cpp:128
static const int kPlayID
Definition: EffectUI.cpp:127
static const int kSaveAsID
Definition: EffectUI.cpp:118
static const int kUserPresetsDummyID
Definition: EffectUI.cpp:123
static const int kFactoryPresetsID
Definition: EffectUI.cpp:134
static const int kEnableID
Definition: EffectUI.cpp:126
static const int kMenuID
Definition: EffectUI.cpp:125
static const int kDeletePresetDummyID
Definition: EffectUI.cpp:124
static const int kUserPresetsID
Definition: EffectUI.cpp:132
static const int kDeletePresetID
Definition: EffectUI.cpp:133
#define RTL_WORKAROUND(pWnd)
Definition: GUISettings.h:20
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
#define safenew
Definition: MemoryX.h:10
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:423
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
FileConfig * gPrefs
Definition: Prefs.cpp:71
AudioIOStartStreamOptions DefaultPlayOptions(AudacityProject &project, bool newDefault)
an object holding per-project preferred sample rate
static ProjectFileIORegistry::AttributeReaderEntries entries
AudacityProject * FindProjectFromWindow(wxWindow *pWindow)
EffectReverbSettings preset
Definition: Reverb.cpp:46
@ eIsSettingToDialog
Definition: ShuttleGui.h:41
@ eIsCreating
Definition: ShuttleGui.h:39
@ eIsGettingFromDialog
Definition: ShuttleGui.h:40
@ eDebugID
Definition: ShuttleGui.h:616
@ eOkButton
Definition: ShuttleGui.h:597
@ eApplyButton
Definition: ShuttleGui.h:606
@ eCancelButton
Definition: ShuttleGui.h:598
@ eCloseButton
Definition: ShuttleGui.h:607
@ eHelpButton
Definition: ShuttleGui.h:601
@ ePreviewButton
Definition: ShuttleGui.h:602
@ eDebugButton
Definition: ShuttleGui.h:603
TranslatableString label
Definition: TagsEditor.cpp:163
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:87
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:89
static AudioIO * Get()
Definition: AudioIO.cpp:133
void RemoveState(AudacityProject &project, Track *pTrack, const std::shared_ptr< RealtimeEffectState > &pState)
Forwards to RealtimeEffectManager::RemoveState with proper init scope.
Definition: AudioIO.cpp:360
std::shared_ptr< RealtimeEffectState > AddState(AudacityProject &project, Track *pTrack, const PluginID &id)
Forwards to RealtimeEffectManager::AddState with proper init scope.
Definition: AudioIO.cpp:351
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.
virtual FilePath HelpPage() const
Fully qualified local help file name, default is empty.
virtual ManualPageID ManualPage() const
Name of a page in the Audacity alpha manual, default is empty.
bool Validate() override
Definition: EffectUI.cpp:1576
bool TransferDataToWindow() override
Definition: EffectUI.cpp:1560
bool TransferDataFromWindow() override
Definition: EffectUI.cpp:1568
virtual void OnPreview(wxCommandEvent &evt)
Definition: EffectUI.cpp:1581
virtual void OnOk(wxCommandEvent &evt)
Definition: EffectUI.cpp:1586
virtual void PopulateOrExchange(ShuttleGui &S)
Definition: EffectUI.cpp:1555
int mAdditionalButtons
Definition: EffectUI.h:202
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:53
void SetAccept(bool accept)
Definition: EffectUI.cpp:75
bool AcceptsFocus() const override
Definition: EffectUI.cpp:61
bool AcceptsFocusFromKeyboard() const override
Definition: EffectUI.cpp:67
EffectPanel(wxWindow *parent)
Definition: EffectUI.cpp:43
bool mAcceptsFocus
Definition: EffectUI.cpp:81
Factory of instances of an effect and of dialogs to control them.
Definition: EffectPlugin.h:52
virtual bool TransferDataToWindow(const EffectSettings &settings)=0
Update controls for the settings.
virtual bool TransferDataFromWindow(EffectSettings &settings)=0
Update the given settings from controls.
virtual const EffectSettingsManager & GetDefinition() const =0
virtual bool IsBatchProcessing() const =0
virtual void Preview(EffectSettingsAccess &access, bool dryOnly)=0
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.
EffectUIClientInterface is an abstract base class to populate a UI and validate UI values....
virtual void ImportPresets(EffectSettings &settings)=0
virtual void ShowOptions()=0
virtual bool IsGraphicalUI()=0
virtual void ExportPresets(const EffectSettings &settings) const =0
virtual std::unique_ptr< EffectUIValidator > PopulateUI(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access)=0
Adds controls to a panel that is given as the parent window of S
virtual bool CanExportPresets()=0
virtual bool HasOptions()=0
EffectPlugin & mEffectUIHost
Definition: EffectUI.h:104
void OnEnable(wxCommandEvent &evt)
Definition: EffectUI.cpp:806
void OnFactoryPreset(wxCommandEvent &evt)
Definition: EffectUI.cpp:959
RegistryPaths mUserPresets
Definition: EffectUI.h:113
void OnDefaults(wxCommandEvent &evt)
Definition: EffectUI.cpp:1096
wxBitmap mStopDisabledBM
Definition: EffectUI.h:133
void OnHelp(wxCommandEvent &evt)
Definition: EffectUI.cpp:677
wxPanel * BuildButtonBar(wxWindow *parent)
Definition: EffectUI.cpp:332
void UpdateControls()
Definition: EffectUI.cpp:1138
bool mIsBatch
Definition: EffectUI.h:117
bool mCapturing
Definition: EffectUI.h:139
std::optional< RealtimeEffects::SuspensionScope > mSuspensionScope
Definition: EffectUI.h:145
wxButton * mMenuBtn
Definition: EffectUI.h:121
virtual ~EffectUIHost()
Definition: EffectUI.cpp:246
std::unique_ptr< EffectUIValidator > mpValidator
Definition: EffectUI.h:111
std::shared_ptr< RealtimeEffectState > mpState
Definition: EffectUI.h:110
void OnErase(wxEraseEvent &evt)
Definition: EffectUI.cpp:568
void OnPlayback(AudioIOEvent)
Definition: EffectUI.cpp:912
void CleanupRealtime()
Definition: EffectUI.cpp:1284
AudacityProject & mProject
Definition: EffectUI.h:102
wxButton * mFFwdBtn
Definition: EffectUI.h:124
bool mIsGUI
Definition: EffectUI.h:116
bool TransferDataToWindow() override
Definition: EffectUI.cpp:255
wxButton * mPlayBtn
Definition: EffectUI.h:122
EffectPlugin::EffectSettingsAccessPtr mpAccess
Definition: EffectUI.h:108
void OnUserPreset(wxCommandEvent &evt)
Definition: EffectUI.cpp:947
void OnDeletePreset(wxCommandEvent &evt)
Definition: EffectUI.cpp:969
wxBitmap mPlayBM
Definition: EffectUI.h:130
bool mPlaying
Definition: EffectUI.h:138
wxButton * mPlayToggleBtn
Definition: EffectUI.h:128
int ShowModal() override
Definition: EffectUI.cpp:303
bool mDisableTransport
Definition: EffectUI.h:137
EffectUIClientInterface & mClient
Definition: EffectUI.h:105
wxBitmap mStopBM
Definition: EffectUI.h:132
SelectedRegion mRegion
Definition: EffectUI.h:141
void DoCancel()
Definition: EffectUI.cpp:659
Observer::Subscription mSubscription
Definition: EffectUI.h:100
void OnFFwd(wxCommandEvent &evt)
Definition: EffectUI.cpp:889
void OnCapture(AudioIOEvent)
Definition: EffectUI.cpp:932
double mPlayPos
Definition: EffectUI.h:142
void OnClose(wxCloseEvent &evt)
Definition: EffectUI.cpp:580
void OnExport(wxCommandEvent &evt)
Definition: EffectUI.cpp:1079
wxButton * mCloseBtn
Definition: EffectUI.h:120
void OnSaveAs(wxCommandEvent &evt)
Definition: EffectUI.cpp:988
wxButton * mApplyBtn
Definition: EffectUI.h:119
void OnOptions(wxCommandEvent &evt)
Definition: EffectUI.cpp:1089
void LoadUserPresets()
Definition: EffectUI.cpp:1217
void OnInitDialog(wxInitDialogEvent &evt)
Definition: EffectUI.cpp:545
EffectUIHost(wxWindow *parent, AudacityProject &project, EffectPlugin &effect, EffectUIClientInterface &client, std::shared_ptr< EffectInstance > &pInstance, EffectSettingsAccess &access, const std::shared_ptr< RealtimeEffectState > &pPriorState={})
Definition: EffectUI.cpp:212
void OnMenu(wxCommandEvent &evt)
Definition: EffectUI.cpp:714
void OnDebug(wxCommandEvent &evt)
Definition: EffectUI.cpp:698
bool mEnabled
Definition: EffectUI.h:135
void OnRewind(wxCommandEvent &evt)
Definition: EffectUI.cpp:867
EffectPlugin::EffectSettingsAccessPtr mpAccess2
Definition: EffectUI.h:109
void OnImport(wxCommandEvent &evt)
Definition: EffectUI.cpp:1068
wxCheckBox * mEnableCb
Definition: EffectUI.h:125
std::shared_ptr< EffectInstance > InitializeInstance()
Definition: EffectUI.cpp:1229
void OnApply(wxCommandEvent &evt)
Definition: EffectUI.cpp:597
const bool mSupportsRealtime
Definition: EffectUI.h:115
wxButton * mRewindBtn
Definition: EffectUI.h:123
bool Initialize()
Definition: EffectUI.cpp:469
void OnPlay(wxCommandEvent &evt)
Definition: EffectUI.cpp:818
const std::shared_ptr< EffectInstance > mpInstance
Definition: EffectUI.h:152
void OnCancel(wxCommandEvent &evt)
Definition: EffectUI.cpp:671
bool mInitialized
Definition: EffectUI.h:114
wxWindow *const mParent
Definition: EffectUI.h:103
wxBitmap CreateBitmap(const char *const xpm[], bool up, bool pusher)
Definition: EffectUI.cpp:1105
bool TransferDataFromWindow() override
Definition: EffectUI.cpp:265
void OnPaint(wxPaintEvent &evt)
Definition: EffectUI.cpp:573
bool mDismissed
Definition: EffectUI.h:144
wxBitmap mPlayDisabledBM
Definition: EffectUI.h:131
Abstract base class used in importing a file.
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:237
bool empty() const
Definition: Identifier.h:61
@ repeattypeplugin
Definition: Menus.h:62
static MenuManager & Get(AudacityProject &project)
Definition: Menus.cpp:71
bool ReportIfActionNotAllowed(const TranslatableString &Name, CommandFlag &flags, CommandFlag flagsRqd)
Definition: Menus.cpp:705
void UpdateMenus(bool checkActive=true)
Definition: Menus.cpp:643
bool isPoint() const
Definition: ViewInfo.h:39
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)
const PluginDescriptor * GetPlugin(const PluginID &ID) const
static PluginManager & Get()
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)
static RealtimeEffectList & Get(AudacityProject &project)
static const std::string & XMLTag()
void WriteXML(XMLWriter &xmlFile) const
Use only in the main thread, to avoid races.
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:628
Track * Get()
void EnsureVisible(bool modifyState=false)
Definition: Track.cpp:97
bool IsLeader() const
Definition: Track.cpp:405
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:486
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:230
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:216
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:2800
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:26
const std::weak_ptr< EffectSettingsAccess > mwSide
Definition: EffectUI.cpp:175
const std::shared_ptr< EffectSettingsAccess > mpMain
Definition: EffectUI.cpp:174
void Flush() override
Make the last Set changes "persistent" in underlying storage.
Definition: EffectUI.cpp:199
void Set(EffectSettings &&settings) override
Definition: EffectUI.cpp:191
bool IsSameAs(const EffectSettingsAccess &other) const override
Definition: EffectUI.cpp:206
void SetLabel(const TranslatableString &label)
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:26
AUDACITY_DLL_API bool DoEffect(const PluginID &ID, const CommandContext &context, unsigned flags)
'Repeat Last Effect'.
Definition: EffectUI.cpp:1338
AUDACITY_DLL_API wxDialog * DialogFactory(wxWindow &parent, EffectPlugin &host, EffectUIClientInterface &client, std::shared_ptr< EffectInstance > &pInstance, EffectSettingsAccess &access)
Definition: EffectUI.cpp:1304
bool RemoveConfigSubgroup(const EffectDefinitionInterface &ident, PluginSettings::ConfigurationType type, const RegistryPath &group)
bool GetConfigSubgroups(const EffectDefinitionInterface &ident, PluginSettings::ConfigurationType type, const RegistryPath &group, RegistryPaths &subgroups)
void SelectAllIfNone(AudacityProject &project)
wxString GetVersionForDisplay(const EffectDefinitionInterface &definition)
Definition: EffectUI.cpp:704
bool on
Definition: AudioIO.h:76
enum AudioIOEvent::Type type
AudacityProject * pProject
Definition: AudioIO.h:70
Externalized state of a plug-in.
Typically statically constructed.
Window placement information for wxWidgetsBasicUI can be constructed from a wxWindow pointer.