/[svn]/linuxsampler/trunk/src/effects/LadspaEffect.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/effects/LadspaEffect.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2183 - (show annotations) (download)
Sat Jun 11 17:53:32 2011 UTC (7 years, 11 months ago) by persson
File size: 14930 byte(s)
* Mac OS X fixes: support the new dir for Core Audio SDK, fixed name
  collision of enum in EffectControl, fixed building outside source
  directory, fixed wrong name of destructor in
  AudioOutputDeviceCoreAudio.cpp
* made sure all source files for hostplugins are included when doing
  "make dist"
* removed empty directories left from the cvs to svn migration

1 /*
2 Copyright (C) 2010 Christian Schoenebeck
3 */
4
5 #include "LadspaEffect.h"
6 #include "../common/DynamicLibraries.h"
7 #include "../common/global_private.h"
8 #include "../common/File.h"
9 #include "../drivers/audio/AudioOutputDevice.h"
10 #include <math.h>
11
12 namespace LinuxSampler {
13
14 ////////////////////////////////////////////////////////////////////////////
15 // private helper functions
16
17 /// Returns total amount of ports for the given effect and port type.
18 static unsigned long _getPortCountByType(const LADSPA_Descriptor* psDescriptor, const LADSPA_PortDescriptor iType) {
19 unsigned long lCount = 0;
20 unsigned long lIndex;
21 for (lIndex = 0; lIndex < psDescriptor->PortCount; lIndex++)
22 if ((psDescriptor->PortDescriptors[lIndex] & iType) == iType)
23 lCount++;
24
25 return lCount;
26 }
27
28 ////////////////////////////////////////////////////////////////////////////
29 // class 'LadspaEffectInfo'
30
31 /**
32 * Identifier of exactly one LADSPA effect, used as unique key, e.g. for the
33 * respective LADSPA effect to be loaded.
34 */
35 class LadspaEffectInfo : public EffectInfo {
36 public:
37 String dll;
38 String label;
39 String name;
40
41 String EffectSystem() {
42 return "LADSPA";
43 }
44
45 String Name() {
46 return label;
47 }
48
49 String Module() {
50 return dll;
51 }
52
53 String Description() {
54 return name;
55 }
56 };
57
58 ////////////////////////////////////////////////////////////////////////////
59 // class 'LadspaEffectControl'
60
61 /**
62 * We just open access to protected members of EffectControl here.
63 */
64 class LadspaEffectControl : public EffectControl {
65 public:
66 EffectControl::SetDefaultValue;
67 EffectControl::SetMinValue;
68 EffectControl::SetMaxValue;
69 EffectControl::SetType;
70 EffectControl::SetDescription;
71 EffectControl::SetPossibilities;
72 };
73
74 ////////////////////////////////////////////////////////////////////////////
75 // class 'LadspaEffect'
76
77 LadspaEffect::LadspaEffect(EffectInfo* pInfo) throw (Exception) : Effect() {
78 this->pInfo = dynamic_cast<LadspaEffectInfo*>(pInfo);
79 if (!this->pInfo)
80 throw Exception("Effect key does not represent a LADSPA effect");
81
82 // DynamicLibraryOpen() and DynamicLibraryClose() maintain a reference
83 // count, so its OK to open and close the respective DLL for each effect,
84 // even though some effects might share the same DLL.
85 hDLL = DynamicLibraryOpen(this->pInfo->dll);
86 if (!hDLL)
87 throw Exception("Could not open DLL '" + this->pInfo->dll + "' for LADSPA effect");
88
89 LADSPA_Descriptor_Function pDescriptorFunction = (LADSPA_Descriptor_Function)
90 DynamicLibraryGetSymbol(hDLL, "ladspa_descriptor");
91
92 if (!pDescriptorFunction)
93 throw Exception("'" + this->pInfo->dll + "' is not a LADSPA plugin library");
94
95 // search for requested effect in that LADSPA DLL
96 for (long lPluginIndex = 0; true; lPluginIndex++) {
97 pDescriptor = pDescriptorFunction(lPluginIndex);
98 if (!pDescriptor)
99 throw Exception(
100 "Effect '" + this->pInfo->label +
101 "' could not be found in LADSPA DLL '" + this->pInfo->dll + "'"
102 );
103
104 if (pDescriptor->Label == this->pInfo->label)
105 break; // found
106 }
107
108 // those will be set later in InitEffect()
109 hEffect = NULL;
110 pDevice = NULL;
111
112 // create control input and control output variables (effect parameters)
113 // (they are going to be assigned to the actual LADSPA effect instance
114 // later in InitEffect() )
115 const int iInControls = _getPortCountByType(
116 pDescriptor,
117 LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT
118 );
119 const int iOutControls = _getPortCountByType(
120 pDescriptor,
121 LADSPA_PORT_CONTROL | LADSPA_PORT_OUTPUT
122 );
123 vInputControls.resize(iInControls);
124 vOutputControls.resize(iOutControls);
125 // create LadspaEffectControl instances and determine its informations
126 // (value range, description, default value)
127 int iInControl = 0;
128 int iOutControl = 0;
129 for (int iPort = 0; iPort < pDescriptor->PortCount; iPort++) {
130 LADSPA_PortDescriptor pPortDescriptor = pDescriptor->PortDescriptors[iPort];
131 if (LADSPA_IS_PORT_CONTROL(pPortDescriptor)) {
132 if (LADSPA_IS_PORT_INPUT(pPortDescriptor)) {
133 LadspaEffectControl* pEffectControl = new LadspaEffectControl();
134 vInputControls[iInControl++] = pEffectControl;
135
136 const float lower = getLowerB(iPort);
137 const float upper = getUpperB(iPort);
138
139 // determine default value
140 float fDefault = 0.5f * lower + 0.5f * upper; // middle value by default
141 if (LADSPA_IS_HINT_HAS_DEFAULT(pPortDescriptor)) {
142 if (LADSPA_IS_HINT_DEFAULT_MINIMUM(pPortDescriptor)) {
143 fDefault = lower;
144 } else if (LADSPA_IS_HINT_DEFAULT_LOW(pPortDescriptor)) {
145 if (LADSPA_IS_HINT_LOGARITHMIC(pPortDescriptor)) {
146 fDefault = exp(log(lower) * 0.75 + log(upper) * 0.25);
147 } else {
148 fDefault = lower * 0.75 + upper * 0.25;
149 }
150 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(pPortDescriptor)) {
151 if (LADSPA_IS_HINT_LOGARITHMIC(pPortDescriptor)) {
152 fDefault = exp(log(lower) * 0.5 + log(upper) * 0.5);
153 } else {
154 fDefault = 0.5f * lower + 0.5f * upper;
155 }
156 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(pPortDescriptor)) {
157 if (LADSPA_IS_HINT_LOGARITHMIC(pPortDescriptor)) {
158 fDefault = exp(log(lower) * 0.25 + log(upper) * 0.75);
159 } else {
160 fDefault = lower * 0.25 + upper * 0.75;
161 }
162 } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(pPortDescriptor)) {
163 fDefault = upper;
164 } else if (LADSPA_IS_HINT_DEFAULT_0(pPortDescriptor)) {
165 fDefault = 0.0f;
166 } else if (LADSPA_IS_HINT_DEFAULT_1(pPortDescriptor)) {
167 fDefault = 1.0f;
168 } else if (LADSPA_IS_HINT_DEFAULT_100(pPortDescriptor)) {
169 fDefault = 100.0f;
170 } else if (LADSPA_IS_HINT_DEFAULT_440(pPortDescriptor)) {
171 fDefault = 440.0f;
172 }
173
174 pEffectControl->SetDefaultValue(fDefault);
175 }
176 pEffectControl->SetValue(fDefault);
177
178 // determine value range type
179 EffectControl::Type_t type;
180 if (LADSPA_IS_HINT_INTEGER(pPortDescriptor)) {
181 type = EffectControl::EFFECT_TYPE_INT;
182 } else if (LADSPA_IS_HINT_TOGGLED(pPortDescriptor)) {
183 type = EffectControl::EFFECT_TYPE_BOOL;
184 } else {
185 type = EffectControl::EFFECT_TYPE_FLOAT;
186 }
187 pEffectControl->SetType(type);
188
189 // is there a minimum value?
190 if (LADSPA_IS_HINT_BOUNDED_BELOW(pPortDescriptor)) {
191 pEffectControl->SetMinValue(lower);
192 }
193
194 // is there a maximum value?
195 if (LADSPA_IS_HINT_BOUNDED_ABOVE(pPortDescriptor)) {
196 pEffectControl->SetMaxValue(upper);
197 }
198
199 // boolean type?
200 if (LADSPA_IS_HINT_TOGGLED(pPortDescriptor)) {
201 std::vector<float> vPossibilities;
202 vPossibilities.push_back(0.0f);
203 vPossibilities.push_back(1.0f);
204 pEffectControl->SetPossibilities(vPossibilities);
205 }
206
207 // retrieve human readable description about port
208 pEffectControl->SetDescription(pDescriptor->PortNames[iPort]);
209
210 } else if (LADSPA_IS_PORT_OUTPUT(pPortDescriptor)) {
211 LadspaEffectControl* pEffectControl = new LadspaEffectControl();
212 vOutputControls[iOutControl++] = pEffectControl;
213
214 //TODO: init output controls like input controls above
215 }
216 }
217 }
218 }
219
220 LadspaEffect::~LadspaEffect() {
221 if (!hEffect) return;
222 if (pDescriptor->deactivate)
223 pDescriptor->deactivate(hEffect);
224 pDescriptor->cleanup(hEffect);
225 DynamicLibraryClose(hDLL);
226 }
227
228 EffectInfo* LadspaEffect::GetEffectInfo() {
229 return pInfo;
230 }
231
232 void LadspaEffect::RenderAudio(uint Samples) {
233 // (re)assign audio input and audio output buffers
234 int iInputPort = 0;
235 int iOutputPort = 0;
236 for (int iPort = 0; iPort < pDescriptor->PortCount; iPort++) {
237 LADSPA_PortDescriptor pPortDescriptor = pDescriptor->PortDescriptors[iPort];
238 if (LADSPA_IS_PORT_AUDIO(pPortDescriptor)) {
239 if (LADSPA_IS_PORT_INPUT(pPortDescriptor)) {
240 pDescriptor->connect_port(hEffect, iPort, vInputChannels[iInputPort++]->Buffer());
241 } else if (LADSPA_IS_PORT_OUTPUT(pPortDescriptor)) {
242 pDescriptor->connect_port(hEffect, iPort, vOutputChannels[iOutputPort++]->Buffer());
243 }
244 }
245 }
246
247 // let the effect do its job
248 pDescriptor->run(hEffect, Samples);
249 }
250
251 void LadspaEffect::InitEffect(AudioOutputDevice* pDevice) throw (Exception) {
252 this->pDevice = pDevice;
253
254 const int iInChannels = _getPortCountByType(
255 pDescriptor,
256 LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT
257 );
258 const int iOutChannels = _getPortCountByType(
259 pDescriptor,
260 LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT
261 );
262 const int iInControls = vInputControls.size();
263 const int iOutControls = vOutputControls.size();
264
265 // now create the actual LADSPA effect instance ...
266 dmsg(1, ("Instantiating LADSPA effect '%s'.\n", pInfo->label.c_str()));
267 hEffect = pDescriptor->instantiate(pDescriptor, pDevice->SampleRate());
268 if (!hEffect)
269 throw Exception("Could not instantiate LADSPA effect '" + pInfo->label + "'");
270
271 // create audio input channels
272 vInputChannels.resize(iInChannels);
273 for (int i = 0; i < iInChannels; i++) {
274 vInputChannels[i] = new AudioChannel(i, pDevice->MaxSamplesPerCycle());
275 }
276
277 // create audio output channels
278 vOutputChannels.resize(iOutChannels);
279 for (int i = 0; i < iOutChannels; i++) {
280 vOutputChannels[i] = new AudioChannel(i, pDevice->MaxSamplesPerCycle());
281 }
282
283 // assign (already created and initialized) control input and control
284 // output variables (effect parameters)
285 int iInControl = 0;
286 int iOutControl = 0;
287 for (int iPort = 0; iPort < pDescriptor->PortCount; iPort++) {
288 LADSPA_PortDescriptor pPortDescriptor = pDescriptor->PortDescriptors[iPort];
289 if (LADSPA_IS_PORT_CONTROL(pPortDescriptor)) {
290 if (LADSPA_IS_PORT_INPUT(pPortDescriptor)) {
291 LadspaEffectControl* pEffectControl =
292 (LadspaEffectControl*) vInputControls[iInControl++];
293 pDescriptor->connect_port(hEffect, iPort, &pEffectControl->Value());
294 } else if (LADSPA_IS_PORT_OUTPUT(pPortDescriptor)) {
295 LadspaEffectControl* pEffectControl =
296 (LadspaEffectControl*) vOutputControls[iOutControl++];
297 pDescriptor->connect_port(hEffect, iPort, &pEffectControl->Value());
298 }
299 }
300 }
301
302 // call LADSPA effect's activate function (if there is one)
303 if (pDescriptor->activate != NULL)
304 pDescriptor->activate(hEffect);
305
306 dmsg(1, ("LADSPA effect '%s' activated.\n", pInfo->label.c_str()));
307 }
308
309 /// Returns lowest allowed value for this LADSPA control port.
310 float LadspaEffect::getLowerB(int iPort) const {
311 float low =
312 (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_BOUNDED_BELOW)
313 ? pDescriptor->PortRangeHints[iPort].LowerBound : 0.0f;
314
315 if (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_SAMPLE_RATE)
316 low *= float(pDevice->SampleRate());
317
318 return low;
319 }
320
321 /// Returns biggest allowed value for this LADSPA control port.
322 float LadspaEffect::getUpperB(int iPort) const {
323 float up =
324 (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_BOUNDED_ABOVE)
325 ? pDescriptor->PortRangeHints[iPort].UpperBound : 1.0f;
326
327 if (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_SAMPLE_RATE)
328 up *= float(pDevice->SampleRate());
329
330 return up;
331 }
332
333 static void _foundLadspaDll(String filename, void* hDLL, void* pFunction, void* pCustom) {
334 LADSPA_Descriptor_Function fDescriptorFunction = (LADSPA_Descriptor_Function) pFunction;
335 std::vector<EffectInfo*>* pV = (std::vector<EffectInfo*>*) pCustom;
336 const LADSPA_Descriptor* psDescriptor;
337 for (long lIndex = 0; (psDescriptor = fDescriptorFunction(lIndex)) != NULL; lIndex++) {
338 //printf("\t%s (%lu/%s)\n", psDescriptor->Name, psDescriptor->UniqueID, psDescriptor->Label);
339 LadspaEffectInfo* pInfo = new LadspaEffectInfo;
340 pInfo->name = psDescriptor->Name;
341 pInfo->label = psDescriptor->Label;
342 pInfo->dll = filename;
343 pV->push_back(pInfo);
344 }
345 DynamicLibraryClose(hDLL);
346 }
347
348 static String defaultLadspaDir() {
349 #if defined(WIN32)
350 const String sysDir =
351 getenv("PROGRAMFILES") ? getenv("PROGRAMFILES") : "C:\\Program Files";
352 const String searchDirs[] = {
353 sysDir + "\\ladspa", //FIXME: hmm... who knows what the common default LADSPA path on Windows is?
354 sysDir + "\\Audacity\\Plug-Ins"
355 };
356 #else
357 const String searchDirs[] = {
358 "/usr/lib/ladspa",
359 "/usr/local/lib/ladspa"
360 };
361 #endif
362 // check if one of the suggested directories exists
363 for (int i = 0; i < sizeof(searchDirs) / sizeof(String); i++) {
364 File f(searchDirs[i]);
365 if (f.Exist() && f.IsDirectory())
366 return searchDirs[i];
367 }
368 // No directory of the list exists? Whatever, return the 1st one of the list.
369 return searchDirs[0];
370 }
371
372 std::vector<EffectInfo*> LadspaEffect::AvailableEffects() {
373 std::vector<EffectInfo*> v; // will be filled in callback function _foundLadspaDll()
374
375 char* pcLadspaPath = getenv("LADSPA_PATH");
376 String ladspaDir = (pcLadspaPath) ? pcLadspaPath : defaultLadspaDir();
377
378 try {
379 DynamicLibrariesSearch(
380 ladspaDir.c_str(), "ladspa_descriptor", _foundLadspaDll, &v
381 );
382 } catch (Exception e) {
383 std::cerr << "Could not scan LADSPA effects: " << e.Message()
384 << std::endl << std::flush;
385 } catch (...) {
386 std::cerr << "Could not scan LADSPA effects: unknown exception\n"
387 << std::flush;
388 }
389
390 return v;
391 }
392
393 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC