1 //
2 // C++ Interface: plugin
3 //
4 // Description:
5 //
6 //
7 //  (C) Copyright 2000 Werner Schweer (ws@seh.de)
8 // Additions/modifications: Mathias Lundgren <lunar_shuttle@users.sf.net>, (C) 2004
9 //                          (C) Copyright 2011 Tim E. Real (terminator356 at users.sourceforge.net)
10 //
11 //  This program is free software; you can redistribute it and/or
12 //  modify it under the terms of the GNU General Public License
13 //  as published by the Free Software Foundation; version 2 of
14 //  the License, or (at your option) any later version.
15 //
16 //  This program is distributed in the hope that it will be useful,
17 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 //  GNU General Public License for more details.
20 //
21 //  You should have received a copy of the GNU General Public License
22 //  along with this program; if not, write to the Free Software
23 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24 //
25 //
26 
27 #ifndef __SIMPLER_PLUGIN_H__
28 #define __SIMPLER_PLUGIN_H__
29 
30 #include <vector>
31 #include <QFileInfo>
32 #include <QString>
33 
34 #include <ladspa.h>
35 #include "muse_math.h"
36 
37 #include "globaldefs.h"
38 #include "plugin_scan.h"
39 
40 #define SS_PLUGIN_PARAM_MIN                  0
41 #define SS_PLUGIN_PARAM_MAX                127
42 
43 namespace MusESimplePlugin {
44 
45 //---------------------------------------------------------
46 //   Port
47 //---------------------------------------------------------
48 
49 struct Port {
50       float _val;
51       };
52 
53 //---------------------------------------------------------
54 //   Plugin base class
55 //---------------------------------------------------------
56 
57 class PluginI;
58 
59 class Plugin
60    {
61    protected:
62       QFileInfo _fi;
63       void* _libHandle;
64       int _references;
65       int _instNo;
66       unsigned long _uniqueID;
67       QString _label;
68       QString _name;
69       QString _maker;
70       QString _copyright;
71 
72       // Total number of ports.
73       unsigned long _portCount;
74       unsigned long _inports;
75       unsigned long _outports;
76       unsigned long _controlInPorts;
77       unsigned long _controlOutPorts;
78 
79       MusECore::PluginFeatures_t _requiredFeatures;
80 
81       std::vector<unsigned long> _pIdx; //control port numbers
82       std::vector<unsigned long> _poIdx; //control out port numbers
83       std::vector<unsigned long> _iIdx; //input port numbers
84       std::vector<unsigned long> _oIdx; //output port numbers
85 
86    public:
Plugin(const QFileInfo * f)87       Plugin(const QFileInfo* f)
88         : _fi(*f), _libHandle(0), _references(0), _instNo(0), _uniqueID(0),
89           _portCount(0),_inports(0), _outports(0),
90           _controlInPorts(0),_controlOutPorts(0),
91           _requiredFeatures(MusECore::PluginNoFeatures) { }
92       Plugin(const MusEPlugin::PluginScanInfoStruct& info);
~Plugin()93       virtual ~Plugin() {}
94 
95       //----------------------------------------------------
96       // The following methods can be called regardless of
97       //  whether the libray is open or not, ie. zero or more
98       //  instances exist. The information is cached.
99       //----------------------------------------------------
100 
101       // Returns features required by the plugin.
requiredFeatures()102       MusECore::PluginFeatures_t requiredFeatures() const { return _requiredFeatures; }
103 
104       // Create and initialize a plugin instance. Returns null if failure.
105       // Equivalent to calling (new ***PlugI())->initPluginInstance(this, ...).
106       // The returned type depends on the derived class (LadspaPluginI*, Lv2PluginI*, etc).
107       // Caller is responsible for deleting the returned object.
108       virtual PluginI* createPluginI(int chans, float sampleRate, unsigned int segmentSize,
109                              bool useDenormalBias, float denormalBias) = 0;
110 
references()111       int references() const            { return _references; }
incReferences(int)112       virtual int incReferences(int)    { return _references; }
instNo()113       int instNo()                      { return _instNo++;   }
instantiate(float,void *)114       virtual void* instantiate(float /*sampleRate*/, void* /*data*/) { return 0; }
115 
label()116       QString label() const                        { return _label; }
name()117       QString name() const                         { return _name; }
id()118       unsigned long id() const                     { return _uniqueID; }
maker()119       QString maker() const                        { return _maker; }
copyright()120       QString copyright() const                    { return _copyright; }
121       QString lib(bool complete = true) const      { return complete ? _fi.completeBaseName() : _fi.baseName(); }
122       QString dirPath(bool complete = true) const  { return complete ? _fi.absolutePath() : _fi.path(); }
filePath()123       QString filePath() const                     { return _fi.filePath(); }
fileName()124       QString fileName() const                     { return _fi.fileName(); }
125 
126       // Total number of ports.
portCount()127       unsigned long portCount() const       { return _portCount; }
parameter()128       unsigned long parameter() const       { return _controlInPorts; }
parameterOut()129       unsigned long parameterOut() const    { return _controlOutPorts; }
inports()130       unsigned long inports() const         { return _inports;     }
outports()131       unsigned long outports() const        { return _outports;     }
inPlaceCapable()132       bool inPlaceCapable() const           { return !(_requiredFeatures & MusECore::PluginNoInPlaceProcessing); }
133 
134 
135       //----------------------------------------------------
136       // The following methods require the library be open,
137       //  ie. at least one instance exists.
138       //----------------------------------------------------
139 
isAudioIn(unsigned long)140       virtual bool isAudioIn(unsigned long) const { return false; }
isAudioOut(unsigned long)141       virtual bool isAudioOut(unsigned long) const { return false; }
isParameterIn(unsigned long)142       virtual bool isParameterIn(unsigned long) const { return false; }
isParameterOut(unsigned long)143       virtual bool isParameterOut(unsigned long) const { return false; }
144 
isLog(unsigned long)145       virtual bool isLog(unsigned long) const         { return false; }
isBool(unsigned long)146       virtual bool isBool(unsigned long) const        { return false; }
isInt(unsigned long)147       virtual bool isInt(unsigned long) const         { return false; }
isLinear(unsigned long)148       virtual bool isLinear(unsigned long) const      { return false; }
defaultValue(unsigned long)149       virtual float defaultValue(unsigned long) const { return 0.0f;  }
150       virtual bool range(unsigned long, float /*sampleRate*/, float* min, float* max) const = 0;
151       virtual bool rangeOut(unsigned long, float /*sampleRate*/, float* min, float* max) const = 0;
getParameterName(unsigned long)152       virtual const char* getParameterName(unsigned long /*param*/) const    { return ""; }
getParameterOutName(unsigned long)153       virtual const char* getParameterOutName(unsigned long /*param*/) const { return ""; }
154 
activate(void *)155       virtual void activate(void* /*handle*/) { }
deactivate(void *)156       virtual void deactivate(void* /*handle*/) { }
cleanup(void *)157       virtual void cleanup(void* /*handle*/) { }
connectInport(void *,unsigned long,void *)158       virtual void connectInport(void* /*handle*/, unsigned long, void* /*datalocation*/) { }
connectOutport(void *,unsigned long,void *)159       virtual void connectOutport(void* /*handle*/, unsigned long, void* /*datalocation*/) { }
connectCtrlInport(void *,unsigned long,void *)160       virtual void connectCtrlInport(void* /*handle*/, unsigned long, void* /*datalocation*/) { }
connectCtrlOutport(void *,unsigned long,void *)161       virtual void connectCtrlOutport(void* /*handle*/, unsigned long, void* /*datalocation*/) { }
connectPort(void *,unsigned long,float *)162       virtual void connectPort(void* /*handle*/, unsigned long /*port*/, float* /*value*/) { }
apply(void *,unsigned long)163       virtual void apply(void* /*handle*/, unsigned long /*n*/) { }
164    };
165 
166 //---------------------------------------------------------
167 //   LadspaPlugin
168 //---------------------------------------------------------
169 
170 #define IS_AUDIO_IN (LADSPA_PORT_AUDIO  | LADSPA_PORT_INPUT)
171 #define IS_AUDIO_OUT (LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT)
172 #define IS_PARAMETER_IN (LADSPA_PORT_CONTROL  | LADSPA_PORT_INPUT)
173 #define IS_PARAMETER_OUT (LADSPA_PORT_CONTROL | LADSPA_PORT_OUTPUT)
174 
175 class LadspaPlugin : public Plugin
176    {
177    private:
178       const LADSPA_Descriptor* _plugin;
179 
180       // Accepts a master port index.
181       bool port_range(unsigned long k, float sampleRate, float* min, float* max) const;
182 
183    public:
184       LadspaPlugin(const QFileInfo* f, const LADSPA_Descriptor_Function, const LADSPA_Descriptor* d);
185       LadspaPlugin(const MusEPlugin::PluginScanInfoStruct& info);
~LadspaPlugin()186       virtual ~LadspaPlugin() { }
187 
188       // Create and initialize a LADSPA plugin instance. Returns null if failure.
189       // Equivalent to calling (new LadspaPlugI())->initPluginInstance(this, ...).
190       // The returned type depends on the this class (LadspaPluginI*, Lv2PluginI*, etc).
191       // Caller is responsible for deleting the returned object.
192       PluginI* createPluginI(int chans, float sampleRate, unsigned int segmentSize,
193                              bool useDenormalBias, float denormalBias);
194 
195       int incReferences(int);
196 
isAudioIn(unsigned long k)197       bool isAudioIn(unsigned long k) const {
198             if(!_plugin)
199               return false;
200             return (_plugin->PortDescriptors[k] & IS_AUDIO_IN) == IS_AUDIO_IN;
201             }
isAudioOut(unsigned long k)202       bool isAudioOut(unsigned long k) const {
203             if(!_plugin)
204               return false;
205             return (_plugin->PortDescriptors[k] & IS_AUDIO_OUT) == IS_AUDIO_OUT;
206             }
isParameterIn(unsigned long k)207       bool isParameterIn(unsigned long k) const {
208             if(!_plugin)
209               return false;
210             return (_plugin->PortDescriptors[k] & IS_PARAMETER_IN) == IS_PARAMETER_IN;
211             }
isParameterOut(unsigned long k)212       bool isParameterOut(unsigned long k) const {
213             if(!_plugin)
214               return false;
215             return (_plugin->PortDescriptors[k] & IS_PARAMETER_OUT) == IS_PARAMETER_OUT;
216             }
217 
isLog(unsigned long k)218       bool isLog(unsigned long k) const {
219             if(!_plugin)
220               return false;
221             LADSPA_PortRangeHint r = _plugin->PortRangeHints[_pIdx[k]];
222             return LADSPA_IS_HINT_LOGARITHMIC(r.HintDescriptor);
223             }
isBool(unsigned long k)224       bool isBool(unsigned long k) const {
225             if(!_plugin)
226               return false;
227             return LADSPA_IS_HINT_TOGGLED(_plugin->PortRangeHints[_pIdx[k]].HintDescriptor);
228             }
isInt(unsigned long k)229       bool isInt(unsigned long k) const {
230             if(!_plugin)
231               return false;
232             LADSPA_PortRangeHint r = _plugin->PortRangeHints[_pIdx[k]];
233             return LADSPA_IS_HINT_INTEGER(r.HintDescriptor);
234             }
isLinear(unsigned long k)235       bool isLinear(unsigned long k) const {
236             if(!_plugin)
237               return false;
238             LADSPA_PortRangeHint r = _plugin->PortRangeHints[_pIdx[k]];
239             return !LADSPA_IS_HINT_INTEGER(r.HintDescriptor) &&
240                    !LADSPA_IS_HINT_LOGARITHMIC(r.HintDescriptor) &&
241                    !LADSPA_IS_HINT_TOGGLED(r.HintDescriptor);
242             }
243       bool range(unsigned long k, float sampleRate, float*, float*) const;
244       bool rangeOut(unsigned long k, float sampleRate, float*, float*) const;
getParameterName(unsigned long k)245       const char* getParameterName(unsigned long k) const {
246             if(!_plugin)
247               return 0;
248             return _plugin->PortNames[_pIdx[k]];
249             }
getParameterOutName(unsigned long k)250       const char* getParameterOutName(unsigned long k) const {
251             if(!_plugin)
252               return 0;
253             return _plugin->PortNames[_poIdx[k]];
254             }
255       float defaultValue(unsigned long k) const;
256 
257       float convertGuiControlValue(unsigned long k, float sampleRate, int val) const;
258 
259       void* instantiate(float sampleRate, void* /*data*/);
260       void connectInport(void* handle, unsigned long k, void* datalocation);
261       void connectOutport(void* handle, unsigned long k, void* datalocation);
262       void connectCtrlInport(void* handle, unsigned long k, void* datalocation);
263       void connectCtrlOutport(void* handle, unsigned long k, void* datalocation);
264 
activate(void * handle)265       void activate(void* handle) {
266             if (_plugin && _plugin->activate)
267                   _plugin->activate((LADSPA_Handle)handle);
268             }
deactivate(void * handle)269       void deactivate(void* handle) {
270             if (_plugin && _plugin->deactivate)
271                   _plugin->deactivate((LADSPA_Handle)handle);
272             }
cleanup(void * handle)273       void cleanup(void* handle) {
274             if (_plugin && _plugin->cleanup)
275                   _plugin->cleanup((LADSPA_Handle)handle);
276             }
connectPort(void * handle,unsigned long port,float * datalocation)277       void connectPort(void* handle, unsigned long port, float* datalocation) {
278             if(_plugin)
279               _plugin->connect_port((LADSPA_Handle)handle, port, datalocation);
280             }
apply(void * handle,unsigned long n)281       void apply(void* handle, unsigned long n) {
282             if(_plugin && _plugin->run)
283               _plugin->run((LADSPA_Handle)handle, n);
284             }
285    };
286 
287 //--------------------------------
288 //  PluginI
289 //  Plugin Instance base class
290 //--------------------------------
291 
292 class PluginI {
293    private:
294       void init();
295 
296    protected:
297       Plugin* _plugin;
298       // Some APIs may need to point to a float or double samplerate, or both (LV2).
299       float _sampleRate;
300       double _dSampleRate;
301       unsigned int _segmentSize;
302       int _channel;
303       int _instances;
304       int _id;
305 
306       Port* _controls;
307       Port* _controlsOut;
308       Port* _controlsOutDummy;
309 
310       unsigned long _audioInPorts;
311       unsigned long _audioOutPorts;
312       unsigned long _controlPorts;
313       unsigned long _controlOutPorts;
314 
315       bool          _hasLatencyOutPort;
316       unsigned long _latencyOutPort;
317 
318       float *_audioInSilenceBuf; // Just all zeros all the time, so we don't have to clear for silence.
319       float *_audioOutDummyBuf;  // A place to connect unused outputs.
320 
321       bool _on;
322       QString _name;
323       QString _label;
324 
325    public:
326       PluginI();
327       virtual ~PluginI();
328 
plugin()329       Plugin* plugin() const { return _plugin; }
330 
requiredFeatures()331       MusECore::PluginFeatures_t requiredFeatures() const {
332         if(!_plugin) return MusECore::PluginNoFeatures;
333         return _plugin->requiredFeatures(); }
334 
on()335       bool on() const        { return _on; }
setOn(bool val)336       void setOn(bool val)   { _on = val; }
337 
pluginID()338       unsigned long pluginID()      { return _plugin->id(); }
339       void setID(int i);
id()340       int id()                      { return _id; }
341 
inPlaceCapable()342       bool inPlaceCapable() const {
343         if(!_plugin) return false;
344         return _plugin->inPlaceCapable();
345         }
346 
347       // Returns true on error.
348       virtual bool initPluginInstance(Plugin* plug, int channels,
349                               float sampleRate, unsigned int segmentSize,
350                               bool useDenormalBias, float denormalBias) = 0;
sampleRate()351       float sampleRate() const { return _sampleRate; }
setSampleRate(float rate)352       void setSampleRate(float rate) { _sampleRate = rate; _dSampleRate = rate; }
segmentSize()353       unsigned int segmentSize() const { return _segmentSize; }
channels()354       int channels() const { return _channel; }
355       virtual void setChannels(int chans) = 0;
356       // Runs the plugin for frames. Any ports involved must already be connected.
357       virtual void process(unsigned long frames) = 0;
358       // Runs the plugin for frames. This automatically connects the given
359       //  data locations to the ports each time it is called.
360       void apply(unsigned pos, unsigned long frames, unsigned long ports, float** bufIn, float** bufOut);
361 
362       // Connects ports with data locations. Multiple sources and destinations, with offset.
363       virtual void connect(unsigned long ports, unsigned long offset, float** src, float** dst) = 0;
364 //       // Connects a single audio input port to a data location.
365 //       void connectInport(unsigned long k, void* datalocation);
366 //       // Connects a single audio output port to a data location.
367 //       void connectOutport(unsigned long k, void* datalocation);
368 //       // Connects a single control parameter input port to a data location.
369 //       void connectCtrlInport(unsigned long k, void* datalocation);
370 //       // Connects a single control parameter output port to a data location.
371 //       void connectCtrlOutport(unsigned long k, void* datalocation);
372 
373       // Returns true on success.
374       bool start();
375       // Returns true on success.
376       bool stop();
377 
isAudioIn(unsigned long k)378       bool isAudioIn(unsigned long k) {
379             if(!_plugin) return false;
380             return _plugin->isAudioIn(k);
381             }
382 
isAudioOut(unsigned long k)383       bool isAudioOut(unsigned long k) {
384             if(!_plugin) return false;
385             return _plugin->isAudioOut(k);
386             }
387 
isLog(unsigned long k)388       bool isLog(unsigned long k) const {
389             if(!_plugin) return false;
390             return _plugin->isLog(k);
391             }
isBool(unsigned long k)392       bool isBool(unsigned long k) const {
393             if(!_plugin) return false;
394             return _plugin->isBool(k);
395             }
isInt(unsigned long k)396       bool isInt(unsigned long k) const {
397             if(!_plugin) return false;
398             return _plugin->isInt(k);
399             }
isLinear(unsigned long k)400       bool isLinear(unsigned long k) const {
401             if(!_plugin) return false;
402             return _plugin->isLinear(k);
403             }
404 
range(unsigned long i,float * min,float * max)405       void range(unsigned long i, float* min, float* max) const {
406             if(!_plugin) return;
407               _plugin->range(i, _sampleRate, min, max);
408             }
rangeOut(unsigned long i,float * min,float * max)409       void rangeOut(unsigned long i, float* min, float* max) const {
410             if(!_plugin) return;
411               _plugin->rangeOut(i, _sampleRate, min, max);
412             }
getParameterName(unsigned long i)413       const char* getParameterName(unsigned long i) const {
414             if(!_plugin) return 0;
415             return _plugin->getParameterName(i);
416             }
getParameterOutName(unsigned long i)417       const char* getParameterOutName(unsigned long i) const {
418             if(!_plugin) return 0;
419             return _plugin->getParameterOutName(i);
420             }
defaultValue(unsigned long i)421       float defaultValue(unsigned long i) const {
422             if(!_plugin) return 0.0;
423             return _plugin->defaultValue(i);
424             }
425 
426       // Return true on success.
427       virtual bool activate() = 0;
428       // Return true on success.
429       virtual bool deactivate() = 0;
pluginLabel()430       QString pluginLabel() const    { return _plugin->label(); }
label()431       QString label() const          { return _label; }
name()432       QString name() const           { return _name; }
lib()433       QString lib() const            { return _plugin->lib(); }
dirPath()434       QString dirPath() const        { return _plugin->dirPath(); }
fileName()435       QString fileName() const       { return _plugin->fileName(); }
436 
437       bool setControl(const QString& s, float val);
438 
inports()439       unsigned long inports() const           { return _audioInPorts; }
outports()440       unsigned long outports() const          { return _audioOutPorts; }
parameters()441       unsigned long parameters() const        { return _controlPorts; }
parametersOut()442       unsigned long parametersOut() const     { return _controlOutPorts; }
443 
444       void setParam(unsigned long i, float val);
param(unsigned long i)445       float param(unsigned long i) const { if(i >= _controlPorts) return 0.0; return _controls[i]._val; }
paramOut(unsigned long i)446       float paramOut(unsigned long i) const { if(i >= _controlOutPorts) return 0.0; return _controlsOut[i]._val; }
447 
448       // Alias for getParameterName.
paramName(unsigned long i)449       const char* paramName(unsigned long i) const    { return getParameterName(i); }
paramOutName(unsigned long i)450       const char* paramOutName(unsigned long i) const { return getParameterOutName(i); }
451 
452       float latency() const;
453       //CtrlValueType ctrlValueType(unsigned long i) const { return _plugin->ctrlValueType(controls[i].idx); }
454       //CtrlList::Mode ctrlMode(unsigned long i) const { return _plugin->ctrlMode(controls[i].idx); }
455 
456       int   getGuiControlValue(unsigned long parameter) const;
457       float convertGuiControlValue(unsigned long parameter, int val) const;
458       };
459 
460 
461 //--------------------------------
462 //  LadspaPluginI
463 //  Ladspa Plugin Instance class
464 //--------------------------------
465 
466 class LadspaPluginI : public PluginI {
467    private:
468       LADSPA_Handle* _handle; // per instance
469       void init();
470 
471    public:
472       LadspaPluginI();
473       virtual ~LadspaPluginI();
474 
475       // Returns true on error.
476       bool initPluginInstance(Plugin* plug, int channels,
477                               float sampleRate, unsigned int segmentSize,
478                               bool useDenormalBias, float denormalBias);
479       void setChannels(int chans);
480       // Runs the plugin for frames. Any ports involved must already be connected.
481       void process(unsigned long frames);
482 
483       // Connects ports with data locations. Multiple sources and destinations, with offset.
484       void connect(unsigned long ports, unsigned long offset, float** src, float** dst);
485 //       // Connects a single audio input port to a data location.
486 //       void connectInport(unsigned long k, void* datalocation);
487 //       // Connects a single audio output port to a data location.
488 //       void connectOutport(unsigned long k, void* datalocation);
489 //       // Connects a single control parameter input port to a data location.
490 //       void connectCtrlInport(unsigned long k, void* datalocation);
491 //       // Connects a single control parameter output port to a data location.
492 //       void connectCtrlOutport(unsigned long k, void* datalocation);
493 
494       // Return true on success.
495       bool activate();
496       // Return true on success.
497       bool deactivate();
498       };
499 
fast_log2(float val)500 static inline float fast_log2 (float val)
501       {
502       /* don't use reinterpret_cast<> because that prevents this
503          from being used by pure C code (for example, GnomeCanvasItems)
504       */
505       int* const exp_ptr = (int *)(&val);
506       int x              = *exp_ptr;
507       const int log_2    = ((x >> 23) & 255) - 128;
508       x &= ~(255 << 23);
509       x += 127 << 23;
510       *exp_ptr = x;
511       val = ((-1.0f/3) * val + 2) * val - 2.0f/3;   // (1)
512       return (val + log_2);
513       }
514 
fast_log10(const float val)515 static inline float fast_log10 (const float val)
516       {
517       return fast_log2(val) / 3.312500f;
518       }
519 
520 //---------------------------------------------------------
521 //   PluginList
522 //---------------------------------------------------------
523 
524 typedef std::list<Plugin*>::iterator iPlugin;
525 
526 class PluginList : public std::list<Plugin*> {
527    public:
528       Plugin* find(const QString& file, const QString& name);
PluginList()529       PluginList() {}
530       ~PluginList();
531       };
532 
533 extern void SS_initPlugins(const QString& hostCachePath);
534 extern PluginList plugins;
535 
536 } // namespace MusESimplePlugin
537 
538 #endif
539