/[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 2183 - (hide annotations) (download)
Sat Jun 11 17:53:32 2011 UTC (12 years, 9 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 schoenebeck 2124 /*
2     Copyright (C) 2010 Christian Schoenebeck
3     */
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     #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 schoenebeck 2135 EffectControl::SetPossibilities;
72 schoenebeck 2124 };
73    
74     ////////////////////////////////////////////////////////////////////////////
75     // class 'LadspaEffect'
76    
77 schoenebeck 2135 LadspaEffect::LadspaEffect(EffectInfo* pInfo) throw (Exception) : Effect() {
78 schoenebeck 2124 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 schoenebeck 2135 // 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 schoenebeck 2124 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 schoenebeck 2135 // create LadspaEffectControl instances and determine its informations
126     // (value range, description, default value)
127 schoenebeck 2124 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 schoenebeck 2135
136 schoenebeck 2124 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 persson 2183 type = EffectControl::EFFECT_TYPE_INT;
182 schoenebeck 2124 } else if (LADSPA_IS_HINT_TOGGLED(pPortDescriptor)) {
183 persson 2183 type = EffectControl::EFFECT_TYPE_BOOL;
184 schoenebeck 2124 } else {
185 persson 2183 type = EffectControl::EFFECT_TYPE_FLOAT;
186 schoenebeck 2124 }
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 schoenebeck 2135 // 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 schoenebeck 2124 // 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 schoenebeck 2135
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 schoenebeck 2124 pDescriptor->connect_port(hEffect, iPort, &pEffectControl->Value());
294 schoenebeck 2135 } else if (LADSPA_IS_PORT_OUTPUT(pPortDescriptor)) {
295     LadspaEffectControl* pEffectControl =
296     (LadspaEffectControl*) vOutputControls[iOutControl++];
297     pDescriptor->connect_port(hEffect, iPort, &pEffectControl->Value());
298 schoenebeck 2124 }
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 schoenebeck 2137 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 schoenebeck 2124 #else
357 schoenebeck 2137 const String searchDirs[] = {
358     "/usr/lib/ladspa",
359     "/usr/local/lib/ladspa"
360     };
361 schoenebeck 2124 #endif
362 schoenebeck 2137 // 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 schoenebeck 2124 }
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