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