1 //
2 // C++ Implementation: plugin
3 //
4 // Description:
5 //
6 // (C) Copyright 2000 Werner Schweer (ws@seh.de)
7 //
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 //
12 // This program is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU General Public License
14 // as published by the Free Software Foundation; version 2 of
15 // the License, or (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 //
26 //
27
28 #include <QtCore>
29 #include <QtWidgets>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <dlfcn.h>
34 #include <string>
35
36 #include "simpler_plugin.h"
37 #include "plugin_cache_reader.h"
38
39 #define SS_LOG_MAX 0
40 #define SS_LOG_MIN -10
41 #define SS_LOG_OFFSET SS_LOG_MIN
42
43
44 #define SP_TRACE_FUNC 0
45 #define SP_DEBUG_LADSPA 0
46
47 #define SP_TRACE_IN if (SP_TRACE_FUNC) fprintf (stderr, "->%s:%d\n", __PRETTY_FUNCTION__, __LINE__);
48 #define SP_TRACE_OUT if (SP_TRACE_FUNC) fprintf (stderr, "<-%s:%d\n", __PRETTY_FUNCTION__, __LINE__);
49 #define SP_ERROR(string) fprintf(stderr, "SimplePlugin error: %s\n", string)
50 #define SP_DBG_LADSPA(string1) if (SP_DEBUG_LADSPA) fprintf(stderr, "%s:%d:%s: %s\n", __FILE__ , __LINE__ , __PRETTY_FUNCTION__, string1);
51 #define SP_DBG_LADSPA2(string1, string2) if (SP_DEBUG_LADSPA) fprintf(stderr, "%s:%d:%s: %s: %s\n", __FILE__ , __LINE__ , __PRETTY_FUNCTION__, string1, string2);
52
53 // Turn on debugging messages.
54 //#define PLUGIN_DEBUGIN
55
56 // Turn on constant stream of debugging messages.
57 //#define PLUGIN_DEBUGIN_PROCESS
58
59 namespace MusESimplePlugin {
60
61 PluginList plugins;
62
63 //
64 // Map plugin parameter on domain [SS_PLUGIN_PARAM_MIN, SS_PLUGIN_PARAM_MAX] to domain [SS_LOG_MIN, SS_LOG_MAX] (log domain)
65 //
SS_map_pluginparam2logdomain(int pluginparam_val)66 float SS_map_pluginparam2logdomain(int pluginparam_val)
67 {
68 float scale = (float) (SS_LOG_MAX - SS_LOG_MIN)/ (float) SS_PLUGIN_PARAM_MAX;
69 float scaled = (float) pluginparam_val * scale;
70 float mapped = scaled + SS_LOG_OFFSET;
71 return mapped;
72 }
73 //
74 // Map plugin parameter on domain to domain [SS_LOG_MIN, SS_LOG_MAX] to [SS_PLUGIN_PARAM_MIN, SS_PLUGIN_PARAM_MAX] (from log-> [0,127])
75 // (inverse func to the above)
SS_map_logdomain2pluginparam(float pluginparam_log)76 int SS_map_logdomain2pluginparam(float pluginparam_log)
77 {
78 float mapped = pluginparam_log - SS_LOG_OFFSET;
79 float scale = (float) SS_PLUGIN_PARAM_MAX / (float) (SS_LOG_MAX - SS_LOG_MIN);
80 int scaled = (int) round(mapped * scale);
81 return scaled;
82 }
83
84 //---------------------------------------------------------
85 // initPlugins
86 // search for LADSPA plugins
87 //---------------------------------------------------------
88
SS_initPlugins(const QString & hostCachePath)89 void SS_initPlugins(const QString& hostCachePath)
90 {
91 SP_TRACE_IN
92
93 MusEPlugin::PluginScanList scan_list;
94 // Read host plugin cache file. We only want ladspa plugins for now...
95 MusEPlugin::readPluginCacheFile(hostCachePath + "/scanner",
96 &scan_list,
97 false,
98 false,
99 MusEPlugin::PluginScanInfoStruct::PluginTypeLADSPA);
100 for(MusEPlugin::ciPluginScanList isl = scan_list.begin(); isl != scan_list.end(); ++isl)
101 {
102 const MusEPlugin::PluginScanInfoRef inforef = *isl;
103 const MusEPlugin::PluginScanInfoStruct& info = inforef->info();
104 switch(info._type)
105 {
106 case MusEPlugin::PluginScanInfoStruct::PluginTypeLADSPA:
107 {
108 //if(MusEGlobal::loadPlugins)
109 {
110 // Make sure it doesn't already exist.
111 if(/*Plugin* pl =*/ plugins.find(PLUGIN_GET_QSTRING(info._completeBaseName),
112 PLUGIN_GET_QSTRING(info._label)))
113 {
114 //fprintf(stderr, "Ignoring LADSPA effect label:%s path:%s duplicate of path:%s\n",
115 // info._label.toLatin1().constData(),
116 // info._fi.filePath().toLatin1().constData(),
117 // pl->filePath().toLatin1().constData());
118 }
119 else
120 {
121 plugins.push_back(new LadspaPlugin(info));
122 }
123 }
124 }
125 break;
126
127 case MusEPlugin::PluginScanInfoStruct::PluginTypeDSSI:
128 case MusEPlugin::PluginScanInfoStruct::PluginTypeDSSIVST:
129 case MusEPlugin::PluginScanInfoStruct::PluginTypeVST:
130 case MusEPlugin::PluginScanInfoStruct::PluginTypeLV2:
131 case MusEPlugin::PluginScanInfoStruct::PluginTypeLinuxVST:
132 case MusEPlugin::PluginScanInfoStruct::PluginTypeMESS:
133 case MusEPlugin::PluginScanInfoStruct::PluginTypeUnknown:
134 case MusEPlugin::PluginScanInfoStruct::PluginTypeNone:
135 case MusEPlugin::PluginScanInfoStruct::PluginTypeAll:
136 break;
137 }
138 }
139
140 SP_TRACE_OUT
141 }
142
143 //---------------------------------------------------------
144 // find
145 //---------------------------------------------------------
146
find(const QString & file,const QString & name)147 Plugin* PluginList::find(const QString& file, const QString& name)
148 {
149 SP_TRACE_IN
150 for (iPlugin i = begin(); i != end(); ++i) {
151 if ((file == (*i)->lib()) && (name == (*i)->label())) {
152 SP_TRACE_OUT
153 return *i;
154 }
155 }
156 //fprintf(stderr, "Plugin <%s> not found\n", name.toLatin1().constData());
157 SP_TRACE_OUT
158 return 0;
159 }
160
~PluginList()161 PluginList::~PluginList()
162 {
163 //fprintf(stderr, "~PluginList\n");
164 //Cleanup plugins:
165 for (iPlugin i = plugins.begin(); i != plugins.end(); ++i)
166 {
167 if((*i)->references() != 0)
168 {
169 fprintf(stderr, "~PluginList: Plugin <%s> reference count not zero! Cannot delete.\n",
170 (*i)->name().toLatin1().constData());
171 continue;
172 }
173 //fprintf(stderr, "~PluginList: deleting plugin <%s>\n",
174 // (*i)->name().toLatin1().constData());
175 delete (*i);
176 }
177 }
178
179 //---------------------------------------------------------
180 // Plugin
181 //---------------------------------------------------------
182
Plugin(const MusEPlugin::PluginScanInfoStruct & info)183 Plugin::Plugin(const MusEPlugin::PluginScanInfoStruct& info)
184 : _fi(PLUGIN_GET_QSTRING(info.filePath())),
185 _libHandle(0),
186 _references(0),
187 _instNo(0),
188 _uniqueID(info._uniqueID),
189 _label(PLUGIN_GET_QSTRING(info._label)),
190 _name(PLUGIN_GET_QSTRING(info._name)),
191 _maker(PLUGIN_GET_QSTRING(info._maker)),
192 _copyright(PLUGIN_GET_QSTRING(info._copyright)),
193 _portCount(info._portCount),
194 _inports(info._inports),
195 _outports(info._outports),
196 _controlInPorts(info._controlInPorts),
197 _controlOutPorts(info._controlOutPorts),
198 _requiredFeatures(info._requiredFeatures) { }
199
200 //---------------------------------------------------------
201 // LadspaPlugin
202 //---------------------------------------------------------
203
LadspaPlugin(const QFileInfo * f,const LADSPA_Descriptor_Function,const LADSPA_Descriptor * d)204 LadspaPlugin::LadspaPlugin(const QFileInfo* f,
205 const LADSPA_Descriptor_Function /*ldf*/,
206 const LADSPA_Descriptor* d)
207 : Plugin(f)
208 {
209 SP_TRACE_IN
210
211 _plugin = NULL;
212
213 _label = QString(d->Label);
214 _name = QString(d->Name);
215 _uniqueID = d->UniqueID;
216 _maker = QString(d->Maker);
217 _copyright = QString(d->Copyright);
218 _portCount = d->PortCount;
219
220 for(unsigned long k = 0; k < _portCount; ++k)
221 {
222 LADSPA_PortDescriptor pd = d->PortDescriptors[k];
223 if(pd & LADSPA_PORT_AUDIO)
224 {
225 if(pd & LADSPA_PORT_INPUT)
226 {
227 ++_inports;
228 }
229 else
230 if(pd & LADSPA_PORT_OUTPUT)
231 {
232 ++_outports;
233 }
234 }
235 else
236 if(pd & LADSPA_PORT_CONTROL)
237 {
238 if(pd & LADSPA_PORT_INPUT)
239 {
240 ++_controlInPorts;
241 }
242 else
243 if(pd & LADSPA_PORT_OUTPUT)
244 {
245 ++_controlOutPorts;
246 }
247 }
248 }
249
250 /*if (SP_DEBUG_LADSPA) {
251 printf("Label: %s\tLib: %s\tPortCount: %d\n", this->label().toLatin1().constData(), this->lib().toLatin1().constData(), plugin->PortCount);
252 printf("LADSPA_PORT_CONTROL|LADSPA_PORT_INPUT: %d\t", pIdx.size());
253 printf("Input ports: %d\t", iIdx.size());
254 printf("Output ports: %d\n\n", oIdx.size());
255 }*/
256
257 if ((_inports != _outports) || (LADSPA_IS_INPLACE_BROKEN(d->Properties)))
258 _requiredFeatures |= MusECore::PluginNoInPlaceProcessing;
259
260 SP_TRACE_OUT
261 }
262
LadspaPlugin(const MusEPlugin::PluginScanInfoStruct & info)263 LadspaPlugin::LadspaPlugin(const MusEPlugin::PluginScanInfoStruct& info)
264 : Plugin(info), _plugin(NULL)
265 {
266 SP_TRACE_IN
267
268 SP_TRACE_OUT
269 }
270
271 //---------------------------------------------------------
272 // createPluginI
273 //---------------------------------------------------------
274
createPluginI(int chans,float sampleRate,unsigned int segmentSize,bool useDenormalBias,float denormalBias)275 PluginI* LadspaPlugin::createPluginI(int chans, float sampleRate, unsigned int segmentSize,
276 bool useDenormalBias, float denormalBias)
277 {
278 LadspaPluginI* plug_i = new LadspaPluginI();
279 if(plug_i->initPluginInstance(
280 this,
281 chans,
282 sampleRate,
283 segmentSize,
284 useDenormalBias,
285 denormalBias))
286 {
287 fprintf(stderr, "LadspaPlugin::createPluginI: cannot instantiate plugin <%s>\n",
288 name().toLatin1().constData());
289 // Make sure to delete the PluginI.
290 delete plug_i;
291 return 0;
292 }
293 return plug_i;
294 }
295
296
297 //---------------------------------------------------------
298 // incReferences
299 //---------------------------------------------------------
300
incReferences(int val)301 int LadspaPlugin::incReferences(int val)
302 {
303 #ifdef PLUGIN_DEBUGIN
304 fprintf(stderr, "LadspaPlugin::incReferences _references:%d val:%d\n", _references, val);
305 #endif
306
307 int newref = _references + val;
308
309 if(newref <= 0)
310 {
311 _references = 0;
312 if(_libHandle)
313 {
314 #ifdef PLUGIN_DEBUGIN
315 fprintf(stderr, "LadspaPlugin::incReferences no more instances, closing library\n");
316 #endif
317
318 dlclose(_libHandle);
319 }
320
321 _libHandle = 0;
322 _plugin = NULL;
323 _pIdx.clear();
324 _poIdx.clear();
325 _iIdx.clear();
326 _oIdx.clear();
327 _requiredFeatures = MusECore::PluginNoFeatures;
328
329 return 0;
330 }
331
332 if(_libHandle == 0)
333 {
334 _libHandle = dlopen(_fi.filePath().toLatin1().constData(), RTLD_NOW);
335
336 if(_libHandle == 0)
337 {
338 fprintf(stderr, "LadspaPlugin::incReferences dlopen(%s) failed: %s\n",
339 _fi.filePath().toLatin1().constData(), dlerror());
340 return 0;
341 }
342
343 LADSPA_Descriptor_Function ladspadf = (LADSPA_Descriptor_Function)dlsym(_libHandle, "ladspa_descriptor");
344 if(ladspadf)
345 {
346 const LADSPA_Descriptor* descr;
347 for(unsigned long i = 0;; ++i)
348 {
349 descr = ladspadf(i);
350 if(descr == NULL)
351 break;
352
353 QString desc_label(descr->Label);
354 if(desc_label == label())
355 {
356 _plugin = descr;
357 break;
358 }
359 }
360 }
361
362 if(_plugin != NULL)
363 {
364 _uniqueID = _plugin->UniqueID;
365
366 _label = QString(_plugin->Label);
367 _name = QString(_plugin->Name);
368 _maker = QString(_plugin->Maker);
369 _copyright = QString(_plugin->Copyright);
370
371 _portCount = _plugin->PortCount;
372 _inports = 0;
373 _outports = 0;
374 _controlInPorts = 0;
375 _controlOutPorts = 0;
376
377 for(unsigned long k = 0; k < _portCount; ++k)
378 {
379 LADSPA_PortDescriptor pd = _plugin->PortDescriptors[k];
380 if(pd & LADSPA_PORT_AUDIO)
381 {
382 if(pd & LADSPA_PORT_INPUT)
383 {
384 ++_inports;
385 _iIdx.push_back(k);
386 }
387 else
388 if(pd & LADSPA_PORT_OUTPUT)
389 {
390 ++_outports;
391 _oIdx.push_back(k);
392 }
393 }
394 else
395 if(pd & LADSPA_PORT_CONTROL)
396 {
397 if(pd & LADSPA_PORT_INPUT)
398 {
399 ++_controlInPorts;
400 _pIdx.push_back(k);
401 }
402 else
403 if(pd & LADSPA_PORT_OUTPUT)
404 {
405 ++_controlOutPorts;
406 _poIdx.push_back(k);
407 }
408 }
409 }
410 }
411 }
412
413 if(_plugin == NULL)
414 {
415 dlclose(_libHandle);
416 _libHandle = 0;
417 _references = 0;
418 fprintf(stderr, "LadspaPlugin::incReferences Error: %s no plugin!\n", _fi.filePath().toLatin1().constData());
419 return 0;
420 }
421
422 if ((_inports != _outports) || (LADSPA_IS_INPLACE_BROKEN(_plugin->Properties)))
423 _requiredFeatures |= MusECore::PluginNoInPlaceProcessing;
424
425 _references = newref;
426
427 return _references;
428 }
429
430 //---------------------------------------------------------
431 // instantiate
432 //---------------------------------------------------------
433
instantiate(float sampleRate,void *)434 void* LadspaPlugin::instantiate(float sampleRate, void*)
435 {
436 if(!_plugin)
437 return NULL;
438 bool success = false;
439 LADSPA_Handle h = _plugin->instantiate(_plugin, sampleRate);
440 success = (h != NULL);
441 if(success)
442 {
443 SP_DBG_LADSPA2("LadspaPlugin instantiated", label().toLatin1().constData());
444 }
445 return h;
446 }
447
448 //---------------------------------------------------------
449 // range
450 //---------------------------------------------------------
451
port_range(unsigned long i,float sampleRate,float * min,float * max) const452 bool LadspaPlugin::port_range(unsigned long i, float sampleRate, float* min, float* max) const
453 {
454 if(!_plugin)
455 return false;
456 LADSPA_PortRangeHint range = _plugin->PortRangeHints[i];
457 LADSPA_PortRangeHintDescriptor desc = range.HintDescriptor;
458 if (desc & LADSPA_HINT_TOGGLED) {
459 *min = 0.0;
460 *max = 1.0;
461 return true;
462 }
463 float m = 1.0;
464 if (desc & LADSPA_HINT_SAMPLE_RATE)
465 m = sampleRate;
466
467 if (desc & LADSPA_HINT_BOUNDED_BELOW)
468 *min = range.LowerBound * m;
469 else
470 *min = 0.0;
471 if (desc & LADSPA_HINT_BOUNDED_ABOVE)
472 *max = range.UpperBound * m;
473 else
474 *max = 1.0;
475 return true;
476 }
477
478 //---------------------------------------------------------
479 // range
480 //---------------------------------------------------------
481
range(unsigned long k,float sampleRate,float * min,float * max) const482 bool LadspaPlugin::range(unsigned long k, float sampleRate, float* min, float* max) const
483 {
484 SP_TRACE_IN
485 k = _pIdx[k];
486 SP_TRACE_OUT
487 return port_range(k, sampleRate, min, max);
488 }
489
490 //---------------------------------------------------------
491 // range
492 //---------------------------------------------------------
493
rangeOut(unsigned long k,float sampleRate,float * min,float * max) const494 bool LadspaPlugin::rangeOut(unsigned long k, float sampleRate, float* min, float* max) const
495 {
496 SP_TRACE_IN
497 k = _poIdx[k];
498 SP_TRACE_OUT
499 return port_range(k, sampleRate, min, max);
500 }
501
502 //---------------------------------------------------------
503 // defaultValue
504 //---------------------------------------------------------
505
defaultValue(unsigned long k) const506 float LadspaPlugin::defaultValue(unsigned long k) const
507 {
508 SP_TRACE_IN
509 if(!_plugin)
510 return 0.0f;
511 k = _pIdx[k];
512 LADSPA_PortRangeHint range = _plugin->PortRangeHints[k];
513 LADSPA_PortRangeHintDescriptor rh = range.HintDescriptor;
514 LADSPA_Data val = 1.0;
515 if (LADSPA_IS_HINT_DEFAULT_MINIMUM(rh))
516 val = range.LowerBound;
517 else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(rh))
518 val = range.UpperBound;
519 else if (LADSPA_IS_HINT_DEFAULT_LOW(rh))
520 if (LADSPA_IS_HINT_LOGARITHMIC(range.HintDescriptor))
521 val = exp(log(range.LowerBound) * .75 +
522 log(range.UpperBound) * .25);
523 else
524 val = range.LowerBound*.75 + range.UpperBound*.25;
525 else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(rh))
526 if (LADSPA_IS_HINT_LOGARITHMIC(range.HintDescriptor))
527 val = exp(log(range.LowerBound) * .5 +
528 log(range.UpperBound) * .5);
529 else
530 val = range.LowerBound*.5 + range.UpperBound*.5;
531 else if (LADSPA_IS_HINT_DEFAULT_HIGH(rh))
532 if (LADSPA_IS_HINT_LOGARITHMIC(range.HintDescriptor))
533 val = exp(log(range.LowerBound) * .25 +
534 log(range.UpperBound) * .75);
535 else
536 val = range.LowerBound*.25 + range.UpperBound*.75;
537 else if (LADSPA_IS_HINT_DEFAULT_0(rh))
538 val = 0.0;
539 else if (LADSPA_IS_HINT_DEFAULT_1(rh))
540 val = 1.0;
541 else if (LADSPA_IS_HINT_DEFAULT_100(rh))
542 val = 100.0;
543 else if (LADSPA_IS_HINT_DEFAULT_440(rh))
544 val = 440.0;
545 // No default found. Make one up...
546 else if (LADSPA_IS_HINT_BOUNDED_BELOW(rh) && LADSPA_IS_HINT_BOUNDED_ABOVE(rh))
547 {
548 if (LADSPA_IS_HINT_LOGARITHMIC(rh))
549 val = exp(log(range.LowerBound) * .5 +
550 log(range.UpperBound) * .5);
551 else
552 val = range.LowerBound*.5 + range.UpperBound*.5;
553 }
554 else if (LADSPA_IS_HINT_BOUNDED_BELOW(rh))
555 val = range.LowerBound;
556 else if (LADSPA_IS_HINT_BOUNDED_ABOVE(rh))
557 {
558 // Hm. What to do here... Just try 0.0 or the upper bound if less than zero.
559 //if(range.UpperBound > 0.0)
560 // val = 0.0;
561 //else
562 // val = range.UpperBound;
563 // Instead try this: Adopt an 'attenuator-like' policy, where upper is the default.
564 val = range.UpperBound;
565 return true;
566 }
567
568 SP_TRACE_OUT
569 return val;
570 }
571
572 //---------------------------------------------------------
573 // connectInport
574 //---------------------------------------------------------
connectInport(void * handle,unsigned long k,void * datalocation)575 void LadspaPlugin::connectInport(void* handle, unsigned long k, void* datalocation)
576 {
577 SP_TRACE_IN
578 if(!_plugin)
579 return;
580 _plugin->connect_port((LADSPA_Handle)handle, _iIdx[k], (LADSPA_Data*)datalocation);
581 SP_TRACE_OUT
582 }
583
584 //---------------------------------------------------------
585 // connectOutport
586 //---------------------------------------------------------
connectOutport(void * handle,unsigned long k,void * datalocation)587 void LadspaPlugin::connectOutport(void* handle, unsigned long k, void* datalocation)
588 {
589 SP_TRACE_IN
590 if(!_plugin)
591 return;
592 _plugin->connect_port((LADSPA_Handle)handle, _oIdx[k], (LADSPA_Data*)datalocation);
593 SP_TRACE_OUT
594 }
595
596 //---------------------------------------------------------
597 // connectCtrlInport
598 //---------------------------------------------------------
connectCtrlInport(void * handle,unsigned long k,void * datalocation)599 void LadspaPlugin::connectCtrlInport(void* handle, unsigned long k, void* datalocation)
600 {
601 SP_TRACE_IN
602 if(!_plugin)
603 return;
604 _plugin->connect_port((LADSPA_Handle)handle, _pIdx[k], (LADSPA_Data*)datalocation);
605 SP_TRACE_OUT
606 }
607
608 //---------------------------------------------------------
609 // connectCtrlOutport
610 //---------------------------------------------------------
connectCtrlOutport(void * handle,unsigned long k,void * datalocation)611 void LadspaPlugin::connectCtrlOutport(void* handle, unsigned long k, void* datalocation)
612 {
613 SP_TRACE_IN
614 if(!_plugin)
615 return;
616 _plugin->connect_port((LADSPA_Handle)handle, _poIdx[k], (LADSPA_Data*)datalocation);
617 SP_TRACE_OUT
618 }
619
620 //---------------------------------------------------------
621 // convertGuiControlValue
622 // scale control value to gui-slider/checkbox representation
623 //---------------------------------------------------------
624
convertGuiControlValue(unsigned long k,float sampleRate,int val) const625 float LadspaPlugin::convertGuiControlValue(unsigned long k, float sampleRate, int val) const
626 {
627 SP_TRACE_IN
628 float floatval = 0.0;
629 float min, max;
630 if(!range(k, sampleRate, &min, &max))
631 return floatval;
632
633 if (isLog(k)) {
634 if (val > 0) {
635 float logged = SS_map_pluginparam2logdomain(val);
636 float e = expf(logged) * (max - min);
637 e+=min;
638 floatval = e;
639 }
640 }
641 else if (isBool(k)) {
642 floatval = (float) val;
643 }
644 else if (isInt(k)) {
645 float scale = (max - min) / SS_PLUGIN_PARAM_MAX;
646 floatval = (float) round((((float) val) * scale) + min);
647 }
648 else {
649 float scale = (max - min) / SS_PLUGIN_PARAM_MAX;
650 floatval = (((float) val) * scale) + min;
651 }
652 SP_TRACE_OUT
653 return floatval;
654 }
655
656
657 //---------------------------------------------------------
658 // PluginI
659 //---------------------------------------------------------
660
init()661 void PluginI::init()
662 {
663 _plugin = 0;
664 _sampleRate = 44100.0f;
665 _dSampleRate = _sampleRate;
666 _segmentSize = 0;
667 _instances = 0;
668 _controls = 0;
669 _controlsOut = 0;
670 _controlsOutDummy = 0;
671 _audioInPorts = 0;
672 _audioOutPorts = 0;
673 _controlPorts = 0;
674 _controlOutPorts = 0;
675 _audioInSilenceBuf = 0;
676 _audioOutDummyBuf = 0;
677 _hasLatencyOutPort = false;
678 _latencyOutPort = 0;
679 _on = true;
680 }
681
PluginI()682 PluginI::PluginI()
683 {
684 _id = -1;
685 init();
686 }
687
688 //---------------------------------------------------------
689 // PluginI
690 //---------------------------------------------------------
691
~PluginI()692 PluginI::~PluginI()
693 {
694 if(_audioInSilenceBuf)
695 free(_audioInSilenceBuf);
696 if(_audioOutDummyBuf)
697 free(_audioOutDummyBuf);
698
699 if(_controlsOutDummy)
700 delete[] _controlsOutDummy;
701 if(_controlsOut)
702 delete[] _controlsOut;
703 if(_controls)
704 delete[] _controls;
705 }
706
707 //---------------------------------------------------------
708 // setID
709 //---------------------------------------------------------
710
setID(int i)711 void PluginI::setID(int i)
712 {
713 _id = i;
714 }
715
716 //---------------------------------------------------------
717 // getGuiControlValue
718 // scale control value to gui-slider/checkbox representation
719 //---------------------------------------------------------
720
getGuiControlValue(unsigned long parameter) const721 int PluginI::getGuiControlValue(unsigned long parameter) const
722 {
723 SP_TRACE_IN
724 float val = param(parameter);
725 float min, max;
726 range(parameter, &min, &max);
727 int intval;
728 if (isLog(parameter)) {
729 intval = SS_map_logdomain2pluginparam(logf(val/(max - min) + min));
730 }
731 else if (isBool(parameter)) {
732 intval = (int) val;
733 }
734 else {
735 float scale = SS_PLUGIN_PARAM_MAX / (max - min);
736 intval = (int) ((val - min) * scale);
737 }
738 SP_TRACE_OUT
739 return intval;
740 }
741
742 //---------------------------------------------------------
743 // convertGuiControlValue
744 // scale control value to gui-slider/checkbox representation
745 //---------------------------------------------------------
746
convertGuiControlValue(unsigned long parameter,int val) const747 float PluginI::convertGuiControlValue(unsigned long parameter, int val) const
748 {
749 SP_TRACE_IN
750 float floatval = 0;
751 float min, max;
752 range(parameter, &min, &max);
753
754 if (isLog(parameter)) {
755 if (val > 0) {
756 float logged = SS_map_pluginparam2logdomain(val);
757 float e = expf(logged) * (max - min);
758 e+=min;
759 floatval = e;
760 }
761 }
762 else if (isBool(parameter)) {
763 floatval = (float) val;
764 }
765 else if (isInt(parameter)) {
766 float scale = (max - min) / SS_PLUGIN_PARAM_MAX;
767 floatval = (float) round((((float) val) * scale) + min);
768 }
769 else {
770 float scale = (max - min) / SS_PLUGIN_PARAM_MAX;
771 floatval = (((float) val) * scale) + min;
772 }
773 SP_TRACE_OUT
774 return floatval;
775 }
776
777 //---------------------------------------------------------
778 // apply
779 // If ports is 0, just process controllers only, not audio (do not 'run').
780 //---------------------------------------------------------
781
apply(unsigned,unsigned long frames,unsigned long ports,float ** bufIn,float ** bufOut)782 void PluginI::apply(unsigned /*pos*/, unsigned long frames, unsigned long ports, float** bufIn, float** bufOut)
783 {
784
785 #ifdef PLUGIN_DEBUGIN_PROCESS
786 fprintf(stderr, "PluginI::apply nsamp:%lu\n", n);
787 #endif
788
789 if(!_plugin)
790 return;
791
792 if(ports > 0) // Don't bother if not 'running'.
793 {
794 connect(ports, 0, bufIn, bufOut);
795 process(frames);
796 }
797 }
798
799 //---------------------------------------------------------
800 // start
801 // activate and connect control ports
802 //---------------------------------------------------------
803
start()804 bool PluginI::start()
805 {
806 if(!_plugin)
807 return false;
808 // Activate all the instances.
809 return activate();
810 }
811
812 //---------------------------------------------------------
813 // stop
814 // deactivate
815 //---------------------------------------------------------
stop()816 bool PluginI::stop()
817 {
818 if(!_plugin)
819 return false;
820 // Activate all the instances.
821 return deactivate();
822 }
823
824 //---------------------------------------------------------
825 // setParam
826 //---------------------------------------------------------
827
setParam(unsigned long i,float val)828 void PluginI::setParam(unsigned long i, float val)
829 {
830 if(i >= _controlPorts)
831 return;
832 _controls[i]._val = val;
833 }
834
835 // TODO
836 // //---------------------------------------------------------
837 // // connect
838 // //---------------------------------------------------------
839 //
840 // void PluginI::connectInport(unsigned long k, void* datalocation)
841 // {
842 // if(!_plugin) return;
843 // // const unsigned long ins = _plugin->inports();
844 // // const unsigned long handle_idx = (k / ins) % instances;
845 // // const unsigned long port_idx = k % ins;
846 // // _plugin->connectInport(handle[handle_idx], port_idx, datalocation);
847 //
848 // const unsigned long ins = _plugin->inports();
849 // for (int i = 0; i < instances; ++i) {
850 // for (unsigned long k = 0; k < audio; ++k) {
851 // }
852 //
853 // const unsigned long port_count = _plugin->portCount();
854 // unsigned long port = 0;
855 // for (int i = 0; i < instances; ++i) {
856 // for (unsigned long k = 0; k < port_count; ++k) {
857 // if (_plugin->isAudioIn(k)) {
858 // //if(port < ports)
859 // if(port < channel)
860 // //_plugin->connectPort(handle[i], k, src[port] + offset);
861 // _plugin->connectInport(handle[i], k, datalocation);
862 // else
863 // // Connect to an input silence buffer.
864 // _plugin->connectInport(handle[i], k, _audioInSilenceBuf);
865 // ++port;
866 // }
867 // }
868 // }
869 // }
870 //
871 // void PluginI::connectOutport(unsigned long k, void* datalocation)
872 // {
873 // if(!_plugin) return;
874 // // const unsigned long outs = _plugin->outports();
875 // // const unsigned long handle_idx = (k / outs) % instances;
876 // // const unsigned long port_idx = k % outs;
877 // // _plugin->connectOutport(handle[handle_idx], port_idx, datalocation);
878 //
879 // const unsigned long port_count = _plugin->portCount();
880 // unsigned long port = 0;
881 // for (int i = 0; i < instances; ++i) {
882 // for (unsigned long k = 0; k < port_count; ++k) {
883 // if (_plugin->isAudioOut(k)) {
884 // //if(port < ports)
885 // if(port < channel)
886 // _plugin->connectOutport(handle[i], k, datalocation);
887 // else
888 // // Connect to a dummy buffer.
889 // _plugin->connectOutport(handle[i], k, _audioOutDummyBuf);
890 // ++port;
891 // }
892 // }
893 // }
894 // }
895 //
896 // void PluginI::connectCtrlInport(unsigned long k, void* datalocation)
897 // {
898 // if(!_plugin) return;
899 // const unsigned long ctrl_ins = _plugin->parameter();
900 // const unsigned long handle_idx = (k / ctrl_ins) % instances;
901 // const unsigned long port_idx = k % ctrl_ins;
902 // _plugin->connectCtrlInport(handle[handle_idx], port_idx, datalocation);
903 // }
904 //
905 // void PluginI::connectCtrlOutport(unsigned long k, void* datalocation)
906 // {
907 // if(!_plugin) return;
908 // const unsigned long ctrl_outs = _plugin->parameterOut();
909 // const unsigned long handle_idx = (k / ctrl_outs) % instances;
910 // const unsigned long port_idx = k % ctrl_outs;
911 // _plugin->connectCtrlOutport(handle[handle_idx], port_idx, datalocation);
912 // }
913
914 //---------------------------------------------------------
915 // latency
916 //---------------------------------------------------------
917
latency() const918 float PluginI::latency() const
919 {
920 if(!_hasLatencyOutPort)
921 return 0.0;
922 return _controlsOut[_latencyOutPort]._val;
923 }
924
925
926 //---------------------------------------------------------
927 // setControl
928 // set plugin instance controller value by name
929 //---------------------------------------------------------
930
setControl(const QString & s,float val)931 bool PluginI::setControl(const QString& s, float val)
932 {
933 if(!_plugin)
934 return true;
935 for (unsigned long i = 0; i < _controlPorts; ++i) {
936 if (QString(_plugin->getParameterName(i)) == s) {
937 setParam(i, val);
938 return false;
939 }
940 }
941 fprintf(stderr, "PluginI:setControl(%s, %f) controller not found\n",
942 s.toLatin1().constData(), val);
943 return true;
944 }
945
946
947
948 //---------------------------------------------------------
949 // LadspaPluginI
950 //---------------------------------------------------------
951
init()952 void LadspaPluginI::init()
953 {
954 _handle = 0;
955 }
956
LadspaPluginI()957 LadspaPluginI::LadspaPluginI()
958 : PluginI()
959 {
960 init();
961 }
962
963 //---------------------------------------------------------
964 // LadspaPluginI
965 //---------------------------------------------------------
966
~LadspaPluginI()967 LadspaPluginI::~LadspaPluginI()
968 {
969 if(_plugin) {
970 // Deactivate is pure virtual, it cannot be
971 // called from the base destructor. Do it here.
972 deactivate();
973 _plugin->incReferences(-1);
974 }
975
976 if(_handle)
977 delete[] _handle;
978 }
979
980 //---------------------------------------------------------
981 // initPluginInstance
982 // return true on error
983 //---------------------------------------------------------
984
initPluginInstance(Plugin * plug,int chans,float sampleRate,unsigned int segmentSize,bool useDenormalBias,float denormalBias)985 bool LadspaPluginI::initPluginInstance(Plugin* plug, int chans,
986 float sampleRate, unsigned int segmentSize,
987 bool useDenormalBias, float denormalBias)
988 {
989 _sampleRate = _dSampleRate = sampleRate;
990 _segmentSize = segmentSize;
991 _channel = chans;
992 if(plug == 0)
993 {
994 fprintf(stderr, "LadspaPluginI::initPluginInstance: zero plugin\n");
995 return true;
996 }
997 _plugin = plug;
998
999 if (_plugin->incReferences(1)==0)
1000 return true;
1001
1002 QString inst("-" + QString::number(_plugin->instNo()));
1003 _name = _plugin->name() + inst;
1004 _label = _plugin->label() + inst;
1005
1006 const unsigned long ins = _plugin->inports();
1007 const unsigned long outs = _plugin->outports();
1008 if(outs)
1009 {
1010 _instances = _channel / outs;
1011 // Ask for one more instance for remainder if required.
1012 const int re = _channel % outs;
1013 if(re != 0)
1014 ++_instances;
1015 if(_instances < 1)
1016 _instances = 1;
1017 }
1018 else
1019 if(ins)
1020 {
1021 _instances = _channel / ins;
1022 // Ask for one more instance for remainder if required.
1023 const int re = _channel % ins;
1024 if(re != 0)
1025 ++_instances;
1026 if(_instances < 1)
1027 _instances = 1;
1028 }
1029 else
1030 _instances = 1;
1031
1032 _handle = new LADSPA_Handle[_instances];
1033 for(int i = 0; i < _instances; ++i)
1034 _handle[i]=NULL;
1035
1036 for(int i = 0; i < _instances; ++i)
1037 {
1038 #ifdef PLUGIN_DEBUGIN
1039 fprintf(stderr, "LadspaPluginI::initPluginInstance instance:%d\n", i);
1040 #endif
1041
1042 _handle[i] = _plugin->instantiate(_sampleRate, NULL);
1043 if(_handle[i] == NULL)
1044 return true;
1045 }
1046
1047 const unsigned long port_count = _plugin->portCount();
1048
1049 _audioInPorts = 0;
1050 _audioOutPorts = 0;
1051 _controlPorts = 0;
1052 _controlOutPorts = 0;
1053
1054 unsigned long port = 0;
1055 for (int i = 0; i < _instances; ++i) {
1056 for (unsigned long k = 0; k < port_count; ++k) {
1057 if (_plugin->isAudioIn(k)) {
1058 if(port < (unsigned long)_channel)
1059 ++_audioInPorts;
1060 ++port;
1061 }
1062 }
1063 }
1064 port = 0;
1065 for (int i = 0; i < _instances; ++i) {
1066 for (unsigned long k = 0; k < port_count; ++k) {
1067 if (_plugin->isAudioOut(k)) {
1068 if(port < (unsigned long)_channel)
1069 ++_audioOutPorts;
1070 ++port;
1071 }
1072 }
1073 }
1074
1075 for(unsigned long k = 0; k < port_count; ++k)
1076 {
1077 if(_plugin->isParameterIn(k))
1078 ++_controlPorts;
1079 else
1080 if(_plugin->isParameterOut(k))
1081 ++_controlOutPorts;
1082 }
1083
1084 if(_controlPorts)
1085 _controls = new Port[_controlPorts];
1086 if(_controlOutPorts)
1087 {
1088 _controlsOut = new Port[_controlOutPorts];
1089 _controlsOutDummy = new Port[_controlOutPorts];
1090 }
1091
1092 for(unsigned long k = 0; k < _controlPorts; ++k)
1093 {
1094 // Set the parameter input's initial value to the default.
1095 const float val = _plugin->defaultValue(k);
1096 _controls[k]._val = val;
1097 // All instances' parameter inputs share the same controls.
1098 // We don't have a mechanism to expose the other instances' inputs.
1099 for(int i = 0; i < _instances; ++i)
1100 _plugin->connectCtrlInport(_handle[i], k, &_controls[k]._val);
1101 }
1102
1103 for(unsigned long k = 0; k < _controlOutPorts; ++k)
1104 {
1105 // Set the parameter output's initial value to zero.
1106 _controlsOut[k]._val = 0.0f;
1107 // Check for a latency port.
1108 const char* pname = _plugin->getParameterOutName(k);
1109 if(pname == QString("latency") || pname == QString("_latency"))
1110 {
1111 _hasLatencyOutPort = true;
1112 _latencyOutPort = k;
1113 }
1114 // Connect only the first instance's parameter output controls.
1115 // We don't have a mechanism to display the other instances' outputs.
1116 if(_instances > 0)
1117 {
1118 _plugin->connectCtrlOutport(_handle[0], k, &_controlsOut[k]._val);
1119 // Connect the rest to dummy ports.
1120 for(int i = 1; i < _instances; ++i)
1121 _plugin->connectCtrlOutport(_handle[i], k, &_controlsOutDummy[k]._val);
1122 }
1123 }
1124
1125 #ifdef _WIN32
1126 _audioInSilenceBuf = (float *) _aligned_malloc(16, sizeof(float) * _segmentSize);
1127 if(_audioInSilenceBuf == NULL)
1128 {
1129 fprintf(stderr,
1130 "ERROR: LadspaPluginI::initPluginInstance: _audioInSilenceBuf _aligned_malloc returned error: NULL. Aborting!\n");
1131 abort();
1132 }
1133 #else
1134 int rv = posix_memalign((void **)&_audioInSilenceBuf, 16, sizeof(float) * _segmentSize);
1135 if(rv != 0)
1136 {
1137 fprintf(stderr,
1138 "ERROR: LadspaPluginI::initPluginInstance: _audioInSilenceBuf posix_memalign returned error:%d. Aborting!\n", rv);
1139 abort();
1140 }
1141 #endif
1142
1143 if(useDenormalBias)
1144 {
1145 for(unsigned q = 0; q < _segmentSize; ++q)
1146 {
1147 _audioInSilenceBuf[q] = denormalBias;
1148 }
1149 }
1150 else
1151 {
1152 memset(_audioInSilenceBuf, 0, sizeof(float) * _segmentSize);
1153 }
1154
1155 #ifdef _WIN32
1156 _audioOutDummyBuf = (float *) _aligned_malloc(16, sizeof(float) * _segmentSize);
1157 if(_audioOutDummyBuf == NULL)
1158 {
1159 fprintf(stderr,
1160 "ERROR: LadspaPluginI::initPluginInstance: _audioInSilenceBuf _aligned_malloc returned error: NULL. Aborting!\n");
1161 abort();
1162 }
1163 #else
1164 rv = posix_memalign((void **)&_audioOutDummyBuf, 16, sizeof(float) * _segmentSize);
1165 if(rv != 0)
1166 {
1167 fprintf(stderr, "ERROR: LadspaPluginI::initPluginInstance: _audioOutDummyBuf posix_memalign returned error:%d. Aborting!\n", rv);
1168 abort();
1169 }
1170 #endif
1171
1172 // Don't activate yet.
1173 //activate();
1174 return false;
1175 }
1176
1177 //---------------------------------------------------------
1178 // setChannels
1179 //---------------------------------------------------------
1180
setChannels(int chans)1181 void LadspaPluginI::setChannels(int chans)
1182 {
1183 _channel = chans;
1184
1185 if(!_plugin)
1186 return;
1187
1188 const unsigned long ins = _plugin->inports();
1189 const unsigned long outs = _plugin->outports();
1190 int ni = 1;
1191 if(outs)
1192 {
1193 ni = chans / outs;
1194 // Ask for one more instance for remainder if required.
1195 const int re = chans % outs;
1196 if(re != 0)
1197 ++ni;
1198 }
1199 else
1200 if(ins)
1201 {
1202 ni = chans / ins;
1203 // Ask for one more instance for remainder if required.
1204 const int re = chans % ins;
1205 if(re != 0)
1206 ++ni;
1207 }
1208
1209 if(ni < 1)
1210 ni = 1;
1211
1212 if (ni == _instances)
1213 return;
1214
1215 LADSPA_Handle* handles = new LADSPA_Handle[ni];
1216
1217 if(ni > _instances)
1218 {
1219 for(int i = 0; i < ni; ++i)
1220 {
1221 if(i < _instances)
1222 // Transfer existing handle from old array to new array.
1223 handles[i] = _handle[i];
1224 else
1225 {
1226 // Create a new plugin instance with handle.
1227 // Use the plugin's current sample rate.
1228 handles[i] = _plugin->instantiate(_sampleRate, NULL);
1229 if(handles[i] == NULL)
1230 {
1231 fprintf(stderr, "LadspaPluginI::setChannels: cannot instantiate instance %d\n", i);
1232
1233 // Although this is a messed up state not easy to get out of (final # of channels?), try not to assert().
1234 // Whoever uses these will have to check instance count or null handle, and try to gracefully fix it and allow a song save.
1235 for(int k = i; k < ni; ++k)
1236 handles[i] = NULL;
1237 ni = i + 1;
1238 //channel = ?;
1239 break;
1240 }
1241 }
1242 }
1243 }
1244 else
1245 {
1246 for(int i = 0; i < _instances; ++i)
1247 {
1248 if(i < ni)
1249 // Transfer existing handle from old array to new array.
1250 handles[i] = _handle[i];
1251 else
1252 {
1253 // Delete existing plugin instance.
1254 // Previously we deleted all the instances and rebuilt from scratch.
1255 // One side effect of this: Since a GUI is constructed only on the first handle,
1256 // previously the native GUI would close when changing channels. Now it doesn't, which is good.
1257 _plugin->deactivate(_handle[i]);
1258 _plugin->cleanup(_handle[i]);
1259 }
1260 }
1261 }
1262
1263 // Delete the old array, and set the new array.
1264 delete[] _handle;
1265 _handle = handles;
1266
1267 // Connect new instances' ports:
1268 for(unsigned long k = 0; k < _controlPorts; ++k)
1269 {
1270 for(int i = _instances; i < ni; ++i)
1271 {
1272 // All instances' parameter inputs share the same controls.
1273 // We don't have a mechanism to expose the other instances' inputs.
1274 _plugin->connectCtrlInport(handles[i], k, &_controls[k]._val);
1275 }
1276 }
1277
1278 for(unsigned long k = 0; k < _controlOutPorts; ++k)
1279 {
1280 // Connect only the first instance's parameter output controls.
1281 // We don't have a mechanism to display the other instances' outputs.
1282 if(_instances == 0 && ni > 0)
1283 // Only if the existing instances was zero. We are creating one(s) now.
1284 _plugin->connectCtrlOutport(_handle[0], k, &_controlsOut[k]._val);
1285 else
1286 {
1287 // Connect the rest to dummy ports.
1288 for(int i = _instances; i < ni; ++i)
1289 _plugin->connectCtrlOutport(_handle[i], k, &_controlsOutDummy[k]._val);
1290 }
1291 }
1292
1293 // Activate new instances.
1294 for(int i = _instances; i < ni; ++i)
1295 _plugin->activate(_handle[i]);
1296
1297 // Finally, set the new number of instances.
1298 _instances = ni;
1299 }
1300
1301 //---------------------------------------------------------
1302 // connect
1303 //---------------------------------------------------------
1304
connect(unsigned long ports,unsigned long offset,float ** src,float ** dst)1305 void LadspaPluginI::connect(unsigned long ports, unsigned long offset, float** src, float** dst)
1306 {
1307 if(!_plugin) return;
1308
1309 const unsigned long port_count = _plugin->portCount();
1310 unsigned long port = 0;
1311 for (int i = 0; i < _instances; ++i) {
1312 for (unsigned long k = 0; k < port_count; ++k) {
1313 if (isAudioIn(k)) {
1314 if(port < ports)
1315 _plugin->connectPort(_handle[i], k, src[port] + offset);
1316 else
1317 // Connect to an input silence buffer.
1318 _plugin->connectPort(_handle[i], k, _audioInSilenceBuf + offset);
1319 ++port;
1320 }
1321 }
1322 }
1323 port = 0;
1324 for (int i = 0; i < _instances; ++i) {
1325 for (unsigned long k = 0; k < port_count; ++k) {
1326 if (isAudioOut(k)) {
1327 if(port < ports)
1328 _plugin->connectPort(_handle[i], k, dst[port] + offset);
1329 else
1330 // Connect to a dummy buffer.
1331 _plugin->connectPort(_handle[i], k, _audioOutDummyBuf + offset);
1332 ++port;
1333 }
1334 }
1335 }
1336 }
1337
1338
1339 //---------------------------------------------------------
1340 // deactivate
1341 //---------------------------------------------------------
1342
deactivate()1343 bool LadspaPluginI::deactivate()
1344 {
1345 if(!_plugin)
1346 return false;
1347 for (int i = 0; i < _instances; ++i) {
1348 _plugin->deactivate(_handle[i]);
1349 _plugin->cleanup(_handle[i]);
1350 }
1351 return true;
1352 }
1353
1354 //---------------------------------------------------------
1355 // activate
1356 //---------------------------------------------------------
1357
activate()1358 bool LadspaPluginI::activate()
1359 {
1360 if(!_plugin)
1361 return false;
1362 for (int i = 0; i < _instances; ++i)
1363 _plugin->activate(_handle[i]);
1364 return true;
1365 }
1366
process(unsigned long frames)1367 void LadspaPluginI::process(unsigned long frames)
1368 {
1369 if(!_plugin)
1370 return;
1371 for(int i = 0; i < _instances; ++i)
1372 _plugin->apply(_handle[i], frames);
1373 }
1374
1375 } // namespace MusESimplePlugin
1376