/[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 2335 - (show annotations) (download)
Sat Mar 17 06:19:01 2012 UTC (12 years ago) by persson
File size: 15290 byte(s)
* fixed compilation with gcc 4.7

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

  ViewVC Help
Powered by ViewVC