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"
28#include "PluginInterface.h"
29#include "PluginProvider.h"
30#include "PluginProvider.h"
31#include "VST3Utils.h"
32#include "VST3Wrapper.h"
33
34
36{
37 // Create our effects module and register
38 // Trust the module manager not to leak this
39 return std::make_unique<VST3EffectsModule>();
40}
41
43
44//Helper class used to find vst3 effects during folder traversal
45class VST3PluginTraverser final : public wxDirTraverser
46{
47 std::function<void(const wxString&)> mOnPluginFound;
48public:
49 VST3PluginTraverser(std::function<void(const wxString&)> onPluginFound)
50 : mOnPluginFound(std::move(onPluginFound))
51 {
52 }
53
54 wxDirTraverseResult OnFile(const wxString& filename) override
55 {
56 if(filename.Matches("*.vst3"))
57 mOnPluginFound(filename);
58 return wxDIR_CONTINUE;
59 }
60 wxDirTraverseResult OnDir(const wxString& dirname) override
61 {
62 if(dirname.Matches("*.vst3"))
63 {
64 mOnPluginFound(dirname);
65 return wxDIR_IGNORE;//do not look inside...
66 }
67 return wxDIR_CONTINUE;
68 }
69};
70
71std::shared_ptr<VST3::Hosting::Module> VST3EffectsModule::GetModule(const wxString& path)
72{
73 const auto it = mModules.find(path);
74 if(it != mModules.end())
75 {
76 if(auto lock = it->second.lock())
77 return lock;
78 }
79
80 std::string moduleCreateError;
81 //VST sdk provides platform-specific module loading routines as well,
82 //implementation is conditionally included (see CMakeLists.txt)
83 auto module = VST3::Hosting::Module::create(path.ToStdString(), moduleCreateError);
84 if(!module)
85 throw std::runtime_error(moduleCreateError.c_str());
86
87 module->getFactory().setHostContext(&AudacityVst3HostApplication::Get());
88
89 mModules[path] = module;
90 return module;
91}
92
94{
95 return {};
96}
97
99{
100 return XO("VST3 Effects");
101}
102
104{
105 return XO("The Audacity Team");
106}
107
109{
110 return AUDACITY_VERSION_STRING;
111}
112
114{
115 return XO("Adds the ability to use VST3 effects in Audacity.");
116}
117
119{
120 return true;
121}
122
124{
125}
126
128{
130}
131
133{
134 static const FileExtensions ext {
135 { _T("vst3") }
136 };
137 return ext;
138}
139
141{
142#ifdef VST3_DEFAULT_INSTALL_PATH
143 return FilePath { VST3_DEFAULT_INSTALL_PATH };
144#else
145 return {};
146#endif
147}
148
150{
151}
152
154{
155 return true;
156}
157
160{
161 //Note: The host recursively scans these folders at startup in this order (User/Global/Application).
162 //https://developer.steinberg.help/display/VST/Plug-in+Locations
163
164 FilePaths pathList;
165#ifdef __WXMSW__
166 // Windows specific VST3 search paths
167 {
168 wxString programFilesPath;
169 if(wxGetEnv("programfiles", &programFilesPath))
170 pathList.push_back(programFilesPath + "\\Common Files\\VST3");
171 }
172#elif __WXMAC__
173 pathList.push_back("~/Library/Audio/Plug-ins/VST3/");
174 pathList.push_back("/Library/Audio/Plug-ins/VST3/");
175 pathList.push_back("/Network/Library/Audio/Plug-ins/VST3/");
176#elif __WXGTK__
177 pathList.push_back(wxGetHomeDir() + "/.vst3/");
178 pathList.push_back("/usr/lib/vst3/");
179 pathList.push_back("/usr/local/lib/vst3/");
180#endif
181
182 // bundled/app specific
183 {
184 auto path = wxFileName(PlatformCompatibility::GetExecutablePath());
185#ifdef __WXGTK__
186 path.AppendDir("vst3");
187#else
188 path.AppendDir("VST3");
189#endif
190 pathList.push_back(path.GetPath());
191 }
192 {
193 auto customPaths = pluginManager.ReadCustomPaths(*this);
194 std::copy(customPaths.begin(), customPaths.end(), std::back_inserter(pathList));
195 }
196
197 PluginPaths result;
198 VST3PluginTraverser vst3PluginTraverser([&](const wxString& pluginPath){
199 result.push_back(pluginPath);
200 });
201
202 for(const auto& path : pathList)
203 {
204 wxDir dir(path);
205 if(dir.IsOpened())
206 dir.Traverse(vst3PluginTraverser, wxEmptyString, wxDIR_DEFAULT);
207 }
208 return result;
209}
210
212 const RegistrationCallback& callback)
213{
214 try
215 {
216 auto module = GetModule(path);
217
218 const auto moduleFactory = module->getFactory();
219 auto nEffects { 0u };
220 for(auto& classInfo : moduleFactory.classInfos())
221 {
222 if(classInfo.category() == kVstAudioEffectClass)
223 {
224 std::unique_ptr<VST3EffectBase> effect;
225 try
226 {
227 effect = Factory::Call(module, classInfo);
228 ++nEffects;
229 }
230 catch(std::exception& e)
231 {
232 wxLogError(
233 "Effect %s@%s cannot be loaded: %s",
234 classInfo.name().c_str(),
235 path.c_str(),
236 e.what()
237 );
238 }
239 catch(...)
240 {
241 wxLogError(
242 "Effect %s@%s cannot be loaded: unknown error",
243 classInfo.name().c_str(),
244 path.c_str()
245 );
246 }
247 if(effect && callback)
248 callback(this, effect.get());
249 }
250 }
251 if(nEffects == 0u)
252 throw std::runtime_error("no effects found");
253
254 return nEffects;
255 }
256 catch(std::exception& e)
257 {
258 errMsg = XO("VST3 module error: %s").Format(e.what());
259 }
260
261 return 0u;
262}
263
264std::unique_ptr<ComponentInterface>
266{
267 try
268 {
269 wxString modulePath;
270 std::string effectUIDString;
271
272 if(!VST3Utils::ParsePluginPath(pluginPath, &modulePath, &effectUIDString))
273 throw std::runtime_error("failed to parse plugin string");
274
275 auto module = GetModule(modulePath);
276 const auto pluginFactory = module->getFactory();
277 for(const auto& classInfo : pluginFactory.classInfos())
278 {
279 if(effectUIDString == classInfo.ID().toString()) {
280 auto result = Factory::Call(module, classInfo);
281 return result;
282 }
283 }
284 throw std::runtime_error("effect UID not found");
285 }
286 catch(std::exception& e)
287 {
288 wxLogError("VST3 Module was not loaded: %s", e.what());
289 }
290 return nullptr;
291}
292
294{
295public:
296
297 void Validate(ComponentInterface& component) override
298 {
299 if(auto vst3effect = dynamic_cast<VST3EffectBase*>(&component))
300 {
301 VST3Wrapper wrapper (
302 *vst3effect->mModule,
303 vst3effect->mEffectClassInfo
304 );
305 wrapper.InitializeComponents();
306 }
307 else
308 throw std::runtime_error("Not a VST3Effect");
309 }
310
311};
312
313std::unique_ptr<PluginProvider::Validator> VST3EffectsModule::MakeValidator() const
314{
315 return std::make_unique<VST3PluginValidator>();
316}
317
318
320{
321 wxString modulePath;
322 if(VST3Utils::ParsePluginPath(path, &modulePath, nullptr))
323 return wxFileName::FileExists(modulePath) || wxFileName::DirExists(modulePath);
324
325 return wxFileName::FileExists(path) || wxFileName::DirExists(path);
326}
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.
virtual PluginPaths ReadCustomPaths(const PluginProvider &provider)=0
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)
bool SupportsCustomModulePaths() const override
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.
std::string FILES_API GetExecutablePath()
void copy(const T *src, T *dst, int32_t n)
Definition: VectorOps.h:40
STL namespace.