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