/[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 2124 - (hide annotations) (download)
Sat Sep 18 09:24:41 2010 UTC (13 years, 7 months ago) by schoenebeck
File size: 12695 byte(s)
* implemented support for internal LADSPA effects (work in progress)

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

  ViewVC Help
Powered by ViewVC