Audacity 3.2.0
LadspaEffectsModule.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 LadspaEffectsModule.cpp
6
7 Dominic Mazzoni
8
9 Paul Licameli split from LadspaEffect.cpp
10
11 This class implements a LADSPA Plug-in effect.
12
13*//*******************************************************************/
14#include "LadspaEffectsModule.h"
15
16#include "ConfigInterface.h"
17
18#if !defined(__WXMSW__)
19#include <dlfcn.h>
20
21#ifndef RTLD_DEEPBIND
22#define RTLD_DEEPBIND 0
23#endif
24#endif
25
26#include <chrono>
27#include <thread>
28#include <wx/log.h>
29#include <wx/tokenzr.h>
30#include <wx/utils.h>
31#include "FileNames.h"
32#include "ModuleManager.h"
33
34// ============================================================================
35// List of effects that ship with Audacity. These will be autoregistered.
36// ============================================================================
37const static wxChar *kShippedEffects[] =
38{
39 wxT("sc4_1882.dll"),
40};
41
42// ============================================================================
43// Module registration entry point
44//
45// This is the symbol that Audacity looks for when the module is built as a
46// dynamic library.
47//
48// When the module is builtin to Audacity, we use the same function, but it is
49// declared static so as not to clash with other builtin modules.
50// ============================================================================
52{
53 // Create and register the importer
54 // Trust the module manager not to leak this
55 return std::make_unique<LadspaEffectsModule>();
56}
57
58// ============================================================================
59// Register this as a builtin module
60// ============================================================================
62
64//
65// LadspaEffectsModule
66//
68
70{
71}
72
74{
75}
76
78{
79 return {};
80}
81
83{
84 /* i18n-hint: abbreviates "Linux Audio Developer's Simple Plugin API"
85 (Application programming interface)
86 */
87 return XO("LADSPA Effects");
88}
89
91{
92 return XO("The Audacity Team");
93}
94
96{
97 // This "may" be different if this were to be maintained as a separate DLL
99}
100
102{
103 return XO("Provides LADSPA Effects");
104}
105
107{
108 // Nothing to do here
109 return true;
110}
111
113{
114 // Nothing to do here
115 return;
116}
117
119{
120#if USE_LADSPA
122#else
123 return {};
124#endif
125}
126
128{
129 static FileExtensions result{{
130
131#ifdef __WXMSW__
132
133 _T("dll")
134
135#else
136
137 _T("so")
138
139 #ifdef __WXMAC__
140 // Is it correct that these are candidate plug-in files too for macOs?
141 , _T("dylib")
142 #endif
143
144#endif
145
146 }};
147 return result;
148}
149
151{
152 // To do: better choice
153 return FileNames::PlugInDir();
154}
155
157{
158 // Autoregister effects that we "think" are ones that have been shipped with
159 // Audacity. A little simplistic, but it should suffice for now.
160 auto pathList = GetSearchPaths();
161 FilePaths files;
162 TranslatableString ignoredErrMsg;
163
164 for (int i = 0; i < (int)WXSIZEOF(kShippedEffects); i++)
165 {
166 files.clear();
167 pm.FindFilesInPathList(kShippedEffects[i], pathList, files);
168 for (size_t j = 0, cnt = files.size(); j < cnt; j++)
169 {
170 if (!pm.IsPluginRegistered(files[j]))
171 {
172 // No checking for error ?
173 DiscoverPluginsAtPath(files[j], ignoredErrMsg,
175 }
176 }
177 }
178}
179
181{
182 auto pathList = GetSearchPaths();
183 FilePaths files;
184
185#if defined(__WXMAC__)
186
187 // Recursively scan for all shared objects
188 pm.FindFilesInPathList(wxT("*.so"), pathList, files, true);
189
190#elif defined(__WXMSW__)
191
192 // Recursively scan for all DLLs
193 pm.FindFilesInPathList(wxT("*.dll"), pathList, files, true);
194
195#else
196
197 // Recursively scan for all shared objects
198 pm.FindFilesInPathList(wxT("*.so"), pathList, files, true);
199
200#endif
201
202 return { files.begin(), files.end() };
203}
204
206 const PluginPath & path, TranslatableString &errMsg,
207 const RegistrationCallback &callback)
208{
209 errMsg = {};
210 // Since we now have builtin VST support, ignore the VST bridge as it
211 // causes duplicate menu entries to appear.
212 wxFileName ff(path);
213 if (ff.GetName().CmpNoCase(wxT("vst-bridge")) == 0) {
214 errMsg = XO("Audacity no longer uses vst-bridge");
215 return 0;
216 }
217
218 // As a courtesy to some plug-ins that might be bridges to
219 // open other plug-ins, we set the current working
220 // directory to be the plug-in's directory.
221 wxString envpath;
222 bool hadpath = wxGetEnv(wxT("PATH"), &envpath);
223 wxSetEnv(wxT("PATH"), ff.GetPath() + wxFILE_SEP_PATH + envpath);
224 wxString saveOldCWD = ff.GetCwd();
225 ff.SetCwd();
226
227 int index = 0;
228 int nLoaded = 0;
229 LADSPA_Descriptor_Function mainFn = NULL;
230
231#if defined(__WXMSW__)
232 wxDynamicLibrary lib;
233 if (lib.Load(path, wxDL_NOW))
234#else
235 void *lib = dlopen((const char *)path.ToUTF8(), RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
236 if (lib)
237#endif
238 {
239
240#if defined(__WXMSW__)
241 wxLogNull logNo;
242
243 mainFn = (LADSPA_Descriptor_Function) lib.GetSymbol(wxT("ladspa_descriptor"));
244#else
245 mainFn = (LADSPA_Descriptor_Function) dlsym(lib, "ladspa_descriptor");
246#endif
247
248 if (mainFn) {
249 const LADSPA_Descriptor *data;
250
251 for (data = mainFn(index); data; data = mainFn(++index)) {
252 LadspaEffectBase effect(path, index);
253 if (effect.InitializePlugin()) {
254 ++nLoaded;
255 if (callback)
256 callback( this, &effect );
257 }
258 else
259 errMsg = XO("Could not load the library");
260 }
261 }
262 }
263 else
264 errMsg = XO("Could not load the library");
265
266#if defined(__WXMSW__)
267 if (lib.IsLoaded()) {
268 // PRL: I suspect Bug1257 -- Crash when enabling Amplio2 -- is the fault of a timing-
269 // dependent multi-threading bug in the Amplio2 library itself, in case the unload of the .dll
270 // comes too soon after the load. I saw the bug in Release builds but not Debug.
271 // A sleep of even 1 ms was enough to fix the problem for me, but let's be even more generous.
272 using namespace std::chrono;
273 std::this_thread::sleep_for(10ms);
274 lib.Unload();
275 }
276#else
277 if (lib) {
278 dlclose(lib);
279 }
280#endif
281
282 wxSetWorkingDirectory(saveOldCWD);
283 hadpath ? wxSetEnv(wxT("PATH"), envpath) : wxUnsetEnv(wxT("PATH"));
284
285 return nLoaded;
286}
287
288std::unique_ptr<ComponentInterface>
290{
291 // Acquires a resource for the application.
292 // For us, the path is two words.
293 // 1) The library's path
294 // 2) The LADSPA descriptor index
295 long index;
296 wxString realPath = path.BeforeFirst(wxT(';'));
297 path.AfterFirst(wxT(';')).ToLong(&index);
298 auto result = Factory::Call(realPath, (int)index);
299 result->InitializePlugin();
300 return result;
301}
302
304{
305 const auto realPath = path.BeforeFirst(wxT(';'));
306 return wxFileName::FileExists(realPath);
307}
308
310{
311 FilePaths pathList;
312 wxString pathVar;
313
314 // Check for the LADSPA_PATH environment variable
315 pathVar = wxString::FromUTF8(getenv("LADSPA_PATH"));
316 if (!pathVar.empty())
317 {
318 wxStringTokenizer tok(pathVar, wxPATH_SEP);
319 while (tok.HasMoreTokens())
320 {
321 pathList.push_back(tok.GetNextToken());
322 }
323 }
324
325#if defined(__WXMAC__)
326#define LADSPAPATH wxT("/Library/Audio/Plug-Ins/LADSPA")
327
328 // Look in ~/Library/Audio/Plug-Ins/LADSPA and /Library/Audio/Plug-Ins/LADSPA
329 pathList.push_back(wxGetHomeDir() + wxFILE_SEP_PATH + LADSPAPATH);
330 pathList.push_back(LADSPAPATH);
331
332#elif defined(__WXMSW__)
333
334 // No special paths...probably should look in %CommonProgramFiles%\LADSPA
335
336#else
337
338 pathList.push_back(wxGetHomeDir() + wxFILE_SEP_PATH + wxT(".ladspa"));
339#if defined(__LP64__)
340 pathList.push_back(wxT("/usr/local/lib64/ladspa"));
341 pathList.push_back(wxT("/usr/lib64/ladspa"));
342#endif
343 pathList.push_back(wxT("/usr/local/lib/ladspa"));
344 pathList.push_back(wxT("/usr/lib/ladspa"));
345 pathList.push_back(wxT(LIBDIR) wxT("/ladspa"));
346
347#endif
348
349 return pathList;
350}
wxT("CloseDown"))
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
#define LADSPAEFFECTS_VERSION
#define LADSPAEFFECTS_FAMILY
DECLARE_PROVIDER_ENTRY(AudacityModule)
static const wxChar * kShippedEffects[]
#define LADSPAPATH
DECLARE_BUILTIN_PROVIDER(LadspaBuiltin)
wxString FilePath
Definition: Project.h:21
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.
An Effect that calls up a LADSPA plug in, i.e. many possible effects from this one class.
PluginPaths FindModulePaths(PluginManagerInterface &pm) override
ComponentInterfaceSymbol GetSymbol() const override
std::unique_ptr< ComponentInterface > LoadPlugin(const PluginPath &path) override
Load the plug-in at a path reported by DiscoverPluginsAtPath.
FilePath InstallPath() override
Where plug-in files should be copied to install them.
TranslatableString GetDescription() const override
EffectFamilySymbol GetOptionalFamilySymbol() override
A symbol identifying the family of plug-ins provided by this.
unsigned DiscoverPluginsAtPath(const PluginPath &path, TranslatableString &errMsg, const RegistrationCallback &callback) override
const FileExtensions & GetFileExtensions() override
File types associated with this protocol.
VendorSymbol GetVendor() const override
void Terminate() override
Called just prior to deletion to allow releasing any resources.
wxString GetVersion() const override
bool Initialize() override
Called immediately after creation. Let provider initialize.
PluginPath GetPath() const override
bool CheckPluginExist(const PluginPath &path) const override
Performs plugin/module existence check, still plugin may fail to load. Implementation should avoid lo...
void AutoRegisterPlugins(PluginManagerInterface &pm) override
Called so that a provider of a static set of plug-ins can register them.
virtual void FindFilesInPathList(const wxString &pattern, const FilePaths &pathList, FilePaths &files, bool directories=false)=0
virtual bool IsPluginRegistered(const PluginPath &path, const TranslatableString *pName=nullptr)=0
Was the plugin registry already populated for a path (maybe from loading the config file)?
static const PluginID & DefaultRegistrationCallback(PluginProvider *provider, ComponentInterface *ident)
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.
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
const LADSPA_Descriptor *(* LADSPA_Descriptor_Function)(unsigned long Index)
Definition: ladspa.h:593
FILES_API FilePath PlugInDir()
The user plug-in directory (not a system one)
_LADSPA_Descriptor is a structure that provides the API to a LADSPA (Linux Audio Plugin Architecture)...
Definition: ladspa.h:373