Audacity 3.2.0
VST3EffectsModule.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file VST3EffectsModule.cpp
6
7 @author Vitaly Sverchinsky
8
9 @brief Part of Audacity VST3 module
10
11**********************************************************************/
12
13
14#include "VST3EffectsModule.h"
15
16#include <stdexcept>
17
18#include <wx/stdpaths.h>
19#include <wx/dir.h>
20#include <wx/log.h>
21#include <wx/utils.h>
22
24#include "ModuleManager.h"
25
26#include "wxArrayStringEx.h"
27#include "PluginInterface.h"
28#include "PluginProvider.h"
29#include "PluginProvider.h"
30#include "VST3Utils.h"
31#include "VST3Wrapper.h"
32
33
35{
36 // Create our effects module and register
37 // Trust the module manager not to leak this
38 return std::make_unique<VST3EffectsModule>();
39}
40
42
43//Helper class used to find vst3 effects during folder traversal
44class VST3PluginTraverser final : public wxDirTraverser
45{
46 std::function<void(const wxString&)> mOnPluginFound;
47public:
48 VST3PluginTraverser(std::function<void(const wxString&)> onPluginFound)
49 : mOnPluginFound(std::move(onPluginFound))
50 {
51 }
52
53 wxDirTraverseResult OnFile(const wxString& filename) override
54 {
55 if(filename.Matches("*.vst3"))
56 mOnPluginFound(filename);
57 return wxDIR_CONTINUE;
58 }
59 wxDirTraverseResult OnDir(const wxString& dirname) override
60 {
61 if(dirname.Matches("*.vst3"))
62 {
63 mOnPluginFound(dirname);
64 return wxDIR_IGNORE;//do not look inside...
65 }
66 return wxDIR_CONTINUE;
67 }
68};
69
70std::shared_ptr<VST3::Hosting::Module> VST3EffectsModule::GetModule(const wxString& path)
71{
72 const auto it = mModules.find(path);
73 if(it != mModules.end())
74 {
75 if(auto lock = it->second.lock())
76 return lock;
77 }
78
79 std::string moduleCreateError;
80 //VST sdk provides platform-specific module loading routines as well,
81 //implementation is conditionally included (see CMakeLists.txt)
82 auto module = VST3::Hosting::Module::create(path.ToStdString(), moduleCreateError);
83 if(!module)
84 throw std::runtime_error(moduleCreateError.c_str());
85
86 module->getFactory().setHostContext(&AudacityVst3HostApplication::Get());
87
88 mModules[path] = module;
89 return module;
90}
91
93{
94 return {};
95}
96
98{
99 return XO("VST3 Effects");
100}
101
103{
104 return XO("The Audacity Team");
105}
106
108{
109 return AUDACITY_VERSION_STRING;
110}
111
113{
114 return XO("Adds the ability to use VST3 effects in Audacity.");
115}
116
118{
119 return true;
120}
121
123{
124}
125
127{
129}
130
132{
133 static const FileExtensions ext {
134 { _T("vst3") }
135 };
136 return ext;
137}
138
140{
141#ifdef VST3_DEFAULT_INSTALL_PATH
142 return FilePath { VST3_DEFAULT_INSTALL_PATH };
143#else
144 return {};
145#endif
146}
147
149{
150}
151
154{
155 //Note: The host recursively scans these folders at startup in this order (User/Global/Application).
156 //https://developer.steinberg.help/display/VST/Plug-in+Locations
157
158 FilePaths pathList;
159#ifdef __WXMSW__
160 // Windows specific VST3 search paths
161 {
162 wxString programFilesPath;
163 if(wxGetEnv("programfiles", &programFilesPath))
164 pathList.push_back(programFilesPath + "\\Common Files\\VST3");
165 }
166#elif __WXMAC__
167 pathList.push_back("~/Library/Audio/Plug-ins/VST3/");
168 pathList.push_back("/Library/Audio/Plug-ins/VST3/");
169 pathList.push_back("/Network/Library/Audio/Plug-ins/VST3/");
170#elif __WXGTK__
171 pathList.push_back(wxGetHomeDir() + "/.vst3/");
172 pathList.push_back("/usr/lib/vst3/");
173 pathList.push_back("/usr/local/lib/vst3/");
174#endif
175
176 // bundled/app specific
177 {
178 auto path = wxFileName(wxStandardPaths::Get().GetExecutablePath());
179#ifdef __WXGTK__
180 path.AppendDir("vst3");
181#else
182 path.AppendDir("VST3");
183#endif
184 pathList.push_back(path.GetPath());
185 }
186
187 PluginPaths result;
188 VST3PluginTraverser vst3PluginTraverser([&](const wxString& pluginPath){
189 result.push_back(pluginPath);
190 });
191
192 for(const auto& path : pathList)
193 {
194 wxDir dir(path);
195 if(dir.IsOpened())
196 dir.Traverse(vst3PluginTraverser, wxEmptyString, wxDIR_DEFAULT);
197 }
198 return result;
199}
200
202 const RegistrationCallback& callback)
203{
204 try
205 {
206 auto module = GetModule(path);
207
208 const auto moduleFactory = module->getFactory();
209 auto nEffects { 0u };
210 for(auto& classInfo : moduleFactory.classInfos())
211 {
212 if(classInfo.category() == kVstAudioEffectClass)
213 {
214 std::unique_ptr<VST3EffectBase> effect;
215 try
216 {
217 effect = Factory::Call(module, classInfo);
218 ++nEffects;
219 }
220 catch(std::exception& e)
221 {
222 wxLogError(
223 "Effect %s@%s cannot be loaded: %s",
224 classInfo.name().c_str(),
225 path.c_str(),
226 e.what()
227 );
228 }
229 catch(...)
230 {
231 wxLogError(
232 "Effect %s@%s cannot be loaded: unknown error",
233 classInfo.name().c_str(),
234 path.c_str()
235 );
236 }
237 if(effect && callback)
238 callback(this, effect.get());
239 }
240 }
241 if(nEffects == 0u)
242 throw std::runtime_error("no effects found");
243
244 return nEffects;
245 }
246 catch(std::exception& e)
247 {
248 errMsg = XO("VST3 module error: %s").Format(e.what());
249 }
250
251 return 0u;
252}
253
254std::unique_ptr<ComponentInterface>
256{
257 try
258 {
259 wxString modulePath;
260 std::string effectUIDString;
261
262 if(!VST3Utils::ParsePluginPath(pluginPath, &modulePath, &effectUIDString))
263 throw std::runtime_error("failed to parse plugin string");
264
265 auto module = GetModule(modulePath);
266 const auto pluginFactory = module->getFactory();
267 for(const auto& classInfo : pluginFactory.classInfos())
268 {
269 if(effectUIDString == classInfo.ID().toString()) {
270 auto result = Factory::Call(module, classInfo);
271 return result;
272 }
273 }
274 throw std::runtime_error("effect UID not found");
275 }
276 catch(std::exception& e)
277 {
278 wxLogError("VST3 Module was not loaded: %s", e.what());
279 }
280 return nullptr;
281}
282
284{
285public:
286
287 void Validate(ComponentInterface& component) override
288 {
289 if(auto vst3effect = dynamic_cast<VST3EffectBase*>(&component))
290 {
291 VST3Wrapper wrapper (
292 *vst3effect->mModule,
293 vst3effect->mEffectClassInfo
294 );
295 wrapper.InitializeComponents();
296 }
297 else
298 throw std::runtime_error("Not a VST3Effect");
299 }
300
301};
302
303std::unique_ptr<PluginProvider::Validator> VST3EffectsModule::MakeValidator() const
304{
305 return std::make_unique<VST3PluginValidator>();
306}
307
308
310{
311 wxString modulePath;
312 if(VST3Utils::ParsePluginPath(path, &modulePath, nullptr))
313 return wxFileName::FileExists(modulePath) || wxFileName::DirExists(modulePath);
314
315 return wxFileName::FileExists(path) || wxFileName::DirExists(path);
316}
XO("Cut/Copy/Paste")
std::vector< PluginPath > PluginPaths
Definition: Identifier.h:215
wxString PluginPath
type alias for identifying a Plugin supplied by a module, each module defining its own interpretation...
Definition: Identifier.h:214
Generalized interface for discovery of plug-ins for one protocol.
wxString FilePath
Definition: Project.h:21
DECLARE_PROVIDER_ENTRY(AudacityModule)
DECLARE_BUILTIN_PROVIDER(VST3Builtin)
ComponentInterface provides name / vendor / version functions to identify plugins....
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
std::function< const PluginID &(PluginProvider *, ComponentInterface *) > RegistrationCallback
Further expand a path reported by FindModulePaths.
Holds a msgid for the translation catalog; may also bind format arguments.
Objects of this class connect Audacity with VST3 effects.
static EffectFamilySymbol GetFamilySymbol()
void AutoRegisterPlugins(PluginManagerInterface &pluginManager) override
Called so that a provider of a static set of plug-ins can register them.
const FileExtensions & GetFileExtensions() override
File types associated with this protocol.
PluginPaths FindModulePaths(PluginManagerInterface &pluginManager) override
std::unique_ptr< ComponentInterface > LoadPlugin(const PluginPath &path) override
Load the plug-in at a path reported by DiscoverPluginsAtPath.
void Terminate() override
Called just prior to deletion to allow releasing any resources.
std::unique_ptr< Validator > MakeValidator() const override
TranslatableString GetDescription() const override
bool CheckPluginExist(const PluginPath &path) const override
Performs plugin/module existence check, still plugin may fail to load. Implementation should avoid lo...
FilePath InstallPath() override
Where plug-in files should be copied to install them.
EffectFamilySymbol GetOptionalFamilySymbol() override
A symbol identifying the family of plug-ins provided by this.
bool Initialize() override
Called immediately after creation. Let provider initialize.
VendorSymbol GetVendor() const override
std::unordered_map< wxString, std::weak_ptr< VST3::Hosting::Module > > mModules
wxString GetVersion() const override
PluginPath GetPath() const override
ComponentInterfaceSymbol GetSymbol() const override
std::shared_ptr< VST3::Hosting::Module > GetModule(const wxString &path)
unsigned DiscoverPluginsAtPath(const PluginPath &path, TranslatableString &errMsg, const RegistrationCallback &callback) override
wxDirTraverseResult OnFile(const wxString &filename) override
wxDirTraverseResult OnDir(const wxString &dirname) override
VST3PluginTraverser(std::function< void(const wxString &)> onPluginFound)
std::function< void(const wxString &)> mOnPluginFound
void Validate(ComponentInterface &component) override
static bool ParsePluginPath(const wxString &pluginPath, wxString *modulePath, std::string *effectUIDString)
Definition: VST3Utils.cpp:74
void InitializeComponents()
Should be called once before almost any other method call.
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:196
STL namespace.