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