/[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 2296 - (hide annotations) (download)
Thu Dec 8 20:03:47 2011 UTC (12 years, 3 months ago) by iliev
File size: 15063 byte(s)
* fixed crash when trying to create an effect instance with controls
  which min and/or max values depend on the sample rate
* experimental support for per voice equalization (work in progress)
* sfz engine: implemented opcodes eq1_freq, eq2_freq, eq3_freq,
  eq1_freqccN, eq2_freqccN, eq3_freqccN, eq1_bw, eq2_bw, eq3_bw,
  eq1_bwccN, eq2_bwccN, eq3_bwccN, eq1_gain, eq2_gain, eq3_gain,
  eq1_gainccN, eq2_gainccN, eq3_gainccN

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 iliev 2296 // TODO: recalculate the min and max values that depends on sample rate
284    
285 schoenebeck 2135 // assign (already created and initialized) control input and control
286     // output variables (effect parameters)
287     int iInControl = 0;
288     int iOutControl = 0;
289     for (int iPort = 0; iPort < pDescriptor->PortCount; iPort++) {
290     LADSPA_PortDescriptor pPortDescriptor = pDescriptor->PortDescriptors[iPort];
291     if (LADSPA_IS_PORT_CONTROL(pPortDescriptor)) {
292     if (LADSPA_IS_PORT_INPUT(pPortDescriptor)) {
293     LadspaEffectControl* pEffectControl =
294     (LadspaEffectControl*) vInputControls[iInControl++];
295 schoenebeck 2124 pDescriptor->connect_port(hEffect, iPort, &pEffectControl->Value());
296 schoenebeck 2135 } else if (LADSPA_IS_PORT_OUTPUT(pPortDescriptor)) {
297     LadspaEffectControl* pEffectControl =
298     (LadspaEffectControl*) vOutputControls[iOutControl++];
299     pDescriptor->connect_port(hEffect, iPort, &pEffectControl->Value());
300 schoenebeck 2124 }
301     }
302     }
303    
304     // call LADSPA effect's activate function (if there is one)
305     if (pDescriptor->activate != NULL)
306     pDescriptor->activate(hEffect);
307    
308     dmsg(1, ("LADSPA effect '%s' activated.\n", pInfo->label.c_str()));
309     }
310    
311     /// Returns lowest allowed value for this LADSPA control port.
312     float LadspaEffect::getLowerB(int iPort) const {
313     float low =
314     (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_BOUNDED_BELOW)
315     ? pDescriptor->PortRangeHints[iPort].LowerBound : 0.0f;
316    
317     if (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_SAMPLE_RATE)
318 iliev 2296 low *= float(pDevice == NULL ? 44100 : pDevice->SampleRate());
319 schoenebeck 2124
320     return low;
321     }
322    
323     /// Returns biggest allowed value for this LADSPA control port.
324     float LadspaEffect::getUpperB(int iPort) const {
325     float up =
326     (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_BOUNDED_ABOVE)
327     ? pDescriptor->PortRangeHints[iPort].UpperBound : 1.0f;
328    
329     if (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_SAMPLE_RATE)
330 iliev 2296 up *= float(pDevice == NULL ? 44100 : pDevice->SampleRate());
331 schoenebeck 2124
332     return up;
333     }
334    
335     static void _foundLadspaDll(String filename, void* hDLL, void* pFunction, void* pCustom) {
336     LADSPA_Descriptor_Function fDescriptorFunction = (LADSPA_Descriptor_Function) pFunction;
337     std::vector<EffectInfo*>* pV = (std::vector<EffectInfo*>*) pCustom;
338     const LADSPA_Descriptor* psDescriptor;
339     for (long lIndex = 0; (psDescriptor = fDescriptorFunction(lIndex)) != NULL; lIndex++) {
340     //printf("\t%s (%lu/%s)\n", psDescriptor->Name, psDescriptor->UniqueID, psDescriptor->Label);
341     LadspaEffectInfo* pInfo = new LadspaEffectInfo;
342     pInfo->name = psDescriptor->Name;
343     pInfo->label = psDescriptor->Label;
344     pInfo->dll = filename;
345     pV->push_back(pInfo);
346     }
347     DynamicLibraryClose(hDLL);
348     }
349    
350     static String defaultLadspaDir() {
351     #if defined(WIN32)
352 schoenebeck 2137 const String sysDir =
353     getenv("PROGRAMFILES") ? getenv("PROGRAMFILES") : "C:\\Program Files";
354     const String searchDirs[] = {
355     sysDir + "\\ladspa", //FIXME: hmm... who knows what the common default LADSPA path on Windows is?
356     sysDir + "\\Audacity\\Plug-Ins"
357     };
358 schoenebeck 2124 #else
359 schoenebeck 2137 const String searchDirs[] = {
360     "/usr/lib/ladspa",
361     "/usr/local/lib/ladspa"
362     };
363 schoenebeck 2124 #endif
364 schoenebeck 2137 // check if one of the suggested directories exists
365     for (int i = 0; i < sizeof(searchDirs) / sizeof(String); i++) {
366     File f(searchDirs[i]);
367     if (f.Exist() && f.IsDirectory())
368     return searchDirs[i];
369     }
370     // No directory of the list exists? Whatever, return the 1st one of the list.
371     return searchDirs[0];
372 schoenebeck 2124 }
373    
374     std::vector<EffectInfo*> LadspaEffect::AvailableEffects() {
375     std::vector<EffectInfo*> v; // will be filled in callback function _foundLadspaDll()
376    
377     char* pcLadspaPath = getenv("LADSPA_PATH");
378     String ladspaDir = (pcLadspaPath) ? pcLadspaPath : defaultLadspaDir();
379    
380     try {
381     DynamicLibrariesSearch(
382     ladspaDir.c_str(), "ladspa_descriptor", _foundLadspaDll, &v
383     );
384     } catch (Exception e) {
385     std::cerr << "Could not scan LADSPA effects: " << e.Message()
386     << std::endl << std::flush;
387     } catch (...) {
388     std::cerr << "Could not scan LADSPA effects: unknown exception\n"
389     << std::flush;
390     }
391    
392     return v;
393     }
394    
395     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC