Audacity 3.2.0
PluginManager.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 PluginManager.cpp
6
7 Leland Lucius
8
9*******************************************************************/
22#include "PluginManager.h"
23
24
25
26#include <algorithm>
27
28#include <wx/log.h>
29#include <wx/tokenzr.h>
30
31#include "BasicUI.h"
32#include "PluginProvider.h"
33
34#include "Internat.h" // for macro XO
35#include "FileNames.h"
36#include "MemoryX.h"
37#include "ModuleManager.h"
39#include "Base64.h"
40#include "Variant.h"
41
43//
44// PluginManager
45//
47
48// Registry has the list of plug ins
49#define REGVERKEY wxString(wxT("/pluginregistryversion"))
50#define REGROOT wxString(wxT("/pluginregistry/"))
51
52// Settings has the values of the plug in settings.
53#define SETVERKEY wxString(wxT("/pluginsettingsversion"))
54#define SETVERCUR wxString(wxT("1.0"))
55#define SETROOT wxString(wxT("/pluginsettings/"))
56
57#define KEY_ID wxT("ID")
58#define KEY_PATH wxT("Path")
59#define KEY_SYMBOL wxT("Symbol")
60#define KEY_NAME wxT("Name")
61#define KEY_VENDOR wxT("Vendor")
62#define KEY_VERSION wxT("Version")
63#define KEY_DESCRIPTION wxT("Description")
64#define KEY_LASTUPDATED wxT("LastUpdated")
65#define KEY_ENABLED wxT("Enabled")
66#define KEY_VALID wxT("Valid")
67#define KEY_PROVIDERID wxT("ProviderID")
68#define KEY_EFFECTTYPE wxT("EffectType")
69#define KEY_EFFECTFAMILY wxT("EffectFamily")
70#define KEY_EFFECTDEFAULT wxT("EffectDefault")
71#define KEY_EFFECTINTERACTIVE wxT("EffectInteractive")
72#define KEY_EFFECTREALTIME wxT("EffectRealtime")
73#define KEY_EFFECTAUTOMATABLE wxT("EffectAutomatable")
74#define KEY_EFFECTTYPE_NONE wxT("None")
75#define KEY_EFFECTTYPE_ANALYZE wxT("Analyze")
76#define KEY_EFFECTTYPE_GENERATE wxT("Generate")
77#define KEY_EFFECTTYPE_PROCESS wxT("Process")
78#define KEY_EFFECTTYPE_TOOL wxT("Tool")
79#define KEY_EFFECTTYPE_HIDDEN wxT("Hidden")
80#define KEY_IMPORTERIDENT wxT("ImporterIdent")
81//#define KEY_IMPORTERFILTER wxT("ImporterFilter")
82#define KEY_IMPORTEREXTENSIONS wxT("ImporterExtensions")
83
84// ============================================================================
85//
86// PluginManagerInterface implementation
87//
88// ============================================================================
89
91 PluginProvider *provider, ComponentInterface *pInterface )
92{
93 if(auto effectDefinitionInterface = dynamic_cast<EffectDefinitionInterface*>(pInterface))
94 return PluginManager::Get().RegisterPlugin(provider, effectDefinitionInterface, PluginTypeEffect);
95 return PluginManager::Get().RegisterPlugin(provider, pInterface);
96}
97
99 PluginProvider *provider, ComponentInterface *pInterface )
100{
101 return PluginManager::Get().RegisterPlugin(provider, pInterface);
102}
103
105{
106 auto pPlugin = GetPlugin( ID );
107 if ( pPlugin )
108 return GetPluginEnabledSetting( *pPlugin );
109 return {};
110}
111
113 const PluginDescriptor &desc ) const
114{
115 switch ( desc.GetPluginType() ) {
116 case PluginTypeModule: {
117 // Retrieve optional family symbol that was recorded in
118 // RegisterPlugin() for the module
119 auto family = desc.GetEffectFamily();
120 if ( family.empty() ) // as for built-in effect and command modules
121 return {};
122 else
123 return wxT('/') + family + wxT("/Enable");
124 }
125 case PluginTypeEffect:
126 // do NOT use GetEffectFamily() for this descriptor, but instead,
127 // delegate to the plugin descriptor of the provider, which may
128 // be different (may be empty)
129 return GetPluginEnabledSetting( desc.GetProviderID() );
130 default:
131 return {};
132 }
133}
134
136 const PluginPath &path, const TranslatableString *pName)
137{
138 for (auto &pair : mRegisteredPlugins) {
139 if (auto &descriptor = pair.second; descriptor.GetPath() == path) {
140 if (pName)
141 descriptor.SetSymbol(
142 { descriptor.GetSymbol().Internal(), *pName });
143 return true;
144 }
145 }
146 return false;
147}
148
149bool PluginManager::IsPluginLoaded(const wxString& ID) const
150{
151 return mLoadedInterfaces.find(ID) != mLoadedInterfaces.end();
152}
153
155{
156 mRegisteredPlugins[desc.GetID()] = std::move(desc);
157}
158
160{
161 PluginDescriptor & plug =
162 CreatePlugin(GetID(provider), provider, PluginTypeModule);
164
165 plug.SetEnabled(true);
166 plug.SetValid(true);
167
168 return plug.GetID();
169}
170
172 PluginProvider *provider, ComponentInterface *command)
173{
175
176 plug.SetProviderID(PluginManager::GetID(provider));
177
178 plug.SetEnabled(true);
179 plug.SetValid(true);
180
181 return plug.GetID();
182}
183
185 PluginProvider *provider, EffectDefinitionInterface *effect, int type)
186{
187 PluginDescriptor & plug = CreatePlugin(GetID(effect), effect, (PluginType)type);
188
189 plug.SetProviderID(PluginManager::GetID(provider));
190
191 plug.SetEffectType(effect->GetClassification());
192 plug.SetEffectFamily(effect->GetFamily().Internal());
193 plug.SetEffectInteractive(effect->IsInteractive());
194 plug.SetEffectDefault(effect->IsDefault());
195 plug.SetRealtimeSupport(effect->RealtimeSupport());
197
198 plug.SetEnabled(true);
199 plug.SetValid(true);
200
201 return plug.GetID();
202}
203
204void PluginManager::FindFilesInPathList(const wxString & pattern,
205 const FilePaths & pathList,
206 FilePaths & files,
207 bool directories)
208{
209
210 wxLogNull nolog;
211
212 // Why bother...
213 if (pattern.empty())
214 {
215 return;
216 }
217
218 // TODO: We REALLY need to figure out the "Audacity" plug-in path(s)
219
220 FilePaths paths;
221
222 // Add the "per-user" plug-ins directory
223 {
224 const wxFileName &ff = FileNames::PlugInDir();
225 paths.push_back(ff.GetFullPath());
226 }
227
228 // Add the "Audacity" plug-ins directory
230#if defined(__WXMAC__)
231 // Path ends for example in "Audacity.app/Contents/MacOSX"
232 //ff.RemoveLastDir();
233 //ff.RemoveLastDir();
234 // just remove the MacOSX part.
235 ff.RemoveLastDir();
236#endif
237 ff.AppendDir(wxT("plug-ins"));
238 paths.push_back(ff.GetPath());
239
240 // Weed out duplicates
241 for (const auto &filePath : pathList)
242 {
243 ff = filePath;
244 const wxString path{ ff.GetFullPath() };
245 if (paths.Index(path, wxFileName::IsCaseSensitive()) == wxNOT_FOUND)
246 {
247 paths.push_back(path);
248 }
249 }
250
251 // Find all matching files in each path
252 for (size_t i = 0, cnt = paths.size(); i < cnt; i++)
253 {
254 ff = paths[i] + wxFILE_SEP_PATH + pattern;
255 wxDir::GetAllFiles(ff.GetPath(), &files, ff.GetFullName(), directories ? wxDIR_DEFAULT : wxDIR_FILES);
256 }
257
258 return;
259}
260
262 const RegistryPath & group)
263{
264 return HasGroup(Group(type, ID, group));
265}
266
268 const PluginID & ID, const RegistryPath & group, RegistryPaths & subgroups)
269{
270 return GetSubgroups(Group(type, ID, group), subgroups);
271}
272
274 const RegistryPath & group, const RegistryPath & key)
275{
276 return HasConfigValue(Key(type, ID, group, key));
277}
278
280 const RegistryPath & group, const RegistryPath & key,
282{
283 return GetConfigValue(Key(type, ID, group, key), var, defval);
284}
285
287 const RegistryPath & group, const RegistryPath & key,
289{
290 return SetConfigValue(Key(type, ID, group, key), value);
291}
292
294 const PluginID & ID, const RegistryPath & group)
295{
296 bool result = GetSettings()->DeleteGroup(Group(type, ID, group));
297 if (result)
298 {
299 GetSettings()->Flush();
300 }
301
302 return result;
303}
304
306 const RegistryPath & group, const RegistryPath & key)
307{
308 bool result = GetSettings()->DeleteEntry(Key(type, ID, group, key));
309 if (result)
310 {
311 GetSettings()->Flush();
312 }
313
314 return result;
315}
316
317// ============================================================================
318//
319// PluginManager
320//
321// ============================================================================
322
323// The one and only PluginManager
324std::unique_ptr<PluginManager> PluginManager::mInstance{};
325
326// ----------------------------------------------------------------------------
327// Creation/Destruction
328// ----------------------------------------------------------------------------
329
331{
332 mSettings = NULL;
333}
334
336{
337 // Ensure termination (harmless if already done)
338 Terminate();
339}
340
342{
343 ModuleManager & moduleManager = ModuleManager::Get();
344 //ModuleManager::DiscoverProviders was called earlier, so we
345 //can be sure that providers are already loaded
346
347 //Check all known plugins to ensure they are still valid.
348 for (auto it = mRegisteredPlugins.begin(); it != mRegisteredPlugins.end();) {
349 auto &pluginDesc = it->second;
350 const auto pluginType = pluginDesc.GetPluginType();
351 if(pluginType == PluginTypeNone || pluginType == PluginTypeModule)
352 {
353 ++it;
354 continue;
355 }
356
357 if(!moduleManager.CheckPluginExist(pluginDesc.GetProviderID(), pluginDesc.GetPath()))
358 it = mRegisteredPlugins.erase(it);
359 else
360 ++it;
361 }
362
363 Save();
364}
365
366// ----------------------------------------------------------------------------
367// PluginManager implementation
368// ----------------------------------------------------------------------------
369
371
372// ============================================================================
373//
374// Return reference to singleton
375//
376// (Thread-safe...no active threading during construction or after destruction)
377// ============================================================================
378
380{
381 if (!mInstance)
382 {
384 }
385
386 return *mInstance;
387}
388
390{
391 sFactory = move(factory);
392
393 // Always load the registry first
394 Load();
395
396 // And force load of setting to verify it's accessible
397 GetSettings();
398
399 auto &mm = ModuleManager::Get();
400 mm.DiscoverProviders();
401 for (auto& [id, module] : mm.Providers()) {
402 RegisterPlugin(module.get());
403 // Allow the module to auto-register children
404 module->AutoRegisterPlugins(*this);
405 }
406
408}
409
411{
412 // Get rid of all non-module(effects?) plugins first
413 for(auto& p : mRegisteredPlugins)
414 {
415 auto& desc = p.second;
416 if(desc.GetPluginType() == PluginTypeEffect)
417 mLoadedInterfaces.erase(desc.GetID());
418 }
419
420 // Now get rid of others
421 mRegisteredPlugins.clear();
422 mLoadedInterfaces.clear();
423}
424
425bool PluginManager::DropFile(const wxString &fileName)
426{
427 using namespace BasicUI;
428 auto &mm = ModuleManager::Get();
429 const wxFileName src{ fileName };
430
431 for (auto &plug : PluginsOfType(PluginTypeModule)) {
432 auto module = static_cast<PluginProvider *>
433 (mm.CreateProviderInstance(plug.GetID(), plug.GetPath()));
434 if (! module)
435 continue;
436
437 const auto &ff = module->InstallPath();
438 const auto &extensions = module->GetFileExtensions();
439 if ( !ff.empty() &&
440 extensions.Index(src.GetExt(), false) != wxNOT_FOUND ) {
441 TranslatableString errMsg;
442 // Do dry-run test of the file format
443 unsigned nPlugIns =
444 module->DiscoverPluginsAtPath(fileName, errMsg, {});
445 if (nPlugIns) {
446 // File contents are good for this module, so check no others.
447 // All branches of this block return true, even in case of
448 // failure for other reasons, to signal that other drag-and-drop
449 // actions should not be tried.
450
451 // Find path to copy it
452 wxFileName dst;
453 dst.AssignDir( ff );
454 dst.SetFullName( src.GetFullName() );
455 if ( dst.Exists() ) {
456 // Query whether to overwrite
457 bool overwrite = (MessageBoxResult::Yes == ShowMessageBox(
458 XO("Overwrite the plug-in file %s?")
459 .Format( dst.GetFullPath() ),
461 .Caption(XO("Plug-in already exists"))
462 .ButtonStyle(Button::YesNo)));
463 if ( !overwrite )
464 return true;
465 }
466
467 // Move the file or subtree
468 bool copied = false;
469 auto dstPath = dst.GetFullPath();
470 if ( src.FileExists() )
471 // A simple one-file plug-in
472 copied = FileNames::DoCopyFile(
473 src.GetFullPath(), dstPath, true );
474 else {
475 // A sub-folder
476 // such as for some VST packages
477 // Recursive copy needed -- to do
478 return true;
479 }
480
481 if (!copied) {
483 XO("Plug-in file is in use. Failed to overwrite") );
484 return true;
485 }
486
487 // Register for real
488 std::vector<PluginID> ids;
489 std::vector<wxString> names;
490 nPlugIns = module->DiscoverPluginsAtPath(dstPath, errMsg,
492 -> const PluginID& {
493 // Register as by default, but also collecting the PluginIDs
494 // and names
496 provider, ident);
497 ids.push_back(id);
498 names.push_back( ident->GetSymbol().Translation() );
499 return id;
500 });
501 if ( ! nPlugIns ) {
502 // Unlikely after the dry run succeeded
504 XO("Failed to register:\n%s").Format( errMsg ) );
505 return true;
506 }
507
508 // Ask whether to enable the plug-ins
509 if (auto nIds = ids.size()) {
510 auto message = XPC(
511 /* i18n-hint A plug-in is an optional added program for a sound
512 effect, or generator, or analyzer */
513 "Enable this plug-in?\n",
514 "Enable these plug-ins?\n",
515 0,
516 "plug-ins"
517 )( nIds );
518 for (const auto &name : names)
519 message.Join( Verbatim( name ), wxT("\n") );
520 bool enable = (MessageBoxResult::Yes == ShowMessageBox(
521 message,
523 .Caption(XO("Enable new plug-ins"))
524 .ButtonStyle(Button::YesNo)));
525 for (const auto &id : ids)
526 mRegisteredPlugins[id].SetEnabled(enable);
527 // Make changes to enabled status persist:
528 this->Save();
529 this->NotifyPluginsChanged();
530 }
531
532 return true;
533 }
534 }
535 }
536
537 return false;
538}
539
541{
542 // Create/Open the registry
543 auto pRegistry = sFactory(FileNames::PluginRegistry());
544 auto &registry = *pRegistry;
545
546 // If this group doesn't exist then we have something that's not a registry.
547 // We should probably warn the user, but it's pretty unlikely that this will happen.
548 if (!registry.HasGroup(REGROOT))
549 {
550 // Must start over
551 // This DeleteAll affects pluginregistry.cfg only, not audacity.cfg
552 // That is, the memory of on/off states of effect (and generator,
553 // analyzer, and tool) plug-ins
554 registry.Clear();
555 registry.Flush();
556 return;
557 }
558
559 // Check for a registry version that we can understand
560 // TODO: Should also check for a registry file that is newer than
561 // what we can understand.
562 mRegver = registry.Read(REGVERKEY);
563 if (Regver_lt(mRegver, "1.1")) {
564 // Conversion code here, for when registry version changes.
565
566 // We iterate through the effects, possibly updating their info.
567 wxString group = GetPluginTypeString(PluginTypeEffect);
568 wxString cfgPath = REGROOT + group + wxCONFIG_PATH_SEPARATOR;
569 wxArrayString groupsToDelete;
570
571 auto cfgGroup = registry.BeginGroup(cfgPath);
572 for(const auto& groupName : registry.GetChildGroups())
573 {
574 auto effectGroup = registry.BeginGroup(groupName);
575 wxString effectSymbol = registry.Read(KEY_SYMBOL, "");
576 wxString effectVersion = registry.Read(KEY_VERSION, "");
577
578
579 // For 2.3.0 the plugins we distribute have moved around.
580 // So we upped the registry version number to 1.1.
581 // These particular config edits were originally written to fix Bug 1914.
582 if (Regver_le(mRegver, "1.0")) {
583 // Nyquist prompt is a built-in that has moved to the tools menu.
584 if (effectSymbol == NYQUIST_PROMPT_ID) {
585 registry.Write(KEY_EFFECTTYPE, "Tool");
586 // Old version of SDE was in Analyze menu. Now it is in Tools.
587 // We don't want both the old and the new.
588 } else if ((effectSymbol == "Sample Data Export") && (effectVersion == "n/a")) {
589 groupsToDelete.push_back(cfgPath + groupName);
590 // Old version of SDI was in Generate menu. Now it is in Tools.
591 } else if ((effectSymbol == "Sample Data Import") && (effectVersion == "n/a")) {
592 groupsToDelete.push_back(cfgPath + groupName);
593 }
594 }
595 }
596 // Doing the deletion within the search loop risked skipping some items,
597 // hence the delayed delete.
598 for (unsigned int i = 0; i < groupsToDelete.size(); i++) {
599 registry.DeleteGroup(groupsToDelete[i]);
600 }
601 // Updates done. Make sure we read the updated data later.
602 registry.Flush();
603 }
604
605 // Load all provider plugins first
606 LoadGroup(&registry, PluginTypeModule);
607
608 // Now the rest
609 LoadGroup(&registry, PluginTypeEffect);
611 LoadGroup(&registry, PluginTypeExporter);
612 LoadGroup(&registry, PluginTypeImporter);
613
614 LoadGroup(&registry, PluginTypeStub);
615 return;
616}
617
619{
620#ifdef __WXMAC__
621 // Bug 1590: On Mac, we should purge the registry of Nyquist plug-ins
622 // bundled with other versions of Audacity, assuming both versions
623 // were properly installed in /Applications (or whatever it is called in
624 // your locale)
625
626 const auto fullExePath = PlatformCompatibility::GetExecutablePath();
627
628 // Strip rightmost path components up to *.app
629 wxFileName exeFn{ fullExePath };
630 exeFn.SetEmptyExt();
631 exeFn.SetName(wxString{});
632 while(exeFn.GetDirCount() && !exeFn.GetDirs().back().EndsWith(".app"))
633 exeFn.RemoveLastDir();
634
635 const auto goodPath = exeFn.GetPath();
636
637 if(exeFn.GetDirCount())
638 exeFn.RemoveLastDir();
639 const auto possiblyBadPath = exeFn.GetPath();
640
641 auto AcceptPath = [&](const wxString &path) {
642 if (!path.StartsWith(possiblyBadPath))
643 // Assume it's not under /Applications
644 return true;
645 if (path.StartsWith(goodPath))
646 // It's bundled with this executable
647 return true;
648 return false;
649 };
650#else
651 auto AcceptPath = [](const wxString&){ return true; };
652#endif
653
654 wxString strVal;
655 bool boolVal;
656 wxString cfgPath = REGROOT + GetPluginTypeString(type) + wxCONFIG_PATH_SEPARATOR;
657
658 const auto cfgGroup = pRegistry->BeginGroup(cfgPath);
659 for(const auto& group : pRegistry->GetChildGroups())
660 {
661 PluginDescriptor plug;
662 const auto effectGroup = pRegistry->BeginGroup(group);
663
664 auto groupName = ConvertID(group);
665
666 // Bypass group if the ID is already in use
667 if (mRegisteredPlugins.count(groupName))
668 continue;
669
670 // Set the ID and type
671 plug.SetID(groupName);
672 plug.SetPluginType(type);
673
674 // Get the provider ID and bypass group if not found
675 if (!pRegistry->Read(KEY_PROVIDERID, &strVal, {}))
676 {
677 // Bypass group if the provider isn't valid
678 if (!strVal.empty() && !mRegisteredPlugins.count(strVal))
679 continue;
680 }
681 plug.SetProviderID(PluginID(strVal));
682
683 // Get the path (optional)
684 pRegistry->Read(KEY_PATH, &strVal, {});
685 if (!AcceptPath(strVal))
686 // Ignore the obsolete path in the config file, during session,
687 // but don't remove it from the file. Maybe you really want to
688 // switch back to the other version of Audacity and lose nothing.
689 continue;
690 plug.SetPath(strVal);
691
692 /*
693 // PRL: Ignore names written in configs before 2.3.0!
694 // use Internal string only! Let the present version of Audacity map
695 // that to a user-visible string.
696 // Get the name and bypass group if not found
697 if (!pRegistry->Read(KEY_NAME, &strVal))
698 {
699 continue;
700 }
701 plug.SetName(strVal);
702 */
703
704 // Get the symbol...Audacity 2.3.0 or later requires it
705 // bypass group if not found
706 // Note, KEY_SYMBOL started getting written to config files in 2.1.0.
707 // KEY_NAME (now ignored) was written before that, but only for VST
708 // effects.
709 if (!pRegistry->Read(KEY_SYMBOL, &strVal))
710 continue;
711
712 // Related to Bug2778: config file only remembered an internal name,
713 // so this symbol may not contain the correct TranslatableString.
714 // See calls to IsPluginRegistered which can correct that.
715 plug.SetSymbol(strVal);
716
717 // Get the version and bypass group if not found
718 if (!pRegistry->Read(KEY_VERSION, &strVal))
719 {
720 continue;
721 }
722 plug.SetVersion(strVal);
723
724 // Get the vendor and bypass group if not found
725 if (!pRegistry->Read(KEY_VENDOR, &strVal))
726 {
727 continue;
728 }
729 plug.SetVendor( strVal );
730
731#if 0
732 // This was done before version 2.2.2, but the value was not really used
733 // But absence of a value will cause early versions to skip the group
734 // Therefore we still write a blank to keep pluginregistry.cfg
735 // backwards-compatible
736
737 // Get the description and bypass group if not found
738 if (!pRegistry->Read(KEY_DESCRIPTION, &strVal))
739 {
740 continue;
741 }
742#endif
743
744 // Is it enabled...default to no if not found
745 pRegistry->Read(KEY_ENABLED, &boolVal, false);
746 plug.SetEnabled(boolVal);
747
748 // Is it valid...default to no if not found
749 pRegistry->Read(KEY_VALID, &boolVal, false);
750 plug.SetValid(boolVal);
751
752 switch (type)
753 {
754 case PluginTypeModule:
755 {
756 // Nothing to do here yet
757 }
758 break;
759
760 case PluginTypeEffect:
761 {
762 // Get the effect type and bypass group if not found
763 if (!pRegistry->Read(KEY_EFFECTTYPE, &strVal))
764 continue;
765
766 if (strVal == KEY_EFFECTTYPE_NONE)
768 else if (strVal == KEY_EFFECTTYPE_ANALYZE)
770 else if (strVal == KEY_EFFECTTYPE_GENERATE)
772 else if (strVal == KEY_EFFECTTYPE_PROCESS)
774 else if (strVal == KEY_EFFECTTYPE_TOOL)
776 else if (strVal == KEY_EFFECTTYPE_HIDDEN)
778 else
779 continue;
780
781 // Get the effect family and bypass group if not found
782 if (!pRegistry->Read(KEY_EFFECTFAMILY, &strVal))
783 {
784 continue;
785 }
786 plug.SetEffectFamily(strVal);
787
788 // Is it a default (above the line) effect and bypass group if not found
789 if (!pRegistry->Read(KEY_EFFECTDEFAULT, &boolVal))
790 {
791 continue;
792 }
793 plug.SetEffectDefault(boolVal);
794
795 // Is it an interactive effect and bypass group if not found
796 if (!pRegistry->Read(KEY_EFFECTINTERACTIVE, &boolVal))
797 {
798 continue;
799 }
800 plug.SetEffectInteractive(boolVal);
801
802 // Is it a realtime capable effect and bypass group if not found
803 if (!pRegistry->Read(KEY_EFFECTREALTIME, &strVal))
804 {
805 continue;
806 }
807 plug.DeserializeRealtimeSupport(strVal);
808
809 // Does the effect support automation...bypass group if not found
810 if (!pRegistry->Read(KEY_EFFECTAUTOMATABLE, &boolVal))
811 {
812 continue;
813 }
814 plug.SetEffectAutomatable(boolVal);
815 }
816 break;
817
819 {
820 // Get the importer identifier and bypass group if not found
821 if (!pRegistry->Read(KEY_IMPORTERIDENT, &strVal))
822 {
823 continue;
824 }
825 plug.SetImporterIdentifier(strVal);
826
827 // Get the importer extensions and bypass group if not found
828 if (!pRegistry->Read(KEY_IMPORTEREXTENSIONS, &strVal))
829 {
830 continue;
831 }
832 FileExtensions extensions;
833 wxStringTokenizer tkr(strVal, wxT(":"));
834 while (tkr.HasMoreTokens())
835 {
836 extensions.push_back(tkr.GetNextToken());
837 }
838 plug.SetImporterExtensions(extensions);
839 }
840 break;
841
842 case PluginTypeStub:
843 {
844 // Nothing additional for stubs
845 }
846 break;
847
848 // Not used by 2.1.1 or greater and should be removed after a few releases past 2.1.0.
849 case PluginTypeNone:
850 {
851 // Used for stub groups
852 }
853 break;
854
855 default:
856 {
857 continue;
858 }
859 }
860
861 // Everything checked out...accept the plugin
862 mRegisteredPlugins[groupName] = std::move(plug);
863 }
864
865 return;
866}
867
869{
870 // Create/Open the registry
871 auto pRegistry = sFactory(FileNames::PluginRegistry());
872 auto &registry = *pRegistry;
873
874 // Clear pluginregistry.cfg (not audacity.cfg)
875 registry.Clear();
876
877 // Save the individual groups
878 SaveGroup(&registry, PluginTypeEffect);
879 SaveGroup(&registry, PluginTypeExporter);
881 SaveGroup(&registry, PluginTypeImporter);
882 SaveGroup(&registry, PluginTypeStub);
883
884 // Not used by 2.1.1 or greater, but must save to allow users to switch between 2.1.0
885 // and 2.1.1+. This should be removed after a few releases past 2.1.0.
886 //SaveGroup(&registry, PluginTypeNone);
887
888 // And now the providers
889 SaveGroup(&registry, PluginTypeModule);
890
891 // Write the version string
892 registry.Write(REGVERKEY, REGVERCUR);
893
894 // Just to be safe
895 registry.Flush();
896
898}
899
901{
903}
904
906{
907 return mRegver;
908}
909
911{
912 wxString group = GetPluginTypeString(type);
913 for (auto &pair : mRegisteredPlugins) {
914 auto & plug = pair.second;
915
916 if (plug.GetPluginType() != type)
917 {
918 continue;
919 }
920
921 const auto pluginGroup = pRegistry->BeginGroup(REGROOT + group + wxCONFIG_PATH_SEPARATOR + ConvertID(plug.GetID()));
922
923 pRegistry->Write(KEY_PATH, plug.GetPath());
924
925 // See comments with the corresponding load-time call to SetSymbol().
926 pRegistry->Write(KEY_SYMBOL, plug.GetSymbol().Internal());
927
928 // PRL: Writing KEY_NAME which is no longer read, but older Audacity
929 // versions expect to find it.
930 pRegistry->Write(KEY_NAME, plug.GetSymbol().Msgid().MSGID());
931
932 pRegistry->Write(KEY_VERSION, plug.GetUntranslatedVersion());
933 pRegistry->Write(KEY_VENDOR, plug.GetVendor());
934 // Write a blank -- see comments in LoadGroup:
935 pRegistry->Write(KEY_DESCRIPTION, wxString{});
936 pRegistry->Write(KEY_PROVIDERID, plug.GetProviderID());
937 pRegistry->Write(KEY_ENABLED, plug.IsEnabled());
938 pRegistry->Write(KEY_VALID, plug.IsValid());
939
940 switch (type)
941 {
942 case PluginTypeModule:
943 break;
944
945 case PluginTypeEffect:
946 {
947 EffectType etype = plug.GetEffectType();
948 wxString stype;
949 if (etype == EffectTypeNone)
950 stype = KEY_EFFECTTYPE_NONE;
951 else if (etype == EffectTypeAnalyze)
953 else if (etype == EffectTypeGenerate)
955 else if (etype == EffectTypeProcess)
957 else if (etype == EffectTypeTool)
958 stype = KEY_EFFECTTYPE_TOOL;
959 else if (etype == EffectTypeHidden)
960 stype = KEY_EFFECTTYPE_HIDDEN;
961
962 pRegistry->Write(KEY_EFFECTTYPE, stype);
963 pRegistry->Write(KEY_EFFECTFAMILY, plug.GetEffectFamily());
964 pRegistry->Write(KEY_EFFECTDEFAULT, plug.IsEffectDefault());
965 pRegistry->Write(KEY_EFFECTINTERACTIVE, plug.IsEffectInteractive());
966 pRegistry->Write(KEY_EFFECTREALTIME, plug.SerializeRealtimeSupport());
967 pRegistry->Write(KEY_EFFECTAUTOMATABLE, plug.IsEffectAutomatable());
968 }
969 break;
970
972 {
973 pRegistry->Write(KEY_IMPORTERIDENT, plug.GetImporterIdentifier());
974 const auto & extensions = plug.GetImporterExtensions();
975 wxString strExt;
976 for (size_t i = 0, cnt = extensions.size(); i < cnt; i++)
977 {
978 strExt += extensions[i] + wxT(":");
979 }
980 strExt.RemoveLast(1);
981 pRegistry->Write(KEY_IMPORTEREXTENSIONS, strExt);
982 }
983 break;
984
985 default:
986 break;
987 }
988 }
989
990 return;
991}
992
993// Here solely for the purpose of Nyquist Workbench until
994// a better solution is devised.
996 std::unique_ptr<EffectDefinitionInterface> effect, PluginType type)
997{
998 PluginDescriptor & plug =
999 CreatePlugin(GetID(effect.get()), effect.get(), type);
1000
1001 plug.SetEffectType(effect->GetType());
1002 plug.SetEffectFamily(effect->GetFamily().Internal());
1003 plug.SetEffectInteractive(effect->IsInteractive());
1004 plug.SetEffectDefault(effect->IsDefault());
1005 plug.SetRealtimeSupport(effect->RealtimeSupport());
1006 plug.SetEffectAutomatable(effect->SupportsAutomation());
1007
1008 plug.SetEffectLegacy(true);
1009 plug.SetEnabled(true);
1010 plug.SetValid(true);
1011
1012 mLoadedInterfaces[plug.GetID()] = std::move(effect);
1013
1014 return plug.GetID();
1015}
1016
1018{
1019 mRegisteredPlugins.erase(ID);
1020 mLoadedInterfaces.erase(ID);
1021}
1022
1024{
1025 return count_if(mRegisteredPlugins.begin(), mRegisteredPlugins.end(), [type](auto &pair){
1026 return pair.second.GetPluginType() == type; });
1027}
1028
1030{
1031 if (auto iter = mRegisteredPlugins.find(ID); iter != mRegisteredPlugins.end())
1032 return &iter->second;
1033
1035 .find_if([&ID](const PluginDescriptor& plug) {
1036 return plug.GetID() == ID;
1037 });
1038 if (iter2 != mEffectPluginsCleared.end())
1039 return &(*iter2);
1040
1041 return nullptr;
1042}
1043
1045{
1046 const auto end = mPm.mRegisteredPlugins.end();
1047 if (incrementing && mIterator != end)
1048 ++mIterator;
1050 for (; mIterator != end; ++mIterator) {
1051 auto &plug = mIterator->second;
1052 if (!all && !(plug.IsValid() && plug.IsEnabled()))
1053 continue;
1054 auto plugType = plug.GetPluginType();
1055 if ((mPluginType == PluginTypeNone || (plugType & mPluginType)) &&
1056 (mEffectType == EffectTypeNone || plug.GetEffectType() == mEffectType)) {
1057 if (!all && (plugType & PluginTypeEffect)) {
1058 // This preference may be written by EffectsPrefs
1059 auto setting = mPm.GetPluginEnabledSetting( plug );
1060 if (!(setting.empty() || gPrefs->Read( setting, true )))
1061 continue;
1062 }
1063 // Pause iteration at this match
1064 break;
1065 }
1066 }
1067}
1068
1070: mPm{ manager }
1071, mIterator{ manager.mRegisteredPlugins.begin() }
1072{
1073}
1074
1076: mPm{ manager }
1077, mIterator{ manager.mRegisteredPlugins.begin() }
1078, mPluginType{ type }
1079{
1080 Advance(false);
1081}
1082
1084: mPm{ manager }
1085, mIterator{ manager.mRegisteredPlugins.begin() }
1086, mEffectType{ type }
1087{
1088 Advance(false);
1089}
1090
1092{
1093 Advance(true);
1094 return *this;
1095}
1096
1098{
1099 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end())
1100 return false;
1101 else
1102 return iter->second.IsEnabled();
1103}
1104
1105void PluginManager::EnablePlugin(const PluginID & ID, bool enable)
1106{
1107 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end())
1108 return;
1109 else
1110 iter->second.SetEnabled(enable);
1111}
1112
1114{
1115 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end()) {
1116 static ComponentInterfaceSymbol empty;
1117 return empty;
1118 }
1119 else
1120 return iter->second.GetSymbol();
1121}
1122
1124{
1125 if(auto it = mLoadedInterfaces.find(ID); it != mLoadedInterfaces.end())
1126 return it->second.get();
1127
1128 if(auto it = mRegisteredPlugins.find(ID); it != mRegisteredPlugins.end())
1129 {
1130 auto& desc = it->second;
1131 if(desc.GetPluginType() == PluginTypeModule)
1132 //it's very likely that this code path is not used
1133 return ModuleManager::Get().CreateProviderInstance(desc.GetID(), desc.GetPath());
1134
1135 if(auto provider = ModuleManager::Get().CreateProviderInstance(desc.GetProviderID(), wxEmptyString))
1136 {
1137 auto pluginInterface = provider->LoadPlugin(desc.GetPath());
1138 auto result = pluginInterface.get();
1139 mLoadedInterfaces[desc.GetID()] = std::move(pluginInterface);
1140 return result;
1141 }
1142 }
1143 return nullptr;
1144}
1145
1147{
1148 mEffectPluginsCleared.clear();
1149
1150 for ( auto it = mRegisteredPlugins.cbegin(); it != mRegisteredPlugins.cend(); )
1151 {
1152 const auto& desc = it->second;
1153 const auto type = desc.GetPluginType();
1154
1155 if (type == PluginTypeEffect || type == PluginTypeStub)
1156 {
1157 mEffectPluginsCleared.push_back(desc);
1158 it = mRegisteredPlugins.erase(it);
1159 }
1160 else
1161 {
1162 ++it;
1163 }
1164 }
1165
1166 // Repeat what usually happens at startup
1167 // This prevents built-in plugins to appear in the plugin validation list
1168 for (auto& [_, provider] : ModuleManager::Get().Providers())
1169 provider->AutoRegisterPlugins(*this);
1170
1171 // Remove auto registered plugins from "cleared" list
1172 for ( auto it = mEffectPluginsCleared.begin(); it != mEffectPluginsCleared.end(); )
1173 {
1174 if ( mRegisteredPlugins.find(it->GetID()) != mRegisteredPlugins.end() )
1175 it = mEffectPluginsCleared.erase(it);
1176 else
1177 ++it;
1178 }
1179}
1180
1181std::map<wxString, std::vector<wxString>> PluginManager::CheckPluginUpdates()
1182{
1183 wxArrayString pathIndex;
1184 for (auto &pair : mRegisteredPlugins) {
1185 auto &plug = pair.second;
1186
1187 // Bypass 2.1.0 placeholders...remove this after a few releases past 2.1.0
1188 if (plug.GetPluginType() != PluginTypeNone)
1189 pathIndex.push_back(plug.GetPath().BeforeFirst(wxT(';')));
1190 }
1191
1192 // Scan for NEW ones.
1193 //
1194 // Because we use the plugins "path" as returned by the providers, we can actually
1195 // have multiple providers report the same path since, at this point, they only
1196 // know that the path might possibly be one supported by the provider.
1197 //
1198 // When the user enables the plugin, each provider that reported it will be asked
1199 // to register the plugin.
1200
1201 auto& moduleManager = ModuleManager::Get();
1202 std::map<wxString, std::vector<wxString>> newPaths;
1203 for(auto& [id, provider] : moduleManager.Providers())
1204 {
1205 const auto paths = provider->FindModulePaths(*this);
1206 for(const auto& path : paths)
1207 {
1208 const auto modulePath = path.BeforeFirst(';');
1209 if (!make_iterator_range(pathIndex).contains(modulePath) ||
1210 make_iterator_range(mEffectPluginsCleared).any_of([&modulePath](const PluginDescriptor& plug) {
1211 return plug.GetPath().BeforeFirst(wxT(';')) == modulePath;
1212 })
1213 )
1214 {
1215 newPaths[modulePath].push_back(id);
1216 }
1217 }
1218 }
1219
1220 return newPaths;
1221}
1222
1224{
1225 return ModuleManager::GetID(provider);
1226}
1227
1229{
1230 return wxString::Format(wxT("%s_%s_%s_%s_%s"),
1232 wxEmptyString,
1233 command->GetVendor().Internal(),
1234 command->GetSymbol().Internal(),
1235 command->GetPath());
1236}
1237
1239{
1240 return wxString::Format(wxT("%s_%s_%s_%s_%s"),
1242 effect->GetFamily().Internal(),
1243 effect->GetVendor().Internal(),
1244 effect->GetSymbol().Internal(),
1245 effect->GetPath());
1246}
1247
1249{
1250 return wxJoin(wxArrayStringEx{
1252 effect->GetFamily().Internal(),
1253 effect->GetVendor().Internal(),
1254 effect->GetSymbol().Internal(),
1255 effect->GetPath()
1256 }, '_');
1257}
1258
1260{
1261 auto strings = wxSplit(ID, '_');
1262 if (strings.size() == 5)
1263 return strings[3];
1264 return {};
1265}
1266
1267// This string persists in configuration files
1268// So config compatibility will break if it is changed across Audacity versions
1270{
1271 wxString str;
1272
1273 switch (type)
1274 {
1275 default:
1276 case PluginTypeNone:
1277 str = wxT("Placeholder");
1278 break;
1279 case PluginTypeStub:
1280 str = wxT("Stub");
1281 break;
1282 case PluginTypeEffect:
1283 str = wxT("Effect");
1284 break;
1286 str = wxT("Generic");
1287 break;
1288 case PluginTypeExporter:
1289 str = wxT("Exporter");
1290 break;
1291 case PluginTypeImporter:
1292 str = wxT("Importer");
1293 break;
1294 case PluginTypeModule:
1296 break;
1297 }
1298
1299 return str;
1300}
1301
1303{
1304 const auto& providerID = plug.GetProviderID();
1305 auto provider = ModuleManager::Get().CreateProviderInstance(providerID, wxEmptyString);
1306
1307 if (provider == nullptr)
1308 {
1309 wxLogWarning("Unable to find a provider for '%s'", providerID);
1310 return false;
1311 }
1312
1313 if (provider->CheckPluginExist(plug.GetPath()) == false)
1314 {
1315 wxLogWarning("Plugin '%s' does not exist", plug.GetID());
1316 return false;
1317 }
1318
1319 return true;
1320}
1321
1324 PluginType type)
1325{
1326 // This will either create a NEW entry or replace an existing entry
1328
1329 plug.SetPluginType(type);
1330
1331 plug.SetID(id);
1332 plug.SetPath(ident->GetPath());
1333 plug.SetSymbol(ident->GetSymbol());
1334 plug.SetVendor(ident->GetVendor().Internal());
1335 plug.SetVersion(ident->GetVersion());
1336
1337 return plug;
1338}
1339
1341{
1342 if (!mSettings)
1343 {
1345
1346 // Check for a settings version that we can understand
1347 if (mSettings->HasEntry(SETVERKEY))
1348 {
1349 wxString setver = mSettings->Read(SETVERKEY, SETVERKEY);
1350 if (setver < SETVERCUR )
1351 {
1352 // This is where we'd put in conversion code when the
1353 // settings version changes.
1354 //
1355 // Should also check for a settings file that is newer than
1356 // what we can understand.
1357 }
1358 }
1359 else
1360 {
1361 // Make sure is has a version string
1362 mSettings->Write(SETVERKEY, SETVERCUR);
1363 mSettings->Flush();
1364 }
1365 }
1366
1367 return mSettings.get();
1368}
1369
1371{
1372 auto settings = GetSettings();
1373
1374 if(!settings->HasGroup(groupName))
1375 return false;
1376
1377 auto group = settings->BeginGroup(groupName);
1378 return !settings->GetChildGroups().empty() || !settings->GetChildKeys().empty();
1379}
1380
1381bool PluginManager::GetSubgroups(const RegistryPath & groupName, RegistryPaths & subgroups)
1382{
1383 if (groupName.empty() || !HasGroup(groupName))
1384 {
1385 return false;
1386 }
1387
1388 auto group = GetSettings()->BeginGroup(groupName);
1389 for(const auto& name : GetSettings()->GetChildGroups())
1390 subgroups.push_back(name);
1391
1392 return true;
1393}
1394
1396{
1397 return GetSettings()->Exists(key);
1398}
1399
1400template<typename T> class TD;
1401
1404{
1405 using namespace Variant;
1406 if (key.empty())
1407 return false;
1408 const auto visitor = [&](const auto var){
1409 const auto pVar = &var.get();
1410 // precondition is that defval wraps same type as var
1411 using Type = typename decltype(var)::type;
1412 const auto pDefval =
1413 std::get_if<std::reference_wrapper<const Type>>(&defval);
1414 //TD<decltype(pDefval)> defType;
1415 //return true;
1416 return GetSettings()->Read(key, pVar, pDefval->get());
1417 };
1418 return Visit(visitor, var);
1419}
1420
1422 const RegistryPath & key, ConfigConstReference value)
1423{
1424 using namespace Variant;
1425 if (key.empty())
1426 return false;
1427 const auto visitor = [&](const auto value){
1428 return GetSettings()->Write(key, value.get()) && GetSettings()->Flush();
1429 };
1430 return Visit(visitor, value);
1431}
1432
1433/* Return value is a key for lookup in a config file */
1435 ConfigurationType type, const PluginID & ID)
1436{
1437 bool shared = (type == ConfigurationType::Shared);
1438
1439 // All the strings reported by PluginDescriptor and used in this function
1440 // persist in the plugin settings configuration file, so they should not
1441 // be changed across Audacity versions, or else compatibility of the
1442 // configuration files will break.
1443
1444 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end())
1445 return {};
1446 else {
1447 const PluginDescriptor & plug = iter->second;
1448
1449 wxString id = GetPluginTypeString(plug.GetPluginType()) +
1450 wxT("_") +
1451 plug.GetEffectFamily() + // is empty for non-Effects
1452 wxT("_") +
1453 plug.GetVendor() +
1454 wxT("_") +
1455 (shared ? wxString{} : plug.GetSymbol().Internal());
1456
1457 return SETROOT +
1458 ConvertID(id) +
1459 wxCONFIG_PATH_SEPARATOR +
1460 (shared ? wxT("shared") : wxT("private")) +
1461 wxCONFIG_PATH_SEPARATOR;
1462 }
1463}
1464
1465/* Return value is a key for lookup in a config file */
1467 const PluginID & ID, const RegistryPath & group)
1468{
1469 auto path = SettingsPath(type, ID);
1470
1471 wxFileName ff(group);
1472 if (!ff.GetName().empty())
1473 {
1474 path += ff.GetFullPath(wxPATH_UNIX) + wxCONFIG_PATH_SEPARATOR;
1475 }
1476
1477 return path;
1478}
1479
1480/* Return value is a key for lookup in a config file */
1482 const RegistryPath & group, const RegistryPath & key)
1483{
1484 auto path = Group(type, ID, group);
1485 if (path.empty())
1486 {
1487 return path;
1488 }
1489
1490 return path + key;
1491}
1492
1493// Sanitize the ID...not the best solution, but will suffice until this
1494// is converted to XML. We use base64 encoding to preserve case.
1496{
1497 if (ID.StartsWith(wxT("base64:")))
1498 {
1499 wxString id = ID.Mid(7);
1500 ArrayOf<char> buf{ id.length() / 4 * 3 };
1501 id = wxString::FromUTF8(buf.get(), Base64::Decode(id, buf.get()));
1502 return id;
1503 }
1504
1505 const wxCharBuffer & buf = ID.ToUTF8();
1506 return wxT("base64:") + Base64::Encode(buf, strlen(buf));
1507}
1508
1509// This is defined out-of-line here, to keep ComponentInterface free of other
1510// #include directives.
1512{
1513 return GetSymbol().Msgid();
1514}
wxT("CloseDown"))
@ Internal
Indicates internal failure from Audacity.
static RegisteredToolbarFactory factory
Toolkit-neutral facade for basic user interface services.
wxString PluginID
#define str(a)
const TranslatableString name
Definition: Distortion.cpp:76
EffectType
@ EffectTypeHidden
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeNone
@ EffectTypeTool
@ EffectTypeProcess
XO("Cut/Copy/Paste")
wxString RegistryPath
Definition: Identifier.h:218
wxString PluginPath
type alias for identifying a Plugin supplied by a module, each module defining its own interpretation...
Definition: Identifier.h:214
std::vector< RegistryPath > RegistryPaths
Definition: Identifier.h:219
#define XPC(sing, plur, n, c)
Definition: Internat.h:98
#define _(s)
Definition: Internat.h:73
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: IteratorX.h:210
#define safenew
Definition: MemoryX.h:10
static CommandHandlerObject & ident(AudacityProject &project)
static const AudacityProject::AttachedObjects::RegisteredFactory key
PluginType
@ PluginTypeStub
@ PluginTypeModule
@ PluginTypeAudacityCommand
@ PluginTypeExporter
@ PluginTypeNone
@ PluginTypeEffect
@ PluginTypeImporter
bool Regver_lt(const PluginRegistryVersion &regver1, const PluginRegistryVersion &regver2)
bool Regver_le(const PluginRegistryVersion &regver1, const PluginRegistryVersion &regver2)
wxString PluginRegistryVersion
Type of plugin registry version information.
#define KEY_EFFECTAUTOMATABLE
#define REGVERKEY
#define KEY_PROVIDERID
#define KEY_SYMBOL
#define KEY_IMPORTEREXTENSIONS
#define KEY_EFFECTTYPE_TOOL
#define KEY_VENDOR
#define KEY_PATH
#define KEY_IMPORTERIDENT
static PluginManager::ConfigFactory sFactory
#define KEY_EFFECTTYPE_GENERATE
#define SETROOT
#define KEY_EFFECTTYPE_PROCESS
#define KEY_EFFECTINTERACTIVE
#define KEY_EFFECTTYPE_HIDDEN
#define KEY_ENABLED
#define SETVERKEY
#define SETVERCUR
#define KEY_EFFECTREALTIME
#define REGROOT
#define KEY_VERSION
#define KEY_EFFECTTYPE_NONE
#define KEY_EFFECTTYPE
#define KEY_EFFECTFAMILY
#define KEY_NAME
#define KEY_VALID
#define KEY_EFFECTTYPE_ANALYZE
#define KEY_DESCRIPTION
#define KEY_EFFECTDEFAULT
constexpr auto REGVERCUR
#define NYQUIST_PROMPT_ID
Generalized interface for discovery of plug-ins for one protocol.
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
static const AttachedProjectObjects::RegisteredFactory manager
static TranslatableStrings names
Definition: TagsEditor.cpp:153
static Settings & settings()
Definition: TrackInfo.cpp:47
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
emulates std::visit for one visitor
int id
ComponentInterface provides name / vendor / version functions to identify plugins....
virtual PluginPath GetPath() const =0
virtual VendorSymbol GetVendor() const =0
TranslatableString GetName() const
virtual ComponentInterfaceSymbol GetSymbol() const =0
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
const wxString & Internal() const
const TranslatableString & Msgid() const
EffectDefinitionInterface is a ComponentInterface that adds some basic read-only information about ef...
virtual EffectType GetClassification() const
Determines which menu it appears in; default same as GetType().
virtual bool IsDefault() const =0
Whether the effect sorts "above the line" in the menus.
virtual bool IsInteractive() const =0
Whether the effect needs a dialog for entry of settings.
virtual bool SupportsAutomation() const =0
Whether the effect has any automatable controls.
virtual RealtimeSince RealtimeSupport() const =0
Since which version of Audacity has the effect supported realtime?
virtual EffectFamilySymbol GetFamily() const =0
Report identifier and user-visible name of the effect protocol.
Abstract base class used in importing a file.
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
static ModuleManager & Get()
static PluginID GetID(PluginProvider *provider)
static wxString GetPluginTypeString()
PluginProvider * CreateProviderInstance(const PluginID &provider, const PluginPath &path)
bool CheckPluginExist(const PluginID &providerId, const PluginPath &path)
CallbackReturn Publish(const PluginsChangedMessage &message)
Send a message to connected callbacks.
Definition: Observer.h:207
static const FilePath & GetExecutablePath()
void SetEnabled(bool enable)
void SetEffectLegacy(bool legacy)
void SetImporterExtensions(FileExtensions extensions)
const ComponentInterfaceSymbol & GetSymbol() const
PluginType GetPluginType() const
void SetVendor(const wxString &vendor)
void SetImporterIdentifier(const wxString &identifier)
wxString GetEffectFamily() const
void SetPath(const PluginPath &path)
void SetValid(bool valid)
const wxString & GetID() const
const wxString & GetVendor() const
void SetSymbol(const ComponentInterfaceSymbol &symbol)
void SetProviderID(const PluginID &providerID)
const PluginPath & GetPath() const
void SetID(const PluginID &ID)
void SetEffectType(EffectType type)
void SetEffectFamily(const wxString &family)
void SetPluginType(PluginType type)
const wxString & GetProviderID() const
void SetEffectAutomatable(bool automatable)
void SetEffectDefault(bool dflt)
void SetEffectInteractive(bool interactive)
void SetRealtimeSupport(EffectDefinitionInterface::RealtimeSince realtime)
void SetVersion(const wxString &version)
void DeserializeRealtimeSupport(const wxString &value)
for deserialization
void Advance(bool incrementing)
Iterator(PluginManager &manager)
Iterates all, even disabled.
const PluginManager & mPm
PluginMap::iterator mIterator
PluginManager maintains a list of all plug ins. That covers modules, effects, generators,...
Definition: PluginManager.h:51
static PluginID OldGetID(const EffectDefinitionInterface *effect)
bool GetConfigSubgroups(ConfigurationType type, const PluginID &ID, const RegistryPath &group, RegistryPaths &subgroups) override
bool HasConfigGroup(ConfigurationType type, const PluginID &ID, const RegistryPath &group)
bool IsPluginEnabled(const PluginID &ID)
bool GetConfigValue(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key, ConfigReference var, ConfigConstReference defval) override
std::vector< PluginDescriptor > mEffectPluginsCleared
void ClearEffectPlugins()
PluginRegistryVersion mRegver
std::map< wxString, std::vector< wxString > > CheckPluginUpdates()
Ensures that all currently registered plugins still exist and scans for new ones.
bool IsPluginRegistered(const PluginPath &path, const TranslatableString *pSymbol) override
Was the plugin registry already populated for a path (maybe from loading the config file)?
bool IsPluginLoaded(const wxString &ID) const
RegistryPath Group(ConfigurationType type, const PluginID &ID, const RegistryPath &group)
bool HasConfigValue(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key) override
std::function< std::unique_ptr< audacity::BasicSettings >(const FilePath &localFilename) > ConfigFactory
void Save()
Save to preferences.
void UnregisterPlugin(const PluginID &ID)
void FindFilesInPathList(const wxString &pattern, const FilePaths &pathList, FilePaths &files, bool directories=false) override
bool GetSubgroups(const RegistryPath &group, RegistryPaths &subgroups)
static Identifier GetEffectNameFromID(const PluginID &ID)
static PluginID GetID(PluginProvider *provider)
bool HasGroup(const RegistryPath &group)
void LoadGroup(audacity::BasicSettings *pRegistry, PluginType type)
void Load()
Load from preferences.
Range PluginsOfType(int type)
PluginDescriptor & CreatePlugin(const PluginID &id, ComponentInterface *ident, PluginType type)
static bool IsPluginAvailable(const PluginDescriptor &plug)
const PluginRegistryVersion & GetRegistryVersion() const override
RegistryPath Key(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key)
static std::unique_ptr< PluginManager > mInstance
void Initialize(ConfigFactory factory)
RegistryPath GetPluginEnabledSetting(const PluginID &ID) const
bool DropFile(const wxString &fileName)
const PluginDescriptor * GetPlugin(const PluginID &ID) const
void EnablePlugin(const PluginID &ID, bool enable)
void RegisterPlugin(PluginDescriptor &&desc)
bool RemoveConfig(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key) override
audacity::BasicSettings * GetSettings()
void SaveGroup(audacity::BasicSettings *pRegistry, PluginType type)
PluginMap mRegisteredPlugins
void InitializePlugins()
wxString ConvertID(const PluginID &ID)
std::unique_ptr< audacity::BasicSettings > mSettings
RegistryPath SettingsPath(ConfigurationType type, const PluginID &ID)
bool SetConfigValue(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key, ConfigConstReference value) override
int GetPluginCount(PluginType type)
static wxString GetPluginTypeString(PluginType type)
void NotifyPluginsChanged()
bool RemoveConfigSubgroup(ConfigurationType type, const PluginID &ID, const RegistryPath &group) override
std::map< PluginID, std::unique_ptr< ComponentInterface > > mLoadedInterfaces
const ComponentInterfaceSymbol & GetSymbol(const PluginID &ID)
static PluginManager & Get()
static const PluginID & AudacityCommandRegistrationCallback(PluginProvider *provider, ComponentInterface *ident)
PluginSettings::ConfigReference ConfigReference
static const PluginID & DefaultRegistrationCallback(PluginProvider *provider, ComponentInterface *ident)
PluginSettings::ConfigConstReference ConfigConstReference
virtual EffectFamilySymbol GetOptionalFamilySymbol()=0
A symbol identifying the family of plug-ins provided by this.
virtual std::unique_ptr< ComponentInterface > LoadPlugin(const PluginPath &path)=0
Load the plug-in at a path reported by DiscoverPluginsAtPath.
virtual FilePath InstallPath()=0
Where plug-in files should be copied to install them.
Holds a msgid for the translation catalog; may also bind format arguments.
Base class for objects that provide facility to store data persistently, and access it with string ke...
Definition: BasicSettings.h:31
virtual bool Flush() noexcept=0
virtual bool Exists(const wxString &key) const
Returns true if group or entry exists.
GroupScope BeginGroup(const wxString &prefix)
Appends a prefix to the current group or sets a new absolute path. Group that was set as current befo...
bool DeleteGroup(const wxString &key)
Deletes specified group if exists.
virtual bool Write(const wxString &key, bool value)=0
bool DeleteEntry(const wxString &key)
Deletes specified entry if exists.
virtual bool Read(const wxString &key, bool *value) const =0
virtual wxArrayString GetChildGroups() const =0
Returns all child groups within the current group.
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
STRINGS_API wxString Encode(const void *in, int len)
Definition: Base64.cpp:27
STRINGS_API int Decode(const wxString &in, void *out)
Definition: Base64.cpp:67
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:279
FILES_API FilePath PlugInDir()
The user plug-in directory (not a system one)
FILES_API bool DoCopyFile(const FilePath &file1, const FilePath &file2, bool overwrite=true)
FILES_API FilePath PluginRegistry()
FILES_API FilePath PluginSettings()
MENUS_API void Visit(Visitor< Traits > &visitor, AudacityProject &project)
const TranslatableString desc
Definition: ExportPCM.cpp:51
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
const char * begin(const char *str) noexcept
Definition: StringUtils.h:101
MessageBoxOptions && Caption(TranslatableString caption_) &&
Definition: BasicUI.h:101