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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2313 - (hide annotations) (download)
Sun Feb 12 11:32:43 2012 UTC (12 years, 2 months ago) by persson
File size: 15254 byte(s)
* bugfix: LADSPA_PATH was not evaluated correctly when containing
  multiple paths (#165)

1 schoenebeck 2124 /*
2 persson 2313 Copyright (C) 2010 - 2012 Christian Schoenebeck
3 schoenebeck 2124 */
4    
5     #include "LadspaEffect.h"
6     #include "../common/DynamicLibraries.h"
7     #include "../common/global_private.h"
8 schoenebeck 2137 #include "../common/File.h"
9 schoenebeck 2124 #include "../drivers/audio/AudioOutputDevice.h"
10 persson 2313 #include <cmath>
11     #include <sstream>
12 schoenebeck 2124
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     EffectControl::SetDefaultValue;
68     EffectControl::SetMinValue;
69     EffectControl::SetMaxValue;
70     EffectControl::SetType;
71     EffectControl::SetDescription;
72 schoenebeck 2135 EffectControl::SetPossibilities;
73 schoenebeck 2124 };
74    
75     ////////////////////////////////////////////////////////////////////////////
76     // class 'LadspaEffect'
77    
78 schoenebeck 2135 LadspaEffect::LadspaEffect(EffectInfo* pInfo) throw (Exception) : Effect() {
79 schoenebeck 2124 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 schoenebeck 2135 // 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 schoenebeck 2124 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 schoenebeck 2135 // create LadspaEffectControl instances and determine its informations
127     // (value range, description, default value)
128 schoenebeck 2124 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 schoenebeck 2135
137 schoenebeck 2124 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 persson 2183 type = EffectControl::EFFECT_TYPE_INT;
183 schoenebeck 2124 } else if (LADSPA_IS_HINT_TOGGLED(pPortDescriptor)) {
184 persson 2183 type = EffectControl::EFFECT_TYPE_BOOL;
185 schoenebeck 2124 } else {
186 persson 2183 type = EffectControl::EFFECT_TYPE_FLOAT;
187 schoenebeck 2124 }
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 schoenebeck 2135 // 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 schoenebeck 2124 // 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 schoenebeck 2135
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 iliev 2296 // TODO: recalculate the min and max values that depends on sample rate
285    
286 schoenebeck 2135 // 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 schoenebeck 2124 pDescriptor->connect_port(hEffect, iPort, &pEffectControl->Value());
297 schoenebeck 2135 } else if (LADSPA_IS_PORT_OUTPUT(pPortDescriptor)) {
298     LadspaEffectControl* pEffectControl =
299     (LadspaEffectControl*) vOutputControls[iOutControl++];
300     pDescriptor->connect_port(hEffect, iPort, &pEffectControl->Value());
301 schoenebeck 2124 }
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 iliev 2296 low *= float(pDevice == NULL ? 44100 : pDevice->SampleRate());
320 schoenebeck 2124
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 iliev 2296 up *= float(pDevice == NULL ? 44100 : pDevice->SampleRate());
332 schoenebeck 2124
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 schoenebeck 2137 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 schoenebeck 2124 #else
360 schoenebeck 2137 const String searchDirs[] = {
361     "/usr/lib/ladspa",
362     "/usr/local/lib/ladspa"
363     };
364 schoenebeck 2124 #endif
365 schoenebeck 2137 // 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 schoenebeck 2124 }
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 persson 2313 String ladspaDir = pcLadspaPath ? pcLadspaPath : defaultLadspaDir();
380 schoenebeck 2124
381     try {
382 persson 2313 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 schoenebeck 2124 } 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