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 return true;
121}
122
124{
125#if USE_LADSPA
127#else
128 return {};
129#endif
130}
131
133{
134 static FileExtensions result{{
135
136#ifdef __WXMSW__
137
138 _T("dll")
139
140#else
141
142 _T("so")
143
144 #ifdef __WXMAC__
145 // Is it correct that these are candidate plug-in files too for macOs?
146 , _T("dylib")
147 #endif
148
149#endif
150
151 }};
152 return result;
153}
154
156{
157 // To do: better choice
158 return FileNames::PlugInDir();
159}
160
162{
163 // Autoregister effects that we "think" are ones that have been shipped with
164 // Audacity. A little simplistic, but it should suffice for now.
165 auto pathList = GetSearchPaths(pm);
166 FilePaths files;
167 TranslatableString ignoredErrMsg;
168
169 for (int i = 0; i < (int)WXSIZEOF(kShippedEffects); i++)
170 {
171 files.clear();
172 pm.FindFilesInPathList(kShippedEffects[i], pathList, files);
173 for (size_t j = 0, cnt = files.size(); j < cnt; j++)
174 {
175 if (!pm.IsPluginRegistered(files[j]))
176 {
177 // No checking for error ?
178 DiscoverPluginsAtPath(files[j], ignoredErrMsg,
180 }
181 }
182 }
183}
184
186{
187 auto pathList = GetSearchPaths(pm);
188 FilePaths files;
189
190#if defined(__WXMAC__)
191
192 // Recursively scan for all shared objects
193 pm.FindFilesInPathList(wxT("*.so"), pathList, files, true);
194
195#elif defined(__WXMSW__)
196
197 // Recursively scan for all DLLs
198 pm.FindFilesInPathList(wxT("*.dll"), pathList, files, true);
199
200#else
201
202 // Recursively scan for all shared objects
203 pm.FindFilesInPathList(wxT("*.so"), pathList, files, true);
204
205#endif
206
207 return { files.begin(), files.end() };
208}
209
211 const PluginPath & path, TranslatableString &errMsg,
212 const RegistrationCallback &callback)
213{
214 errMsg = {};
215 // Since we now have builtin VST support, ignore the VST bridge as it
216 // causes duplicate menu entries to appear.
217 wxFileName ff(path);
218 if (ff.GetName().CmpNoCase(wxT("vst-bridge")) == 0) {
219 errMsg = XO("Audacity no longer uses vst-bridge");
220 return 0;
221 }
222
223 // As a courtesy to some plug-ins that might be bridges to
224 // open other plug-ins, we set the current working
225 // directory to be the plug-in's directory.
226 wxString envpath;
227 bool hadpath = wxGetEnv(wxT("PATH"), &envpath);
228 wxSetEnv(wxT("PATH"), ff.GetPath() + wxFILE_SEP_PATH + envpath);
229 wxString saveOldCWD = ff.GetCwd();
230 ff.SetCwd();
231
232 int index = 0;
233 int nLoaded = 0;
234 LADSPA_Descriptor_Function mainFn = NULL;
235
236#if defined(__WXMSW__)
237 wxDynamicLibrary lib;
238 if (lib.Load(path, wxDL_NOW))
239#else
240 void *lib = dlopen((const char *)path.ToUTF8(), RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
241 if (lib)
242#endif
243 {
244
245#if defined(__WXMSW__)
246 wxLogNull logNo;
247
248 mainFn = (LADSPA_Descriptor_Function) lib.GetSymbol(wxT("ladspa_descriptor"));
249#else
250 mainFn = (LADSPA_Descriptor_Function) dlsym(lib, "ladspa_descriptor");
251#endif
252
253 if (mainFn) {
254 const LADSPA_Descriptor *data;
255
256 for (data = mainFn(index); data; data = mainFn(++index)) {
257 LadspaEffectBase effect(path, index);
258 if (effect.InitializePlugin()) {
259 ++nLoaded;
260 if (callback)
261 callback( this, &effect );
262 }
263 else
264 errMsg = XO("Could not load the library");
265 }
266 }
267 }
268 else
269 errMsg = XO("Could not load the library");
270
271#if defined(__WXMSW__)
272 if (lib.IsLoaded()) {
273 // PRL: I suspect Bug1257 -- Crash when enabling Amplio2 -- is the fault of a timing-
274 // dependent multi-threading bug in the Amplio2 library itself, in case the unload of the .dll
275 // comes too soon after the load. I saw the bug in Release builds but not Debug.
276 // A sleep of even 1 ms was enough to fix the problem for me, but let's be even more generous.
277 using namespace std::chrono;
278 std::this_thread::sleep_for(10ms);
279 lib.Unload();
280 }
281#else
282 if (lib) {
283 dlclose(lib);
284 }
285#endif
286
287 wxSetWorkingDirectory(saveOldCWD);
288 hadpath ? wxSetEnv(wxT("PATH"), envpath) : wxUnsetEnv(wxT("PATH"));
289
290 return nLoaded;
291}
292
293std::unique_ptr<ComponentInterface>
295{
296 // Acquires a resource for the application.
297 // For us, the path is two words.
298 // 1) The library's path
299 // 2) The LADSPA descriptor index
300 long index;
301 wxString realPath = path.BeforeFirst(wxT(';'));
302 path.AfterFirst(wxT(';')).ToLong(&index);
303 auto result = Factory::Call(realPath, (int)index);
304 result->InitializePlugin();
305 return result;
306}
307
309{
310 const auto realPath = path.BeforeFirst(wxT(';'));
311 return wxFileName::FileExists(realPath);
312}
313
315{
316 FilePaths pathList;
317 wxString pathVar;
318
319 // Check for the LADSPA_PATH environment variable
320 pathVar = wxString::FromUTF8(getenv("LADSPA_PATH"));
321 if (!pathVar.empty())
322 {
323 wxStringTokenizer tok(pathVar, wxPATH_SEP);
324 while (tok.HasMoreTokens())
325 {
326 pathList.push_back(tok.GetNextToken());
327 }
328 }
329
330#if defined(__WXMAC__)
331#define LADSPAPATH wxT("/Library/Audio/Plug-Ins/LADSPA")
332
333 // Look in ~/Library/Audio/Plug-Ins/LADSPA and /Library/Audio/Plug-Ins/LADSPA
334 pathList.push_back(wxGetHomeDir() + wxFILE_SEP_PATH + LADSPAPATH);
335 pathList.push_back(LADSPAPATH);
336
337#elif defined(__WXMSW__)
338
339 // No special paths...probably should look in %CommonProgramFiles%\LADSPA
340
341#else
342
343 pathList.push_back(wxGetHomeDir() + wxFILE_SEP_PATH + wxT(".ladspa"));
344#if defined(__LP64__)
345 pathList.push_back(wxT("/usr/local/lib64/ladspa"));
346 pathList.push_back(wxT("/usr/lib64/ladspa"));
347#endif
348 pathList.push_back(wxT("/usr/local/lib/ladspa"));
349 pathList.push_back(wxT("/usr/lib/ladspa"));
350 pathList.push_back(wxT(LIBDIR) wxT("/ladspa"));
351
352#endif
353
354 {
355 auto customPaths = pluginManager.ReadCustomPaths(*this);
356 std::copy(customPaths.begin(), customPaths.end(), std::back_inserter(pathList));
357 }
358
359 return pathList;
360}
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
FilePaths GetSearchPaths(PluginManagerInterface &pluginManager)
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.
bool SupportsCustomModulePaths() const override
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 PluginPaths ReadCustomPaths(const PluginProvider &provider)=0
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)
void copy(const T *src, T *dst, int32_t n)
Definition: VectorOps.h:40
_LADSPA_Descriptor is a structure that provides the API to a LADSPA (Linux Audio Plugin Architecture)...
Definition: ladspa.h:373