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 this->NotifyPluginsChanged();
529 }
530
531 return true;
532 }
533 }
534 }
535
536 return false;
537}
538
540{
541 // Create/Open the registry
542 auto pRegistry = sFactory(FileNames::PluginRegistry());
543 auto &registry = *pRegistry;
544
545 // If this group doesn't exist then we have something that's not a registry.
546 // We should probably warn the user, but it's pretty unlikely that this will happen.
547 if (!registry.HasGroup(REGROOT))
548 {
549 // Must start over
550 // This DeleteAll affects pluginregistry.cfg only, not audacity.cfg
551 // That is, the memory of on/off states of effect (and generator,
552 // analyzer, and tool) plug-ins
553 registry.DeleteAll();
554 registry.Flush();
555 return;
556 }
557
558 // Check for a registry version that we can understand
559 // TODO: Should also check for a registry file that is newer than
560 // what we can understand.
561 mRegver = registry.Read(REGVERKEY);
562 if (Regver_lt(mRegver, "1.1")) {
563 // Conversion code here, for when registry version changes.
564
565 // We iterate through the effects, possibly updating their info.
566 wxString groupName;
567 long groupIndex;
568 wxString group = GetPluginTypeString(PluginTypeEffect);
569 wxString cfgPath = REGROOT + group + wxCONFIG_PATH_SEPARATOR;
570 wxArrayString groupsToDelete;
571
572 registry.SetPath(cfgPath);
573 for (bool cont = registry.GetFirstGroup(groupName, groupIndex);
574 cont;
575 registry.SetPath(cfgPath),
576 cont = registry.GetNextGroup(groupName, groupIndex))
577 {
578 registry.SetPath(groupName);
579 wxString effectSymbol = registry.Read(KEY_SYMBOL, "");
580 wxString effectVersion = registry.Read(KEY_VERSION, "");
581
582
583 // For 2.3.0 the plugins we distribute have moved around.
584 // So we upped the registry version number to 1.1.
585 // These particular config edits were originally written to fix Bug 1914.
586 if (Regver_le(mRegver, "1.0")) {
587 // Nyquist prompt is a built-in that has moved to the tools menu.
588 if (effectSymbol == NYQUIST_PROMPT_ID) {
589 registry.Write(KEY_EFFECTTYPE, "Tool");
590 // Old version of SDE was in Analyze menu. Now it is in Tools.
591 // We don't want both the old and the new.
592 } else if ((effectSymbol == "Sample Data Export") && (effectVersion == "n/a")) {
593 groupsToDelete.push_back(cfgPath + groupName);
594 // Old version of SDI was in Generate menu. Now it is in Tools.
595 } else if ((effectSymbol == "Sample Data Import") && (effectVersion == "n/a")) {
596 groupsToDelete.push_back(cfgPath + groupName);
597 }
598 }
599
600 }
601 // Doing the deletion within the search loop risked skipping some items,
602 // hence the delayed delete.
603 for (unsigned int i = 0; i < groupsToDelete.size(); i++) {
604 registry.DeleteGroup(groupsToDelete[i]);
605 }
606 registry.SetPath("");
607 // Updates done. Make sure we read the updated data later.
608 registry.Flush();
609 }
610
611 // Load all provider plugins first
612 LoadGroup(&registry, PluginTypeModule);
613
614 // Now the rest
615 LoadGroup(&registry, PluginTypeEffect);
617 LoadGroup(&registry, PluginTypeExporter);
618 LoadGroup(&registry, PluginTypeImporter);
619
620 LoadGroup(&registry, PluginTypeStub);
621 return;
622}
623
625{
626#ifdef __WXMAC__
627 // Bug 1590: On Mac, we should purge the registry of Nyquist plug-ins
628 // bundled with other versions of Audacity, assuming both versions
629 // were properly installed in /Applications (or whatever it is called in
630 // your locale)
631
632 const auto fullExePath = PlatformCompatibility::GetExecutablePath();
633
634 // Strip rightmost path components up to *.app
635 wxFileName exeFn{ fullExePath };
636 exeFn.SetEmptyExt();
637 exeFn.SetName(wxString{});
638 while(exeFn.GetDirCount() && !exeFn.GetDirs().back().EndsWith(".app"))
639 exeFn.RemoveLastDir();
640
641 const auto goodPath = exeFn.GetPath();
642
643 if(exeFn.GetDirCount())
644 exeFn.RemoveLastDir();
645 const auto possiblyBadPath = exeFn.GetPath();
646
647 auto AcceptPath = [&](const wxString &path) {
648 if (!path.StartsWith(possiblyBadPath))
649 // Assume it's not under /Applications
650 return true;
651 if (path.StartsWith(goodPath))
652 // It's bundled with this executable
653 return true;
654 return false;
655 };
656#else
657 auto AcceptPath = [](const wxString&){ return true; };
658#endif
659
660 wxString strVal;
661 bool boolVal;
662 wxString groupName;
663 long groupIndex;
664 wxString group = GetPluginTypeString(type);
665 wxString cfgPath = REGROOT + group + wxCONFIG_PATH_SEPARATOR;
666
667 pRegistry->SetPath(cfgPath);
668 for (bool cont = pRegistry->GetFirstGroup(groupName, groupIndex);
669 cont;
670 pRegistry->SetPath(cfgPath),
671 cont = pRegistry->GetNextGroup(groupName, groupIndex))
672 {
673 PluginDescriptor plug;
674
675 pRegistry->SetPath(groupName);
676
677 groupName = ConvertID(groupName);
678
679 // Bypass group if the ID is already in use
680 if (mRegisteredPlugins.count(groupName))
681 continue;
682
683 // Set the ID and type
684 plug.SetID(groupName);
685 plug.SetPluginType(type);
686
687 // Get the provider ID and bypass group if not found
688 if (!pRegistry->Read(KEY_PROVIDERID, &strVal, wxEmptyString))
689 {
690 // Bypass group if the provider isn't valid
691 if (!strVal.empty() && !mRegisteredPlugins.count(strVal))
692 continue;
693 }
694 plug.SetProviderID(PluginID(strVal));
695
696 // Get the path (optional)
697 pRegistry->Read(KEY_PATH, &strVal, wxEmptyString);
698 if (!AcceptPath(strVal))
699 // Ignore the obsolete path in the config file, during session,
700 // but don't remove it from the file. Maybe you really want to
701 // switch back to the other version of Audacity and lose nothing.
702 continue;
703 plug.SetPath(strVal);
704
705 /*
706 // PRL: Ignore names written in configs before 2.3.0!
707 // use Internal string only! Let the present version of Audacity map
708 // that to a user-visible string.
709 // Get the name and bypass group if not found
710 if (!pRegistry->Read(KEY_NAME, &strVal))
711 {
712 continue;
713 }
714 plug.SetName(strVal);
715 */
716
717 // Get the symbol...Audacity 2.3.0 or later requires it
718 // bypass group if not found
719 // Note, KEY_SYMBOL started getting written to config files in 2.1.0.
720 // KEY_NAME (now ignored) was written before that, but only for VST
721 // effects.
722 if (!pRegistry->Read(KEY_SYMBOL, &strVal))
723 continue;
724
725 // Related to Bug2778: config file only remembered an internal name,
726 // so this symbol may not contain the correct TranslatableString.
727 // See calls to IsPluginRegistered which can correct that.
728 plug.SetSymbol(strVal);
729
730 // Get the version and bypass group if not found
731 if (!pRegistry->Read(KEY_VERSION, &strVal))
732 {
733 continue;
734 }
735 plug.SetVersion(strVal);
736
737 // Get the vendor and bypass group if not found
738 if (!pRegistry->Read(KEY_VENDOR, &strVal))
739 {
740 continue;
741 }
742 plug.SetVendor( strVal );
743
744#if 0
745 // This was done before version 2.2.2, but the value was not really used
746 // But absence of a value will cause early versions to skip the group
747 // Therefore we still write a blank to keep pluginregistry.cfg
748 // backwards-compatible
749
750 // Get the description and bypass group if not found
751 if (!pRegistry->Read(KEY_DESCRIPTION, &strVal))
752 {
753 continue;
754 }
755#endif
756
757 // Is it enabled...default to no if not found
758 pRegistry->Read(KEY_ENABLED, &boolVal, false);
759 plug.SetEnabled(boolVal);
760
761 // Is it valid...default to no if not found
762 pRegistry->Read(KEY_VALID, &boolVal, false);
763 plug.SetValid(boolVal);
764
765 switch (type)
766 {
767 case PluginTypeModule:
768 {
769 // Nothing to do here yet
770 }
771 break;
772
773 case PluginTypeEffect:
774 {
775 // Get the effect type and bypass group if not found
776 if (!pRegistry->Read(KEY_EFFECTTYPE, &strVal))
777 continue;
778
779 if (strVal == KEY_EFFECTTYPE_NONE)
781 else if (strVal == KEY_EFFECTTYPE_ANALYZE)
783 else if (strVal == KEY_EFFECTTYPE_GENERATE)
785 else if (strVal == KEY_EFFECTTYPE_PROCESS)
787 else if (strVal == KEY_EFFECTTYPE_TOOL)
789 else if (strVal == KEY_EFFECTTYPE_HIDDEN)
791 else
792 continue;
793
794 // Get the effect family and bypass group if not found
795 if (!pRegistry->Read(KEY_EFFECTFAMILY, &strVal))
796 {
797 continue;
798 }
799 plug.SetEffectFamily(strVal);
800
801 // Is it a default (above the line) effect and bypass group if not found
802 if (!pRegistry->Read(KEY_EFFECTDEFAULT, &boolVal))
803 {
804 continue;
805 }
806 plug.SetEffectDefault(boolVal);
807
808 // Is it an interactive effect and bypass group if not found
809 if (!pRegistry->Read(KEY_EFFECTINTERACTIVE, &boolVal))
810 {
811 continue;
812 }
813 plug.SetEffectInteractive(boolVal);
814
815 // Is it a realtime capable effect and bypass group if not found
816 if (!pRegistry->Read(KEY_EFFECTREALTIME, &strVal))
817 {
818 continue;
819 }
820 plug.DeserializeRealtimeSupport(strVal);
821
822 // Does the effect support automation...bypass group if not found
823 if (!pRegistry->Read(KEY_EFFECTAUTOMATABLE, &boolVal))
824 {
825 continue;
826 }
827 plug.SetEffectAutomatable(boolVal);
828 }
829 break;
830
832 {
833 // Get the importer identifier and bypass group if not found
834 if (!pRegistry->Read(KEY_IMPORTERIDENT, &strVal))
835 {
836 continue;
837 }
838 plug.SetImporterIdentifier(strVal);
839
840 // Get the importer extensions and bypass group if not found
841 if (!pRegistry->Read(KEY_IMPORTEREXTENSIONS, &strVal))
842 {
843 continue;
844 }
845 FileExtensions extensions;
846 wxStringTokenizer tkr(strVal, wxT(":"));
847 while (tkr.HasMoreTokens())
848 {
849 extensions.push_back(tkr.GetNextToken());
850 }
851 plug.SetImporterExtensions(extensions);
852 }
853 break;
854
855 case PluginTypeStub:
856 {
857 // Nothing additional for stubs
858 }
859 break;
860
861 // Not used by 2.1.1 or greater and should be removed after a few releases past 2.1.0.
862 case PluginTypeNone:
863 {
864 // Used for stub groups
865 }
866 break;
867
868 default:
869 {
870 continue;
871 }
872 }
873
874 // Everything checked out...accept the plugin
875 mRegisteredPlugins[groupName] = std::move(plug);
876 }
877
878 return;
879}
880
882{
883 // Create/Open the registry
884 auto pRegistry = sFactory(FileNames::PluginRegistry());
885 auto &registry = *pRegistry;
886
887 // Clear pluginregistry.cfg (not audacity.cfg)
888 registry.DeleteAll();
889
890 // Save the individual groups
891 SaveGroup(&registry, PluginTypeEffect);
892 SaveGroup(&registry, PluginTypeExporter);
894 SaveGroup(&registry, PluginTypeImporter);
895 SaveGroup(&registry, PluginTypeStub);
896
897 // Not used by 2.1.1 or greater, but must save to allow users to switch between 2.1.0
898 // and 2.1.1+. This should be removed after a few releases past 2.1.0.
899 //SaveGroup(&registry, PluginTypeNone);
900
901 // And now the providers
902 SaveGroup(&registry, PluginTypeModule);
903
904 // Write the version string
905 registry.Write(REGVERKEY, REGVERCUR);
906
907 // Just to be safe
908 registry.Flush();
909
911}
912
914{
916}
917
919{
920 return mRegver;
921}
922
924{
925 wxString group = GetPluginTypeString(type);
926 for (auto &pair : mRegisteredPlugins) {
927 auto & plug = pair.second;
928
929 if (plug.GetPluginType() != type)
930 {
931 continue;
932 }
933
934 pRegistry->SetPath(REGROOT + group + wxCONFIG_PATH_SEPARATOR + ConvertID(plug.GetID()));
935
936 pRegistry->Write(KEY_PATH, plug.GetPath());
937
938 // See comments with the corresponding load-time call to SetSymbol().
939 pRegistry->Write(KEY_SYMBOL, plug.GetSymbol().Internal());
940
941 // PRL: Writing KEY_NAME which is no longer read, but older Audacity
942 // versions expect to find it.
943 pRegistry->Write(KEY_NAME, plug.GetSymbol().Msgid().MSGID());
944
945 pRegistry->Write(KEY_VERSION, plug.GetUntranslatedVersion());
946 pRegistry->Write(KEY_VENDOR, plug.GetVendor());
947 // Write a blank -- see comments in LoadGroup:
948 pRegistry->Write(KEY_DESCRIPTION, wxString{});
949 pRegistry->Write(KEY_PROVIDERID, plug.GetProviderID());
950 pRegistry->Write(KEY_ENABLED, plug.IsEnabled());
951 pRegistry->Write(KEY_VALID, plug.IsValid());
952
953 switch (type)
954 {
955 case PluginTypeModule:
956 break;
957
958 case PluginTypeEffect:
959 {
960 EffectType etype = plug.GetEffectType();
961 wxString stype;
962 if (etype == EffectTypeNone)
963 stype = KEY_EFFECTTYPE_NONE;
964 else if (etype == EffectTypeAnalyze)
966 else if (etype == EffectTypeGenerate)
968 else if (etype == EffectTypeProcess)
970 else if (etype == EffectTypeTool)
971 stype = KEY_EFFECTTYPE_TOOL;
972 else if (etype == EffectTypeHidden)
973 stype = KEY_EFFECTTYPE_HIDDEN;
974
975 pRegistry->Write(KEY_EFFECTTYPE, stype);
976 pRegistry->Write(KEY_EFFECTFAMILY, plug.GetEffectFamily());
977 pRegistry->Write(KEY_EFFECTDEFAULT, plug.IsEffectDefault());
978 pRegistry->Write(KEY_EFFECTINTERACTIVE, plug.IsEffectInteractive());
979 pRegistry->Write(KEY_EFFECTREALTIME, plug.SerializeRealtimeSupport());
980 pRegistry->Write(KEY_EFFECTAUTOMATABLE, plug.IsEffectAutomatable());
981 }
982 break;
983
985 {
986 pRegistry->Write(KEY_IMPORTERIDENT, plug.GetImporterIdentifier());
987 const auto & extensions = plug.GetImporterExtensions();
988 wxString strExt;
989 for (size_t i = 0, cnt = extensions.size(); i < cnt; i++)
990 {
991 strExt += extensions[i] + wxT(":");
992 }
993 strExt.RemoveLast(1);
994 pRegistry->Write(KEY_IMPORTEREXTENSIONS, strExt);
995 }
996 break;
997
998 default:
999 break;
1000 }
1001 }
1002
1003 return;
1004}
1005
1006// Here solely for the purpose of Nyquist Workbench until
1007// a better solution is devised.
1009 std::unique_ptr<EffectDefinitionInterface> effect, PluginType type)
1010{
1011 PluginDescriptor & plug =
1012 CreatePlugin(GetID(effect.get()), effect.get(), type);
1013
1014 plug.SetEffectType(effect->GetType());
1015 plug.SetEffectFamily(effect->GetFamily().Internal());
1016 plug.SetEffectInteractive(effect->IsInteractive());
1017 plug.SetEffectDefault(effect->IsDefault());
1018 plug.SetRealtimeSupport(effect->RealtimeSupport());
1019 plug.SetEffectAutomatable(effect->SupportsAutomation());
1020
1021 plug.SetEffectLegacy(true);
1022 plug.SetEnabled(true);
1023 plug.SetValid(true);
1024
1025 mLoadedInterfaces[plug.GetID()] = std::move(effect);
1026
1027 return plug.GetID();
1028}
1029
1031{
1032 mRegisteredPlugins.erase(ID);
1033 mLoadedInterfaces.erase(ID);
1034}
1035
1037{
1038 return count_if(mRegisteredPlugins.begin(), mRegisteredPlugins.end(), [type](auto &pair){
1039 return pair.second.GetPluginType() == type; });
1040}
1041
1043{
1044 if (auto iter = mRegisteredPlugins.find(ID); iter != mRegisteredPlugins.end())
1045 return &iter->second;
1046
1048 .find_if([&ID](const PluginDescriptor& plug) {
1049 return plug.GetID() == ID;
1050 });
1051 if (iter2 != mEffectPluginsCleared.end())
1052 return &(*iter2);
1053
1054 return nullptr;
1055}
1056
1058{
1059 const auto end = mPm.mRegisteredPlugins.end();
1060 if (incrementing && mIterator != end)
1061 ++mIterator;
1063 for (; mIterator != end; ++mIterator) {
1064 auto &plug = mIterator->second;
1065 if (!all && !(plug.IsValid() && plug.IsEnabled()))
1066 continue;
1067 auto plugType = plug.GetPluginType();
1068 if ((mPluginType == PluginTypeNone || (plugType & mPluginType)) &&
1069 (mEffectType == EffectTypeNone || plug.GetEffectType() == mEffectType)) {
1070 if (!all && (plugType & PluginTypeEffect)) {
1071 // This preference may be written by EffectsPrefs
1072 auto setting = mPm.GetPluginEnabledSetting( plug );
1073 if (!(setting.empty() || gPrefs->Read( setting, true )))
1074 continue;
1075 }
1076 // Pause iteration at this match
1077 break;
1078 }
1079 }
1080}
1081
1083: mPm{ manager }
1084, mIterator{ manager.mRegisteredPlugins.begin() }
1085{
1086}
1087
1089: mPm{ manager }
1090, mIterator{ manager.mRegisteredPlugins.begin() }
1091, mPluginType{ type }
1092{
1093 Advance(false);
1094}
1095
1097: mPm{ manager }
1098, mIterator{ manager.mRegisteredPlugins.begin() }
1099, mEffectType{ type }
1100{
1101 Advance(false);
1102}
1103
1105{
1106 Advance(true);
1107 return *this;
1108}
1109
1111{
1112 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end())
1113 return false;
1114 else
1115 return iter->second.IsEnabled();
1116}
1117
1118void PluginManager::EnablePlugin(const PluginID & ID, bool enable)
1119{
1120 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end())
1121 return;
1122 else
1123 iter->second.SetEnabled(enable);
1124}
1125
1127{
1128 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end()) {
1129 static ComponentInterfaceSymbol empty;
1130 return empty;
1131 }
1132 else
1133 return iter->second.GetSymbol();
1134}
1135
1137{
1138 if(auto it = mLoadedInterfaces.find(ID); it != mLoadedInterfaces.end())
1139 return it->second.get();
1140
1141 if(auto it = mRegisteredPlugins.find(ID); it != mRegisteredPlugins.end())
1142 {
1143 auto& desc = it->second;
1144 if(desc.GetPluginType() == PluginTypeModule)
1145 //it's very likely that this code path is not used
1146 return ModuleManager::Get().CreateProviderInstance(desc.GetID(), desc.GetPath());
1147
1148 if(auto provider = ModuleManager::Get().CreateProviderInstance(desc.GetProviderID(), wxEmptyString))
1149 {
1150 auto pluginInterface = provider->LoadPlugin(desc.GetPath());
1151 auto result = pluginInterface.get();
1152 mLoadedInterfaces[desc.GetID()] = std::move(pluginInterface);
1153 return result;
1154 }
1155 }
1156 return nullptr;
1157}
1158
1160{
1161 mEffectPluginsCleared.clear();
1162
1163 for ( auto it = mRegisteredPlugins.cbegin(); it != mRegisteredPlugins.cend(); )
1164 {
1165 const auto& desc = it->second;
1166 const auto type = desc.GetPluginType();
1167
1168 if (type == PluginTypeEffect || type == PluginTypeStub)
1169 {
1170 mEffectPluginsCleared.push_back(desc);
1171 it = mRegisteredPlugins.erase(it);
1172 }
1173 else
1174 {
1175 ++it;
1176 }
1177 }
1178
1179 // Repeat what usually happens at startup
1180 // This prevents built-in plugins to appear in the plugin validation list
1181 for (auto& [_, provider] : ModuleManager::Get().Providers())
1182 provider->AutoRegisterPlugins(*this);
1183
1184 // Remove auto registered plugins from "cleared" list
1185 for ( auto it = mEffectPluginsCleared.begin(); it != mEffectPluginsCleared.end(); )
1186 {
1187 if ( mRegisteredPlugins.find(it->GetID()) != mRegisteredPlugins.end() )
1188 it = mEffectPluginsCleared.erase(it);
1189 else
1190 ++it;
1191 }
1192}
1193
1194std::map<wxString, std::vector<wxString>> PluginManager::CheckPluginUpdates()
1195{
1196 wxArrayString pathIndex;
1197 for (auto &pair : mRegisteredPlugins) {
1198 auto &plug = pair.second;
1199
1200 // Bypass 2.1.0 placeholders...remove this after a few releases past 2.1.0
1201 if (plug.GetPluginType() != PluginTypeNone)
1202 pathIndex.push_back(plug.GetPath().BeforeFirst(wxT(';')));
1203 }
1204
1205 // Scan for NEW ones.
1206 //
1207 // Because we use the plugins "path" as returned by the providers, we can actually
1208 // have multiple providers report the same path since, at this point, they only
1209 // know that the path might possibly be one supported by the provider.
1210 //
1211 // When the user enables the plugin, each provider that reported it will be asked
1212 // to register the plugin.
1213
1214 auto& moduleManager = ModuleManager::Get();
1215 std::map<wxString, std::vector<wxString>> newPaths;
1216 for(auto& [id, provider] : moduleManager.Providers())
1217 {
1218 const auto paths = provider->FindModulePaths(*this);
1219 for(const auto& path : paths)
1220 {
1221 const auto modulePath = path.BeforeFirst(';');
1222 if (!make_iterator_range(pathIndex).contains(modulePath) ||
1223 make_iterator_range(mEffectPluginsCleared).any_of([&modulePath](const PluginDescriptor& plug) {
1224 return plug.GetPath().BeforeFirst(wxT(';')) == modulePath;
1225 })
1226 )
1227 {
1228 newPaths[modulePath].push_back(id);
1229 }
1230 }
1231 }
1232
1233 return newPaths;
1234}
1235
1237{
1238 return ModuleManager::GetID(provider);
1239}
1240
1242{
1243 return wxString::Format(wxT("%s_%s_%s_%s_%s"),
1245 wxEmptyString,
1246 command->GetVendor().Internal(),
1247 command->GetSymbol().Internal(),
1248 command->GetPath());
1249}
1250
1252{
1253 return wxString::Format(wxT("%s_%s_%s_%s_%s"),
1255 effect->GetFamily().Internal(),
1256 effect->GetVendor().Internal(),
1257 effect->GetSymbol().Internal(),
1258 effect->GetPath());
1259}
1260
1262{
1263 return wxJoin(wxArrayStringEx{
1265 effect->GetFamily().Internal(),
1266 effect->GetVendor().Internal(),
1267 effect->GetSymbol().Internal(),
1268 effect->GetPath()
1269 }, '_');
1270}
1271
1273{
1274 auto strings = wxSplit(ID, '_');
1275 if (strings.size() == 5)
1276 return strings[3];
1277 return {};
1278}
1279
1280// This string persists in configuration files
1281// So config compatibility will break if it is changed across Audacity versions
1283{
1284 wxString str;
1285
1286 switch (type)
1287 {
1288 default:
1289 case PluginTypeNone:
1290 str = wxT("Placeholder");
1291 break;
1292 case PluginTypeStub:
1293 str = wxT("Stub");
1294 break;
1295 case PluginTypeEffect:
1296 str = wxT("Effect");
1297 break;
1299 str = wxT("Generic");
1300 break;
1301 case PluginTypeExporter:
1302 str = wxT("Exporter");
1303 break;
1304 case PluginTypeImporter:
1305 str = wxT("Importer");
1306 break;
1307 case PluginTypeModule:
1309 break;
1310 }
1311
1312 return str;
1313}
1314
1316{
1317 const auto& providerID = plug.GetProviderID();
1318 auto provider = ModuleManager::Get().CreateProviderInstance(providerID, wxEmptyString);
1319
1320 if (provider == nullptr)
1321 {
1322 wxLogWarning("Unable to find a provider for '%s'", providerID);
1323 return false;
1324 }
1325
1326 if (provider->CheckPluginExist(plug.GetPath()) == false)
1327 {
1328 wxLogWarning("Plugin '%s' does not exist", plug.GetID());
1329 return false;
1330 }
1331
1332 return true;
1333}
1334
1337 PluginType type)
1338{
1339 // This will either create a NEW entry or replace an existing entry
1341
1342 plug.SetPluginType(type);
1343
1344 plug.SetID(id);
1345 plug.SetPath(ident->GetPath());
1346 plug.SetSymbol(ident->GetSymbol());
1347 plug.SetVendor(ident->GetVendor().Internal());
1348 plug.SetVersion(ident->GetVersion());
1349
1350 return plug;
1351}
1352
1354{
1355 if (!mSettings)
1356 {
1358
1359 // Check for a settings version that we can understand
1360 if (mSettings->HasEntry(SETVERKEY))
1361 {
1362 wxString setver = mSettings->Read(SETVERKEY, SETVERKEY);
1363 if (setver < SETVERCUR )
1364 {
1365 // This is where we'd put in conversion code when the
1366 // settings version changes.
1367 //
1368 // Should also check for a settings file that is newer than
1369 // what we can understand.
1370 }
1371 }
1372 else
1373 {
1374 // Make sure is has a version string
1375 mSettings->Write(SETVERKEY, SETVERCUR);
1376 mSettings->Flush();
1377 }
1378 }
1379
1380 return mSettings.get();
1381}
1382
1384{
1385 auto settings = GetSettings();
1386
1387 bool res = settings->HasGroup(group);
1388 if (res)
1389 {
1390 // The group exists, but empty groups aren't considered valid
1391 wxString oldPath = settings->GetPath();
1392 settings->SetPath(group);
1393 res = settings->GetNumberOfEntries() || settings->GetNumberOfGroups();
1394 settings->SetPath(oldPath);
1395 }
1396
1397 return res;
1398}
1399
1401{
1402 if (group.empty() || !HasGroup(group))
1403 {
1404 return false;
1405 }
1406
1407 wxString path = GetSettings()->GetPath();
1408 GetSettings()->SetPath(group);
1409
1410 wxString name;
1411 long index = 0;
1412 if (GetSettings()->GetFirstGroup(name, index))
1413 {
1414 do
1415 {
1416 subgroups.push_back(name);
1417 } while (GetSettings()->GetNextGroup(name, index));
1418 }
1419
1420 GetSettings()->SetPath(path);
1421
1422 return true;
1423}
1424
1426{
1427 return GetSettings()->Exists(key);
1428}
1429
1432{
1433 if (key.empty())
1434 return false;
1435 const auto visitor = [&](const auto var){
1436 const auto pVar = &var.get();
1437 // precondition is that defval wraps same type as var
1438 using Type = typename decltype(var)::type;
1439 const auto pDefval =
1440 std::get_if<std::reference_wrapper<const Type>>(&defval);
1441 return GetSettings()->Read(key, pVar, *pDefval);
1442 };
1443 return Visit(visitor, var);
1444}
1445
1447 const RegistryPath & key, ConfigConstReference value)
1448{
1449 if (key.empty())
1450 return false;
1451 const auto visitor = [&](const auto value){
1452 return GetSettings()->Write(key, value.get()) && GetSettings()->Flush();
1453 };
1454 return Visit(visitor, value);
1455}
1456
1457/* Return value is a key for lookup in a config file */
1459 ConfigurationType type, const PluginID & ID)
1460{
1461 bool shared = (type == ConfigurationType::Shared);
1462
1463 // All the strings reported by PluginDescriptor and used in this function
1464 // persist in the plugin settings configuration file, so they should not
1465 // be changed across Audacity versions, or else compatibility of the
1466 // configuration files will break.
1467
1468 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end())
1469 return {};
1470 else {
1471 const PluginDescriptor & plug = iter->second;
1472
1473 wxString id = GetPluginTypeString(plug.GetPluginType()) +
1474 wxT("_") +
1475 plug.GetEffectFamily() + // is empty for non-Effects
1476 wxT("_") +
1477 plug.GetVendor() +
1478 wxT("_") +
1479 (shared ? wxString{} : plug.GetSymbol().Internal());
1480
1481 return SETROOT +
1482 ConvertID(id) +
1483 wxCONFIG_PATH_SEPARATOR +
1484 (shared ? wxT("shared") : wxT("private")) +
1485 wxCONFIG_PATH_SEPARATOR;
1486 }
1487}
1488
1489/* Return value is a key for lookup in a config file */
1491 const PluginID & ID, const RegistryPath & group)
1492{
1493 auto path = SettingsPath(type, ID);
1494
1495 wxFileName ff(group);
1496 if (!ff.GetName().empty())
1497 {
1498 path += ff.GetFullPath(wxPATH_UNIX) + wxCONFIG_PATH_SEPARATOR;
1499 }
1500
1501 return path;
1502}
1503
1504/* Return value is a key for lookup in a config file */
1506 const RegistryPath & group, const RegistryPath & key)
1507{
1508 auto path = Group(type, ID, group);
1509 if (path.empty())
1510 {
1511 return path;
1512 }
1513
1514 return path + key;
1515}
1516
1517// Sanitize the ID...not the best solution, but will suffice until this
1518// is converted to XML. We use base64 encoding to preserve case.
1520{
1521 if (ID.StartsWith(wxT("base64:")))
1522 {
1523 wxString id = ID.Mid(7);
1524 ArrayOf<char> buf{ id.length() / 4 * 3 };
1525 id = wxString::FromUTF8(buf.get(), Base64::Decode(id, buf.get()));
1526 return id;
1527 }
1528
1529 const wxCharBuffer & buf = ID.ToUTF8();
1530 return wxT("base64:") + Base64::Encode(buf, strlen(buf));
1531}
1532
1533// This is defined out-of-line here, to keep ComponentInterface free of other
1534// #include directives.
1536{
1537 return GetSymbol().Msgid();
1538}
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:76
EffectType
@ EffectTypeHidden
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeNone
@ EffectTypeTool
@ EffectTypeProcess
wxString PluginID
Definition: EffectManager.h:30
const TranslatableString desc
Definition: ExportPCM.cpp:55
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
auto Visit(Visitor &&vis, Variant &&var)
Mimic some of std::visit, for the case of one visitor only.
Definition: MemoryX.h:628
#define safenew
Definition: MemoryX.h:10
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:448
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:70
static const AttachedProjectObjects::RegisteredFactory manager
static TranslatableStrings names
Definition: TagsEditor.cpp:152
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)
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:47
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:97
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)
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
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)
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.
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:274
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:100