1 /**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 EffectManager.cpp
6
7 Audacity(R) is copyright (c) 1999-2008 Audacity Team.
8 License: GPL v2. See License.txt.
9
10 ******************************************************************//**
11
12 \class EffectManager
13 \brief EffectManager is the class that handles effects and effect categories.
14
15 It maintains a graph of effect categories and subcategories,
16 registers and unregisters effects and can return filtered lists of
17 effects.
18
19 *//*******************************************************************/
20
21
22 #include "EffectManager.h"
23
24 #include "Effect.h"
25
26 #include <algorithm>
27 #include <wx/tokenzr.h>
28
29 #include "../widgets/AudacityMessageBox.h"
30
31 #include "../ShuttleGetDefinition.h"
32 #include "../commands/CommandContext.h"
33 #include "../commands/AudacityCommand.h"
34 #include "../PluginManager.h"
35
36
37 /*******************************************************************************
38 Creates a singleton and returns reference
39
40 (Thread-safe...no active threading during construction or after destruction)
41 *******************************************************************************/
Get()42 EffectManager & EffectManager::Get()
43 {
44 static EffectManager em;
45 return em;
46 }
47
EffectManager()48 EffectManager::EffectManager()
49 {
50 mSkipStateFlag = false;
51 }
52
~EffectManager()53 EffectManager::~EffectManager()
54 {
55 }
56
57 // Here solely for the purpose of Nyquist Workbench until
58 // a better solution is devised.
RegisterEffect(std::unique_ptr<Effect> uEffect)59 const PluginID & EffectManager::RegisterEffect(std::unique_ptr<Effect> uEffect)
60 {
61 auto pEffect = uEffect.get();
62 const PluginID & ID =
63 PluginManager::Get().RegisterPlugin(std::move(uEffect), PluginTypeEffect);
64 mEffects[ID] = pEffect;
65 return ID;
66 }
67
68 // Here solely for the purpose of Nyquist Workbench until
69 // a better solution is devised.
UnregisterEffect(const PluginID & ID)70 void EffectManager::UnregisterEffect(const PluginID & ID)
71 {
72 PluginID id = ID;
73 PluginManager::Get().UnregisterPlugin(id);
74 mEffects.erase(id);
75 }
76
DoAudacityCommand(const PluginID & ID,const CommandContext & context,wxWindow * parent,bool shouldPrompt)77 bool EffectManager::DoAudacityCommand(const PluginID & ID,
78 const CommandContext &context,
79 wxWindow *parent,
80 bool shouldPrompt /* = true */)
81
82 {
83 this->SetSkipStateFlag(false);
84 AudacityCommand *command = GetAudacityCommand(ID);
85
86 if (!command)
87 {
88 return false;
89 }
90
91 bool res = command->DoAudacityCommand(parent, context, shouldPrompt);
92
93 return res;
94 }
95
GetCommandSymbol(const PluginID & ID)96 ComponentInterfaceSymbol EffectManager::GetCommandSymbol(const PluginID & ID)
97 {
98 return PluginManager::Get().GetSymbol(ID);
99 }
100
GetCommandName(const PluginID & ID)101 TranslatableString EffectManager::GetCommandName(const PluginID & ID)
102 {
103 return GetCommandSymbol(ID).Msgid();
104 }
105
GetEffectFamilyName(const PluginID & ID)106 TranslatableString EffectManager::GetEffectFamilyName(const PluginID & ID)
107 {
108 auto effect = GetEffect(ID);
109 if (effect)
110 return effect->GetFamily().Msgid();
111 return {};
112 }
113
GetVendorName(const PluginID & ID)114 TranslatableString EffectManager::GetVendorName(const PluginID & ID)
115 {
116 auto effect = GetEffect(ID);
117 if (effect)
118 return effect->GetVendor().Msgid();
119 return {};
120 }
121
GetCommandIdentifier(const PluginID & ID)122 CommandID EffectManager::GetCommandIdentifier(const PluginID & ID)
123 {
124 wxString name = PluginManager::Get().GetSymbol(ID).Internal();
125 return Effect::GetSquashedName(name);
126 }
127
GetCommandDescription(const PluginID & ID)128 TranslatableString EffectManager::GetCommandDescription(const PluginID & ID)
129 {
130 if (GetEffect(ID))
131 return XO("Applied effect: %s").Format( GetCommandName(ID) );
132 if (GetAudacityCommand(ID))
133 return XO("Applied command: %s").Format( GetCommandName(ID) );
134
135 return {};
136 }
137
GetCommandUrl(const PluginID & ID)138 ManualPageID EffectManager::GetCommandUrl(const PluginID & ID)
139 {
140 Effect* pEff = GetEffect(ID);
141 if( pEff )
142 return pEff->ManualPage();
143 AudacityCommand * pCom = GetAudacityCommand(ID);
144 if( pCom )
145 return pCom->ManualPage();
146
147 return wxEmptyString;
148 }
149
GetCommandTip(const PluginID & ID)150 TranslatableString EffectManager::GetCommandTip(const PluginID & ID)
151 {
152 Effect* pEff = GetEffect(ID);
153 if( pEff )
154 return pEff->GetDescription();
155 AudacityCommand * pCom = GetAudacityCommand(ID);
156 if( pCom )
157 return pCom->GetDescription();
158
159 return {};
160 }
161
162
GetCommandDefinition(const PluginID & ID,const CommandContext & context,int flags)163 void EffectManager::GetCommandDefinition(const PluginID & ID, const CommandContext & context, int flags)
164 {
165 ComponentInterface *command;
166 command = GetEffect(ID);
167 if( !command )
168 command = GetAudacityCommand( ID );
169 if( !command )
170 return;
171
172 ShuttleParams NullShuttle;
173 // Test if it defines any parameters at all.
174 bool bHasParams = command->DefineParams( NullShuttle );
175 if( (flags ==0) && !bHasParams )
176 return;
177
178 // This is capturing the output context into the shuttle.
179 ShuttleGetDefinition S( *context.pOutput.get()->mStatusTarget.get() );
180 S.StartStruct();
181 // using GET to expose a CommandID to the user!
182 // Macro command details are one place that we do expose Identifier
183 // to (more sophisticated) users
184 S.AddItem( GetCommandIdentifier( ID ).GET(), "id" );
185 S.AddItem( GetCommandName( ID ).Translation(), "name" );
186 if( bHasParams ){
187 S.StartField( "params" );
188 S.StartArray();
189 command->DefineParams( S );
190 S.EndArray();
191 S.EndField();
192 }
193 // use GET() to expose some details to macro programming users
194 S.AddItem( GetCommandUrl( ID ).GET(), "url" );
195 // The tip is a translated string!
196 S.AddItem( GetCommandTip( ID ).Translation(), "tip" );
197 S.EndStruct();
198 }
199
200
201
IsHidden(const PluginID & ID)202 bool EffectManager::IsHidden(const PluginID & ID)
203 {
204 Effect *effect = GetEffect(ID);
205
206 if (effect)
207 {
208 return effect->IsHidden();
209 }
210
211 return false;
212 }
213
SetSkipStateFlag(bool flag)214 void EffectManager::SetSkipStateFlag(bool flag)
215 {
216 mSkipStateFlag = flag;
217 }
218
GetSkipStateFlag()219 bool EffectManager::GetSkipStateFlag()
220 {
221 return mSkipStateFlag;
222 }
223
SupportsAutomation(const PluginID & ID)224 bool EffectManager::SupportsAutomation(const PluginID & ID)
225 {
226 const PluginDescriptor *plug = PluginManager::Get().GetPlugin(ID);
227 if (plug)
228 {
229 return plug->IsEffectAutomatable();
230 }
231
232 return false;
233 }
234
GetEffectParameters(const PluginID & ID)235 wxString EffectManager::GetEffectParameters(const PluginID & ID)
236 {
237 Effect *effect = GetEffect(ID);
238
239 if (effect)
240 {
241 wxString parms;
242
243 effect->GetAutomationParameters(parms);
244
245 // Some effects don't have automatable parameters and will not return
246 // anything, so try to get the active preset (current or factory).
247 if (parms.empty())
248 {
249 parms = GetDefaultPreset(ID);
250 }
251
252 return parms;
253 }
254
255 AudacityCommand *command = GetAudacityCommand(ID);
256
257 if (command)
258 {
259 wxString parms;
260
261 command->GetAutomationParameters(parms);
262
263 // Some effects don't have automatable parameters and will not return
264 // anything, so try to get the active preset (current or factory).
265 if (parms.empty())
266 {
267 parms = GetDefaultPreset(ID);
268 }
269
270 return parms;
271 }
272 return wxEmptyString;
273 }
274
SetEffectParameters(const PluginID & ID,const wxString & params)275 bool EffectManager::SetEffectParameters(const PluginID & ID, const wxString & params)
276 {
277 Effect *effect = GetEffect(ID);
278
279 if (effect)
280 {
281 CommandParameters eap(params);
282
283 if (eap.HasEntry(wxT("Use Preset")))
284 {
285 return effect->SetAutomationParameters(eap.Read(wxT("Use Preset")));
286 }
287
288 return effect->SetAutomationParameters(params);
289 }
290 AudacityCommand *command = GetAudacityCommand(ID);
291
292 if (command)
293 {
294 // Set defaults (if not initialised) before setting values.
295 command->Init();
296 CommandParameters eap(params);
297
298 if (eap.HasEntry(wxT("Use Preset")))
299 {
300 return command->SetAutomationParameters(eap.Read(wxT("Use Preset")));
301 }
302
303 return command->SetAutomationParameters(params);
304 }
305 return false;
306 }
307
PromptUser(const PluginID & ID,const EffectClientInterface::EffectDialogFactory & factory,wxWindow & parent)308 bool EffectManager::PromptUser(
309 const PluginID & ID,
310 const EffectClientInterface::EffectDialogFactory &factory, wxWindow &parent)
311 {
312 bool result = false;
313 Effect *effect = GetEffect(ID);
314
315 if (effect)
316 {
317 result = effect->ShowInterface(
318 parent, factory, effect->IsBatchProcessing() );
319 return result;
320 }
321
322 AudacityCommand *command = GetAudacityCommand(ID);
323
324 if (command)
325 {
326 result = command->PromptUser(&parent);
327 return result;
328 }
329
330 return result;
331 }
332
HasPresets(const PluginID & ID)333 bool EffectManager::HasPresets(const PluginID & ID)
334 {
335 Effect *effect = GetEffect(ID);
336
337 if (!effect)
338 {
339 return false;
340 }
341
342 return effect->GetUserPresets().size() > 0 ||
343 effect->GetFactoryPresets().size() > 0 ||
344 effect->HasCurrentSettings() ||
345 effect->HasFactoryDefaults();
346 }
347
348 #include <wx/choice.h>
349 #include <wx/listbox.h>
350 #include "../ShuttleGui.h"
351
352 namespace {
353
354 ///////////////////////////////////////////////////////////////////////////////
355 //
356 // EffectPresetsDialog
357 //
358 ///////////////////////////////////////////////////////////////////////////////
359
360 class EffectPresetsDialog final : public wxDialogWrapper
361 {
362 public:
363 EffectPresetsDialog(wxWindow *parent, Effect *effect);
364 virtual ~EffectPresetsDialog();
365
366 wxString GetSelected() const;
367 void SetSelected(const wxString & parms);
368
369 private:
370 void SetPrefix(const TranslatableString & type, const wxString & prefix);
371 void UpdateUI();
372
373 void OnType(wxCommandEvent & evt);
374 void OnOk(wxCommandEvent & evt);
375 void OnCancel(wxCommandEvent & evt);
376
377 private:
378 wxChoice *mType;
379 wxListBox *mPresets;
380
381 RegistryPaths mFactoryPresets;
382 RegistryPaths mUserPresets;
383 wxString mSelection;
384
385 DECLARE_EVENT_TABLE()
386 };
387
388 enum
389 {
390 ID_Type = 10000
391 };
392
BEGIN_EVENT_TABLE(EffectPresetsDialog,wxDialogWrapper)393 BEGIN_EVENT_TABLE(EffectPresetsDialog, wxDialogWrapper)
394 EVT_CHOICE(ID_Type, EffectPresetsDialog::OnType)
395 EVT_LISTBOX_DCLICK(wxID_ANY, EffectPresetsDialog::OnOk)
396 EVT_BUTTON(wxID_OK, EffectPresetsDialog::OnOk)
397 EVT_BUTTON(wxID_CANCEL, EffectPresetsDialog::OnCancel)
398 END_EVENT_TABLE()
399
400 EffectPresetsDialog::EffectPresetsDialog(wxWindow *parent, Effect *effect)
401 : wxDialogWrapper(parent, wxID_ANY, XO("Select Preset"))
402 {
403 ShuttleGui S(this, eIsCreating);
404 S.StartVerticalLay();
405 {
406 S.StartTwoColumn();
407 S.SetStretchyCol(1);
408 {
409 S.AddPrompt(XXO("Type:"));
410 mType = S.Id(ID_Type).AddChoice( {}, {}, 0 );
411
412 S.AddPrompt(XXO("&Preset:"));
413 mPresets = S
414 .Style( wxLB_SINGLE | wxLB_NEEDED_SB )
415 .AddListBox( {} );
416 }
417 S.EndTwoColumn();
418
419 S.AddStandardButtons();
420 }
421 S.EndVerticalLay();
422
423 mUserPresets = effect->GetUserPresets();
424 mFactoryPresets = effect->GetFactoryPresets();
425
426 if (mUserPresets.size() > 0)
427 {
428 mType->Append(_("User Presets"));
429 }
430
431 if (mFactoryPresets.size() > 0)
432 {
433 mType->Append(_("Factory Presets"));
434 }
435
436 if (effect->HasCurrentSettings())
437 {
438 mType->Append(_("Current Settings"));
439 }
440
441 if (effect->HasFactoryDefaults())
442 {
443 mType->Append(_("Factory Defaults"));
444 }
445
446 UpdateUI();
447 }
448
~EffectPresetsDialog()449 EffectPresetsDialog::~EffectPresetsDialog()
450 {
451 }
452
GetSelected() const453 wxString EffectPresetsDialog::GetSelected() const
454 {
455 return mSelection;
456 }
457
SetSelected(const wxString & parms)458 void EffectPresetsDialog::SetSelected(const wxString & parms)
459 {
460 wxString preset = parms;
461 if (preset.StartsWith(Effect::kUserPresetIdent))
462 {
463 preset.Replace(Effect::kUserPresetIdent, wxEmptyString, false);
464 SetPrefix(XO("User Presets"), preset);
465 }
466 else if (preset.StartsWith(Effect::kFactoryPresetIdent))
467 {
468 preset.Replace(Effect::kFactoryPresetIdent, wxEmptyString, false);
469 SetPrefix(XO("Factory Presets"), preset);
470 }
471 else if (preset.StartsWith(Effect::kCurrentSettingsIdent))
472 {
473 SetPrefix(XO("Current Settings"), wxEmptyString);
474 }
475 else if (preset.StartsWith(Effect::kFactoryDefaultsIdent))
476 {
477 SetPrefix(XO("Factory Defaults"), wxEmptyString);
478 }
479 }
480
SetPrefix(const TranslatableString & type,const wxString & prefix)481 void EffectPresetsDialog::SetPrefix(
482 const TranslatableString & type, const wxString & prefix)
483 {
484 mType->SetStringSelection(type.Translation());
485
486 if (type == XO("User Presets"))
487 {
488 mPresets->Clear();
489 for (const auto &preset : mUserPresets)
490 mPresets->Append(preset);
491 mPresets->Enable(true);
492 mPresets->SetStringSelection(prefix);
493 if (mPresets->GetSelection() == wxNOT_FOUND)
494 {
495 mPresets->SetSelection(0);
496 }
497 mSelection = Effect::kUserPresetIdent + mPresets->GetStringSelection();
498 }
499 else if (type == XO("Factory Presets"))
500 {
501 mPresets->Clear();
502 for (size_t i = 0, cnt = mFactoryPresets.size(); i < cnt; i++)
503 {
504 auto label = mFactoryPresets[i];
505 if (label.empty())
506 {
507 label = _("None");
508 }
509 mPresets->Append(label);
510 }
511 mPresets->Enable(true);
512 mPresets->SetStringSelection(prefix);
513 if (mPresets->GetSelection() == wxNOT_FOUND)
514 {
515 mPresets->SetSelection(0);
516 }
517 mSelection = Effect::kFactoryPresetIdent + mPresets->GetStringSelection();
518 }
519 else if (type == XO("Current Settings"))
520 {
521 mPresets->Clear();
522 mPresets->Enable(false);
523 mSelection = Effect::kCurrentSettingsIdent;
524 }
525 else if (type == XO("Factory Defaults"))
526 {
527 mPresets->Clear();
528 mPresets->Enable(false);
529 mSelection = Effect::kFactoryDefaultsIdent;
530 }
531 }
532
UpdateUI()533 void EffectPresetsDialog::UpdateUI()
534 {
535 int selected = mType->GetSelection();
536 if (selected == wxNOT_FOUND)
537 {
538 selected = 0;
539 mType->SetSelection(selected);
540 }
541 wxString type = mType->GetString(selected);
542
543 if (type == _("User Presets"))
544 {
545 selected = mPresets->GetSelection();
546 if (selected == wxNOT_FOUND)
547 {
548 selected = 0;
549 }
550
551 mPresets->Clear();
552 for (const auto &preset : mUserPresets)
553 mPresets->Append(preset);
554 mPresets->Enable(true);
555 mPresets->SetSelection(selected);
556 mSelection = Effect::kUserPresetIdent + mPresets->GetString(selected);
557 }
558 else if (type == _("Factory Presets"))
559 {
560 selected = mPresets->GetSelection();
561 if (selected == wxNOT_FOUND)
562 {
563 selected = 0;
564 }
565
566 mPresets->Clear();
567 for (size_t i = 0, cnt = mFactoryPresets.size(); i < cnt; i++)
568 {
569 auto label = mFactoryPresets[i];
570 if (label.empty())
571 {
572 label = _("None");
573 }
574 mPresets->Append(label);
575 }
576 mPresets->Enable(true);
577 mPresets->SetSelection(selected);
578 mSelection = Effect::kFactoryPresetIdent + mPresets->GetString(selected);
579 }
580 else if (type == _("Current Settings"))
581 {
582 mPresets->Clear();
583 mPresets->Enable(false);
584 mSelection = Effect::kCurrentSettingsIdent;
585 }
586 else if (type == _("Factory Defaults"))
587 {
588 mPresets->Clear();
589 mPresets->Enable(false);
590 mSelection = Effect::kFactoryDefaultsIdent;
591 }
592 }
593
OnType(wxCommandEvent & WXUNUSED (evt))594 void EffectPresetsDialog::OnType(wxCommandEvent & WXUNUSED(evt))
595 {
596 UpdateUI();
597 }
598
OnOk(wxCommandEvent & WXUNUSED (evt))599 void EffectPresetsDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
600 {
601 UpdateUI();
602
603 EndModal(true);
604 }
605
OnCancel(wxCommandEvent & WXUNUSED (evt))606 void EffectPresetsDialog::OnCancel(wxCommandEvent & WXUNUSED(evt))
607 {
608 mSelection = wxEmptyString;
609
610 EndModal(false);
611 }
612
613 }
614
GetPreset(const PluginID & ID,const wxString & params,wxWindow * parent)615 wxString EffectManager::GetPreset(const PluginID & ID, const wxString & params, wxWindow * parent)
616 {
617 Effect *effect = GetEffect(ID);
618
619 if (!effect)
620 {
621 return wxEmptyString;
622 }
623
624 CommandParameters eap(params);
625
626 wxString preset;
627 if (eap.HasEntry(wxT("Use Preset")))
628 {
629 preset = eap.Read(wxT("Use Preset"));
630 }
631
632 {
633 EffectPresetsDialog dlg(parent, effect);
634 dlg.Layout();
635 dlg.Fit();
636 dlg.SetSize(dlg.GetMinSize());
637 dlg.CenterOnParent();
638 dlg.SetSelected(preset);
639
640 if (dlg.ShowModal())
641 preset = dlg.GetSelected();
642 else
643 preset = wxEmptyString;
644 }
645
646 if (preset.empty())
647 {
648 return preset;
649 }
650
651 // This cleans a config "file" backed by a string in memory.
652 eap.DeleteAll();
653
654 eap.Write(wxT("Use Preset"), preset);
655 eap.GetParameters(preset);
656
657 return preset;
658 }
659
GetDefaultPreset(const PluginID & ID)660 wxString EffectManager::GetDefaultPreset(const PluginID & ID)
661 {
662 Effect *effect = GetEffect(ID);
663
664 if (!effect)
665 {
666 return wxEmptyString;
667 }
668
669 wxString preset;
670 if (effect->HasCurrentSettings())
671 {
672 preset = Effect::kCurrentSettingsIdent;
673 }
674 else if (effect->HasFactoryDefaults())
675 {
676 preset = Effect::kFactoryDefaultsIdent;
677 }
678
679 if (!preset.empty())
680 {
681 CommandParameters eap;
682
683 eap.Write(wxT("Use Preset"), preset);
684 eap.GetParameters(preset);
685 }
686
687 return preset;
688 }
689
SetBatchProcessing(const PluginID & ID,bool start)690 void EffectManager::SetBatchProcessing(const PluginID & ID, bool start)
691 {
692 Effect *effect = GetEffect(ID);
693 if (effect)
694 {
695 effect->SetBatchProcessing(start);
696 return;
697 }
698
699 AudacityCommand *command = GetAudacityCommand(ID);
700 if (command)
701 {
702 command->SetBatchProcessing(start);
703 return;
704 }
705
706 }
707
GetEffect(const PluginID & ID)708 Effect *EffectManager::GetEffect(const PluginID & ID)
709 {
710 // Must have a "valid" ID
711 if (ID.empty())
712 {
713 return NULL;
714 }
715
716 // If it is actually a command then refuse it (as an effect).
717 if( mCommands.find( ID ) != mCommands.end() )
718 return NULL;
719
720 // TODO: This is temporary and should be redone when all effects are converted
721 if (mEffects.find(ID) == mEffects.end())
722 {
723 // This will instantiate the effect client if it hasn't already been done
724 EffectDefinitionInterface *ident = dynamic_cast<EffectDefinitionInterface *>(PluginManager::Get().GetInstance(ID));
725 if (ident && ident->IsLegacy())
726 {
727 auto effect = dynamic_cast<Effect *>(ident);
728 if (effect && effect->Startup(NULL))
729 {
730 mEffects[ID] = effect;
731 return effect;
732 }
733 }
734
735 auto effect = std::make_shared<Effect>(); // TODO: use make_unique and store in std::unordered_map
736 if (effect)
737 {
738 EffectClientInterface *client = dynamic_cast<EffectClientInterface *>(ident);
739 if (client && effect->Startup(client))
740 {
741 auto pEffect = effect.get();
742 mEffects[ID] = pEffect;
743 mHostEffects[ID] = std::move(effect);
744 return pEffect;
745 }
746 }
747
748 auto command = dynamic_cast<AudacityCommand *>(PluginManager::Get().GetInstance(ID));
749 if( !command )
750 AudacityMessageBox(
751 XO(
752 "Attempting to initialize the following effect failed:\n\n%s\n\nMore information may be available in 'Help > Diagnostics > Show Log'")
753 .Format( GetCommandName(ID) ),
754 XO("Effect failed to initialize"));
755
756 return NULL;
757 }
758
759 return mEffects[ID];
760 }
761
GetAudacityCommand(const PluginID & ID)762 AudacityCommand *EffectManager::GetAudacityCommand(const PluginID & ID)
763 {
764 // Must have a "valid" ID
765 if (ID.empty())
766 {
767 return NULL;
768 }
769
770 // TODO: This is temporary and should be redone when all effects are converted
771 if (mCommands.find(ID) == mCommands.end())
772 {
773
774 // This will instantiate the effect client if it hasn't already been done
775 auto command = dynamic_cast<AudacityCommand *>(PluginManager::Get().GetInstance(ID));
776 if (command )//&& command->Startup(NULL))
777 {
778 command->Init();
779 mCommands[ID] = command;
780 return command;
781 }
782
783 /*
784 if (ident && ident->IsLegacy())
785 {
786 auto command = dynamic_cast<AudacityCommand *>(ident);
787 if (commandt && command->Startup(NULL))
788 {
789 mCommands[ID] = command;
790 return command;
791 }
792 }
793
794
795 auto command = std::make_shared<AudacityCommand>(); // TODO: use make_unique and store in std::unordered_map
796 if (command)
797 {
798 AudacityCommand *client = dynamic_cast<AudacityCommand *>(ident);
799 if (client && command->Startup(client))
800 {
801 auto pCommand = command.get();
802 mEffects[ID] = pCommand;
803 mHostEffects[ID] = std::move(effect);
804 return pEffect;
805 }
806 }
807 */
808 AudacityMessageBox(
809 XO(
810 "Attempting to initialize the following command failed:\n\n%s\n\nMore information may be available in 'Help > Diagnostics > Show Log'")
811 .Format( GetCommandName(ID) ),
812 XO("Command failed to initialize"));
813
814 return NULL;
815 }
816
817 return mCommands[ID];
818 }
819
820
GetEffectByIdentifier(const CommandID & strTarget)821 const PluginID & EffectManager::GetEffectByIdentifier(const CommandID & strTarget)
822 {
823 static PluginID empty;
824 if (strTarget.empty()) // set GetCommandIdentifier to wxT("") to not show an effect in Batch mode
825 {
826 return empty;
827 }
828
829 PluginManager & pm = PluginManager::Get();
830 // Effects OR Generic commands...
831 for (auto &plug
832 : pm.PluginsOfType(PluginTypeEffect | PluginTypeAudacityCommand)) {
833 auto &ID = plug.GetID();
834 if (GetCommandIdentifier(ID) == strTarget)
835 return ID;
836 }
837 return empty;
838 }
839
840