/[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 2135 - (hide annotations) (download)
Thu Sep 30 20:00:43 2010 UTC (13 years, 6 months ago) by schoenebeck
File size: 14336 byte(s)
* added and implemented a set of 19 new LSCP commands for controlling
  internal effects:
  - added LSCP command "GET AVAILABLE_EFFECTS"
  - added LSCP command "LIST AVAILABLE_EFFECTS"
  - added LSCP command "GET EFFECT INFO <effect-index>"
  - added LSCP command "CREATE EFFECT_INSTANCE <effect-index>"
  - added LSCP command
    "CREATE EFFECT_INSTANCE <effect-system> <module> <effect-name>"
  - added LSCP command "DESTROY EFFECT_INSTANCE <effect-instance>"
  - added LSCP command "GET EFFECT_INSTANCES"
  - added LSCP command "LIST EFFECT_INSTANCES"
  - added LSCP command "GET EFFECT_INSTANCE INFO <effect-instance>"
  - added LSCP command "GET EFFECT_INSTANCE_INPUT_CONTROL INFO
    <effect-instance> <input-control>"
  - added LSCP command "SET EFFECT_INSTANCE_INPUT_CONTROL <effect-instance>
    <input-control> <value>"
  - added LSCP command "GET MASTER_EFFECT_CHAINS <audio-device>"
  - added LSCP command "LIST MASTER_EFFECT_CHAINS <audio-device>"
  - added LSCP command "ADD MASTER_EFFECT_CHAIN <audio-device>"
  - added LSCP command
    "REMOVE MASTER_EFFECT_CHAIN <audio-device> <effect-chain>"
  - added LSCP command
    "GET MASTER_EFFECT_CHAIN INFO <audio-device> <effect-chain>"
  - added LSCP command "APPEND MASTER_EFFECT_CHAIN EFFECT <audio-device>
    <effect-chain> <effect-instance>"
  - added LSCP command "INSERT MASTER_EFFECT_CHAIN EFFECT <audio-device>
    <effect-chain> <effect-instance> <effect-chain-pos>"
  - added LSCP command "REMOVE MASTER_EFFECT_CHAIN EFFECT <audio-device>
    <effect-chain> <effect-instance>"
* bumped version to 1.0.0.cvs7

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 schoenebeck 2135 EffectControl::SetPossibilities;
71 schoenebeck 2124 };
72    
73     ////////////////////////////////////////////////////////////////////////////
74     // class 'LadspaEffect'
75    
76 schoenebeck 2135 LadspaEffect::LadspaEffect(EffectInfo* pInfo) throw (Exception) : Effect() {
77 schoenebeck 2124 this->pInfo = dynamic_cast<LadspaEffectInfo*>(pInfo);
78     if (!this->pInfo)
79     throw Exception("Effect key does not represent a LADSPA effect");
80    
81     // DynamicLibraryOpen() and DynamicLibraryClose() maintain a reference
82     // count, so its OK to open and close the respective DLL for each effect,
83     // even though some effects might share the same DLL.
84     hDLL = DynamicLibraryOpen(this->pInfo->dll);
85     if (!hDLL)
86     throw Exception("Could not open DLL '" + this->pInfo->dll + "' for LADSPA effect");
87    
88     LADSPA_Descriptor_Function pDescriptorFunction = (LADSPA_Descriptor_Function)
89     DynamicLibraryGetSymbol(hDLL, "ladspa_descriptor");
90    
91     if (!pDescriptorFunction)
92     throw Exception("'" + this->pInfo->dll + "' is not a LADSPA plugin library");
93    
94     // search for requested effect in that LADSPA DLL
95     for (long lPluginIndex = 0; true; lPluginIndex++) {
96     pDescriptor = pDescriptorFunction(lPluginIndex);
97     if (!pDescriptor)
98     throw Exception(
99     "Effect '" + this->pInfo->label +
100     "' could not be found in LADSPA DLL '" + this->pInfo->dll + "'"
101     );
102    
103     if (pDescriptor->Label == this->pInfo->label)
104     break; // found
105     }
106    
107     // those will be set later in InitEffect()
108     hEffect = NULL;
109     pDevice = NULL;
110    
111 schoenebeck 2135 // create control input and control output variables (effect parameters)
112     // (they are going to be assigned to the actual LADSPA effect instance
113     // later in InitEffect() )
114 schoenebeck 2124 const int iInControls = _getPortCountByType(
115     pDescriptor,
116     LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT
117     );
118     const int iOutControls = _getPortCountByType(
119     pDescriptor,
120     LADSPA_PORT_CONTROL | LADSPA_PORT_OUTPUT
121     );
122     vInputControls.resize(iInControls);
123     vOutputControls.resize(iOutControls);
124 schoenebeck 2135 // create LadspaEffectControl instances and determine its informations
125     // (value range, description, default value)
126 schoenebeck 2124 int iInControl = 0;
127     int iOutControl = 0;
128     for (int iPort = 0; iPort < pDescriptor->PortCount; iPort++) {
129     LADSPA_PortDescriptor pPortDescriptor = pDescriptor->PortDescriptors[iPort];
130     if (LADSPA_IS_PORT_CONTROL(pPortDescriptor)) {
131     if (LADSPA_IS_PORT_INPUT(pPortDescriptor)) {
132     LadspaEffectControl* pEffectControl = new LadspaEffectControl();
133     vInputControls[iInControl++] = pEffectControl;
134 schoenebeck 2135
135 schoenebeck 2124 const float lower = getLowerB(iPort);
136     const float upper = getUpperB(iPort);
137    
138     // determine default value
139     float fDefault = 0.5f * lower + 0.5f * upper; // middle value by default
140     if (LADSPA_IS_HINT_HAS_DEFAULT(pPortDescriptor)) {
141     if (LADSPA_IS_HINT_DEFAULT_MINIMUM(pPortDescriptor)) {
142     fDefault = lower;
143     } else if (LADSPA_IS_HINT_DEFAULT_LOW(pPortDescriptor)) {
144     if (LADSPA_IS_HINT_LOGARITHMIC(pPortDescriptor)) {
145     fDefault = exp(log(lower) * 0.75 + log(upper) * 0.25);
146     } else {
147     fDefault = lower * 0.75 + upper * 0.25;
148     }
149     } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(pPortDescriptor)) {
150     if (LADSPA_IS_HINT_LOGARITHMIC(pPortDescriptor)) {
151     fDefault = exp(log(lower) * 0.5 + log(upper) * 0.5);
152     } else {
153     fDefault = 0.5f * lower + 0.5f * upper;
154     }
155     } else if (LADSPA_IS_HINT_DEFAULT_HIGH(pPortDescriptor)) {
156     if (LADSPA_IS_HINT_LOGARITHMIC(pPortDescriptor)) {
157     fDefault = exp(log(lower) * 0.25 + log(upper) * 0.75);
158     } else {
159     fDefault = lower * 0.25 + upper * 0.75;
160     }
161     } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(pPortDescriptor)) {
162     fDefault = upper;
163     } else if (LADSPA_IS_HINT_DEFAULT_0(pPortDescriptor)) {
164     fDefault = 0.0f;
165     } else if (LADSPA_IS_HINT_DEFAULT_1(pPortDescriptor)) {
166     fDefault = 1.0f;
167     } else if (LADSPA_IS_HINT_DEFAULT_100(pPortDescriptor)) {
168     fDefault = 100.0f;
169     } else if (LADSPA_IS_HINT_DEFAULT_440(pPortDescriptor)) {
170     fDefault = 440.0f;
171     }
172    
173     pEffectControl->SetDefaultValue(fDefault);
174     }
175     pEffectControl->SetValue(fDefault);
176    
177     // determine value range type
178     EffectControl::Type_t type;
179     if (LADSPA_IS_HINT_INTEGER(pPortDescriptor)) {
180     type = EffectControl::TYPE_INT;
181     } else if (LADSPA_IS_HINT_TOGGLED(pPortDescriptor)) {
182     type = EffectControl::TYPE_BOOL;
183     } else {
184     type = EffectControl::TYPE_FLOAT;
185     }
186     pEffectControl->SetType(type);
187    
188     // is there a minimum value?
189     if (LADSPA_IS_HINT_BOUNDED_BELOW(pPortDescriptor)) {
190     pEffectControl->SetMinValue(lower);
191     }
192    
193     // is there a maximum value?
194     if (LADSPA_IS_HINT_BOUNDED_ABOVE(pPortDescriptor)) {
195     pEffectControl->SetMaxValue(upper);
196     }
197    
198 schoenebeck 2135 // boolean type?
199     if (LADSPA_IS_HINT_TOGGLED(pPortDescriptor)) {
200     std::vector<float> vPossibilities;
201     vPossibilities.push_back(0.0f);
202     vPossibilities.push_back(1.0f);
203     pEffectControl->SetPossibilities(vPossibilities);
204     }
205    
206 schoenebeck 2124 // retrieve human readable description about port
207     pEffectControl->SetDescription(pDescriptor->PortNames[iPort]);
208    
209     } else if (LADSPA_IS_PORT_OUTPUT(pPortDescriptor)) {
210     LadspaEffectControl* pEffectControl = new LadspaEffectControl();
211     vOutputControls[iOutControl++] = pEffectControl;
212 schoenebeck 2135
213     //TODO: init output controls like input controls above
214     }
215     }
216     }
217     }
218    
219     LadspaEffect::~LadspaEffect() {
220     if (!hEffect) return;
221     if (pDescriptor->deactivate)
222     pDescriptor->deactivate(hEffect);
223     pDescriptor->cleanup(hEffect);
224     DynamicLibraryClose(hDLL);
225     }
226    
227     EffectInfo* LadspaEffect::GetEffectInfo() {
228     return pInfo;
229     }
230    
231     void LadspaEffect::RenderAudio(uint Samples) {
232     // (re)assign audio input and audio output buffers
233     int iInputPort = 0;
234     int iOutputPort = 0;
235     for (int iPort = 0; iPort < pDescriptor->PortCount; iPort++) {
236     LADSPA_PortDescriptor pPortDescriptor = pDescriptor->PortDescriptors[iPort];
237     if (LADSPA_IS_PORT_AUDIO(pPortDescriptor)) {
238     if (LADSPA_IS_PORT_INPUT(pPortDescriptor)) {
239     pDescriptor->connect_port(hEffect, iPort, vInputChannels[iInputPort++]->Buffer());
240     } else if (LADSPA_IS_PORT_OUTPUT(pPortDescriptor)) {
241     pDescriptor->connect_port(hEffect, iPort, vOutputChannels[iOutputPort++]->Buffer());
242     }
243     }
244     }
245    
246     // let the effect do its job
247     pDescriptor->run(hEffect, Samples);
248     }
249    
250     void LadspaEffect::InitEffect(AudioOutputDevice* pDevice) throw (Exception) {
251     this->pDevice = pDevice;
252    
253     const int iInChannels = _getPortCountByType(
254     pDescriptor,
255     LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT
256     );
257     const int iOutChannels = _getPortCountByType(
258     pDescriptor,
259     LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT
260     );
261     const int iInControls = vInputControls.size();
262     const int iOutControls = vOutputControls.size();
263    
264     // now create the actual LADSPA effect instance ...
265     dmsg(1, ("Instantiating LADSPA effect '%s'.\n", pInfo->label.c_str()));
266     hEffect = pDescriptor->instantiate(pDescriptor, pDevice->SampleRate());
267     if (!hEffect)
268     throw Exception("Could not instantiate LADSPA effect '" + pInfo->label + "'");
269    
270     // create audio input channels
271     vInputChannels.resize(iInChannels);
272     for (int i = 0; i < iInChannels; i++) {
273     vInputChannels[i] = new AudioChannel(i, pDevice->MaxSamplesPerCycle());
274     }
275    
276     // create audio output channels
277     vOutputChannels.resize(iOutChannels);
278     for (int i = 0; i < iOutChannels; i++) {
279     vOutputChannels[i] = new AudioChannel(i, pDevice->MaxSamplesPerCycle());
280     }
281    
282     // assign (already created and initialized) control input and control
283     // output variables (effect parameters)
284     int iInControl = 0;
285     int iOutControl = 0;
286     for (int iPort = 0; iPort < pDescriptor->PortCount; iPort++) {
287     LADSPA_PortDescriptor pPortDescriptor = pDescriptor->PortDescriptors[iPort];
288     if (LADSPA_IS_PORT_CONTROL(pPortDescriptor)) {
289     if (LADSPA_IS_PORT_INPUT(pPortDescriptor)) {
290     LadspaEffectControl* pEffectControl =
291     (LadspaEffectControl*) vInputControls[iInControl++];
292 schoenebeck 2124 pDescriptor->connect_port(hEffect, iPort, &pEffectControl->Value());
293 schoenebeck 2135 } else if (LADSPA_IS_PORT_OUTPUT(pPortDescriptor)) {
294     LadspaEffectControl* pEffectControl =
295     (LadspaEffectControl*) vOutputControls[iOutControl++];
296     pDescriptor->connect_port(hEffect, iPort, &pEffectControl->Value());
297 schoenebeck 2124 }
298     }
299     }
300    
301     // call LADSPA effect's activate function (if there is one)
302     if (pDescriptor->activate != NULL)
303     pDescriptor->activate(hEffect);
304    
305     dmsg(1, ("LADSPA effect '%s' activated.\n", pInfo->label.c_str()));
306     }
307    
308     /// Returns lowest allowed value for this LADSPA control port.
309     float LadspaEffect::getLowerB(int iPort) const {
310     float low =
311     (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_BOUNDED_BELOW)
312     ? pDescriptor->PortRangeHints[iPort].LowerBound : 0.0f;
313    
314     if (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_SAMPLE_RATE)
315     low *= float(pDevice->SampleRate());
316    
317     return low;
318     }
319    
320     /// Returns biggest allowed value for this LADSPA control port.
321     float LadspaEffect::getUpperB(int iPort) const {
322     float up =
323     (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_BOUNDED_ABOVE)
324     ? pDescriptor->PortRangeHints[iPort].UpperBound : 1.0f;
325    
326     if (pDescriptor->PortRangeHints[iPort].HintDescriptor & LADSPA_HINT_SAMPLE_RATE)
327     up *= float(pDevice->SampleRate());
328    
329     return up;
330     }
331    
332     static void _foundLadspaDll(String filename, void* hDLL, void* pFunction, void* pCustom) {
333     LADSPA_Descriptor_Function fDescriptorFunction = (LADSPA_Descriptor_Function) pFunction;
334     std::vector<EffectInfo*>* pV = (std::vector<EffectInfo*>*) pCustom;
335     const LADSPA_Descriptor* psDescriptor;
336     for (long lIndex = 0; (psDescriptor = fDescriptorFunction(lIndex)) != NULL; lIndex++) {
337     //printf("\t%s (%lu/%s)\n", psDescriptor->Name, psDescriptor->UniqueID, psDescriptor->Label);
338     LadspaEffectInfo* pInfo = new LadspaEffectInfo;
339     pInfo->name = psDescriptor->Name;
340     pInfo->label = psDescriptor->Label;
341     pInfo->dll = filename;
342     pV->push_back(pInfo);
343     }
344     DynamicLibraryClose(hDLL);
345     }
346    
347     static String defaultLadspaDir() {
348     #if defined(WIN32)
349     //FIXME: hmm... who knows what the common default LADSPA path on Windows is?
350     const String sysDir = getenv("PROGRAMFILES");
351     return sysDir + "\ladspa";
352     #else
353     return "/usr/lib/ladspa";
354     #endif
355     }
356    
357     std::vector<EffectInfo*> LadspaEffect::AvailableEffects() {
358     std::vector<EffectInfo*> v; // will be filled in callback function _foundLadspaDll()
359    
360     char* pcLadspaPath = getenv("LADSPA_PATH");
361     String ladspaDir = (pcLadspaPath) ? pcLadspaPath : defaultLadspaDir();
362    
363     try {
364     DynamicLibrariesSearch(
365     ladspaDir.c_str(), "ladspa_descriptor", _foundLadspaDll, &v
366     );
367     } catch (Exception e) {
368     std::cerr << "Could not scan LADSPA effects: " << e.Message()
369     << std::endl << std::flush;
370     } catch (...) {
371     std::cerr << "Could not scan LADSPA effects: unknown exception\n"
372     << std::flush;
373     }
374    
375     return v;
376     }
377    
378     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC