1 //=============================================================================
2 // MusE
3 // Linux Music Editor
4 // $Id: dssihost.cpp,v 1.15.2.16 2009/12/15 03:39:58 terminator356 Exp $
5 //
6 // Copyright (C) 1999-2011 by Werner Schweer and others
7 // (C) Copyright 2011-2016 Tim E. Real (terminator356 on sourceforge)
8 //
9 // This program is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; version 2 of
12 // the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //=============================================================================
23
24 #include "config.h"
25 #ifdef DSSI_SUPPORT
26
27 // Turn on debugging messages
28 //#define DSSI_DEBUG
29 // Turn on constant flow of process debugging messages
30 //#define DSSI_DEBUG_PROCESS
31
32 // Support vst state saving/loading with vst chunks.
33 //#define DSSI_VST_CHUNK_SUPPORT
34
35 #include <string>
36 #include <string.h>
37 #include <signal.h>
38 #include <dlfcn.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <sys/stat.h>
42
43 #include <QDir>
44 #include <QFileInfo>
45
46 #include "dssihost.h"
47 #include "synth.h"
48 #include "audio.h"
49 #include "jackaudio.h"
50 #include "midi_consts.h"
51 #include "midiport.h"
52 #include "minstrument.h"
53 #include "stringparam.h"
54 #include "plugin.h"
55 #include "controlfifo.h"
56 #include "xml.h"
57 #include "song.h"
58 #include "ctrl.h"
59
60 #include "app.h"
61 #include "globals.h"
62 #include "gconfig.h"
63 #include "popupmenu.h"
64 #include "lock_free_buffer.h"
65 #include "pluglist.h"
66
67 namespace MusECore {
68
69 //---------------------------------------------------------
70 // initDSSI
71 //---------------------------------------------------------
72
initDSSI()73 void initDSSI()
74 {
75 const MusEPlugin::PluginScanList& scan_list = MusEPlugin::pluginList;
76 for(MusEPlugin::ciPluginScanList isl = scan_list.begin(); isl != scan_list.end(); ++isl)
77 {
78 const MusEPlugin::PluginScanInfoRef inforef = *isl;
79 const MusEPlugin::PluginScanInfoStruct& info = inforef->info();
80 switch(info._type)
81 {
82 case MusEPlugin::PluginScanInfoStruct::PluginTypeDSSI:
83 case MusEPlugin::PluginScanInfoStruct::PluginTypeDSSIVST:
84 {
85 #ifdef DSSI_SUPPORT
86 if(MusEGlobal::loadDSSI)
87 {
88 // * Done in plugin.cpp already. *
89 //if(info._class & PluginScanInfo::PluginClassEffect)
90 //{
91 // // Make sure it doesn't already exist.
92 // if(const Plugin* pl = MusEGlobal::plugins.find(info._fi.completeBaseName(), info._label))
93 // {
94 // fprintf(stderr, "Ignoring DSSI effect label:%s path:%s duplicate of path:%s\n",
95 // info._label.toLatin1().constData(),
96 // info._fi.filePath().toLatin1().constData(),
97 // pl->filePath().toLatin1().constData());
98 //
99 // }
100 // else
101 // {
102 // if(MusEGlobal::debugMsg)
103 // info.dump(message);
104 // MusEGlobal::plugins.add(info);
105 // }
106 //}
107
108 // For now we allow effects as a synth track. Until we allow programs (and midi) in the effect rack.
109 if(info._class & MusEPlugin::PluginScanInfoStruct::PluginClassEffect ||
110 info._class & MusEPlugin::PluginScanInfoStruct::PluginClassInstrument)
111 {
112 // Make sure it doesn't already exist.
113 if(const Synth* sy = MusEGlobal::synthis.find(
114 PLUGIN_GET_QSTRING(info._completeBaseName),
115 PLUGIN_GET_QSTRING(info._uri),
116 PLUGIN_GET_QSTRING(info._label)))
117 {
118 fprintf(stderr, "Ignoring DSSI synth label:%s uri:%s path:%s duplicate of path:%s\n",
119 PLUGIN_GET_CSTRING(info._label),
120 PLUGIN_GET_CSTRING(info._uri),
121 PLUGIN_GET_CSTRING(info.filePath()),
122 sy->filePath().toLatin1().constData());
123 }
124 else
125 {
126 DssiSynth* s = new DssiSynth(info);
127 MusEGlobal::synthis.push_back(s);
128 }
129 }
130 }
131 #endif
132 }
133 break;
134
135 case MusEPlugin::PluginScanInfoStruct::PluginTypeLADSPA:
136 case MusEPlugin::PluginScanInfoStruct::PluginTypeVST:
137 case MusEPlugin::PluginScanInfoStruct::PluginTypeLV2:
138 case MusEPlugin::PluginScanInfoStruct::PluginTypeLinuxVST:
139 case MusEPlugin::PluginScanInfoStruct::PluginTypeMESS:
140 case MusEPlugin::PluginScanInfoStruct::PluginTypeUnknown:
141 case MusEPlugin::PluginScanInfoStruct::PluginTypeNone:
142 case MusEPlugin::PluginScanInfoStruct::PluginTypeAll:
143 break;
144 }
145 }
146 }
147
148 //---------------------------------------------------------
149 // DssiSynth
150 // Synth.name = plug.Label (In LADSPA and DSSI this is the more important unique string)
151 // Synth.descr = plug.Name (In LADSPA and DSSI this is the less important name string)
152 // Synth.maker = plug.maker
153 // Synth.version = nil (no such field in ladspa, maybe try copyright instead)
154 //---------------------------------------------------------
155
DssiSynth(QFileInfo & fi,const QString & uri,const DSSI_Descriptor * d,bool isDssiVst,PluginFeatures_t reqFeatures)156 DssiSynth::DssiSynth(QFileInfo& fi, const QString& uri, const DSSI_Descriptor* d,
157 bool isDssiVst, PluginFeatures_t reqFeatures) : // ddskrjo removed const from QFileInfo
158 Synth(fi, uri, QString(d->LADSPA_Plugin->Label), QString(d->LADSPA_Plugin->Name),
159 QString(d->LADSPA_Plugin->Maker), QString(), reqFeatures)
160 {
161 df = 0;
162 handle = 0;
163 dssi = 0;
164 _isDssiVst = isDssiVst;
165 _hasGui = false;
166
167 const LADSPA_Descriptor* descr = d->LADSPA_Plugin;
168
169 _portCount = descr->PortCount;
170
171 _inports = 0;
172 _outports = 0;
173 _controlInPorts = 0;
174 _controlOutPorts = 0;
175 for(unsigned long k = 0; k < _portCount; ++k)
176 {
177 LADSPA_PortDescriptor pd = descr->PortDescriptors[k];
178 if(pd & LADSPA_PORT_AUDIO)
179 {
180 if(pd & LADSPA_PORT_INPUT)
181 ++_inports;
182 else
183 if(pd & LADSPA_PORT_OUTPUT)
184 ++_outports;
185 }
186 else
187 if(pd & LADSPA_PORT_CONTROL)
188 {
189 if(pd & LADSPA_PORT_INPUT)
190 ++_controlInPorts;
191 else
192 if(pd & LADSPA_PORT_OUTPUT)
193 ++_controlOutPorts;
194 }
195 }
196
197 // Hack: Blacklist vst plugins in-place, configurable for now.
198 if ((_inports != _outports) || (_isDssiVst && !MusEGlobal::config.vstInPlace))
199 _requiredFeatures |= PluginNoInPlaceProcessing;
200 }
201
202 //---------------------------------------------------------
203 // DssiSynth
204 // Synth.name = plug.Label (In LADSPA and DSSI this is the more important unique string)
205 // Synth.descr = plug.Name (In LADSPA and DSSI this is the less important name string)
206 // Synth.maker = plug.maker
207 // Synth.version = nil (no such field in ladspa, maybe try copyright instead)
208 //---------------------------------------------------------
209
DssiSynth(const MusEPlugin::PluginScanInfoStruct & info)210 DssiSynth::DssiSynth(const MusEPlugin::PluginScanInfoStruct& info)
211 : Synth(PLUGIN_GET_QSTRING(info.filePath()),
212 PLUGIN_GET_QSTRING(info._uri),
213 PLUGIN_GET_QSTRING(info._label),
214 PLUGIN_GET_QSTRING(info._name),
215 PLUGIN_GET_QSTRING(info._maker),
216 QString(),
217 info._requiredFeatures)
218 {
219 df = 0;
220 handle = 0;
221 dssi = 0;
222 _isDssiVst = info._type == MusEPlugin::PluginScanInfoStruct::PluginTypeDSSIVST;
223
224 // _hasGui = false;
225 _hasGui = info._pluginFlags & MusEPlugin::PluginScanInfoStruct::HasGui;
226
227 _portCount = info._portCount;
228
229 _inports = info._inports;
230 _outports = info._outports;
231 _controlInPorts = info._controlInPorts;
232 _controlOutPorts = info._controlOutPorts;
233
234 // Hack: Blacklist vst plugins in-place, configurable for now.
235 if(_isDssiVst && !MusEGlobal::config.vstInPlace)
236 _requiredFeatures |= PluginNoInPlaceProcessing;
237 }
238
~DssiSynth()239 DssiSynth::~DssiSynth()
240 {
241 if(dssi)
242 // delete dssi;
243 printf("DssiSynth::~DssiSynth Error: dssi descriptor is not NULL\n");
244 }
245
246 //---------------------------------------------------------
247 // createSIF
248 //---------------------------------------------------------
249
createSIF(SynthI * synti)250 SynthIF* DssiSynth::createSIF(SynthI* synti)
251 {
252 if (_instances == 0)
253 {
254 handle = dlopen(info.filePath().toLatin1().constData(), RTLD_NOW);
255 if (handle == 0)
256 {
257 fprintf(stderr, "DssiSynth::createSIF dlopen(%s) failed: %s\n",
258 info.filePath().toLatin1().constData(), dlerror());
259 return 0;
260 }
261 df = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor");
262
263 if (!df) {
264 const char *txt = dlerror();
265 fprintf(stderr,
266 "Unable to find dssi_descriptor() function in plugin "
267 "library file \"%s\": %s.\n"
268 "Are you sure this is a DSSI plugin file?\n",
269 info.filePath().toLatin1().constData(),
270 txt ? txt : "?");
271 dlclose(handle);
272 handle = 0;
273 return 0;
274 }
275 for (int i = 0;; ++i)
276 {
277 dssi = df(i);
278 if (dssi == 0)
279 break;
280 QString label(dssi->LADSPA_Plugin->Label);
281 if (label == _name)
282 break;
283 }
284
285 if(dssi != 0)
286 {
287 _inports = 0;
288 _outports = 0;
289 _controlInPorts = 0;
290 _controlOutPorts = 0;
291 iIdx.clear();
292 oIdx.clear();
293 rpIdx.clear();
294 midiCtl2PortMap.clear();
295 port2MidiCtlMap.clear();
296
297 const LADSPA_Descriptor* descr = dssi->LADSPA_Plugin;
298
299 _portCount = descr->PortCount;
300
301 for (unsigned long k = 0; k < _portCount; ++k)
302 {
303 LADSPA_PortDescriptor pd = descr->PortDescriptors[k];
304
305 #ifdef DSSI_DEBUG
306 printf("DssiSynth::createSIF ladspa plugin Port:%lu Name:%s descriptor:%x\n", k, descr->PortNames[k], pd);
307 #endif
308
309 if (LADSPA_IS_PORT_AUDIO(pd))
310 {
311 if (LADSPA_IS_PORT_INPUT(pd))
312 {
313 ++_inports;
314 iIdx.push_back(k);
315 }
316 else if (LADSPA_IS_PORT_OUTPUT(pd))
317 {
318 ++_outports;
319 oIdx.push_back(k);
320 }
321
322 rpIdx.push_back((unsigned long)-1);
323 }
324 else if (LADSPA_IS_PORT_CONTROL(pd))
325 {
326 if (LADSPA_IS_PORT_INPUT(pd))
327 {
328 rpIdx.push_back(_controlInPorts);
329 ++_controlInPorts;
330 }
331 else if (LADSPA_IS_PORT_OUTPUT(pd))
332 {
333 rpIdx.push_back((unsigned long)-1);
334 ++_controlOutPorts;
335 }
336 }
337 }
338
339 // Hack: Blacklist vst plugins in-place, configurable for now.
340 if((_inports != _outports) || (_isDssiVst && !MusEGlobal::config.vstInPlace))
341 _requiredFeatures |= PluginNoInPlaceProcessing;
342 }
343 }
344
345 if (dssi == 0)
346 {
347 fprintf(stderr, "cannot find DSSI synti %s\n", _name.toLatin1().constData());
348 dlclose(handle);
349 handle = 0;
350 df = 0;
351 return 0;
352 }
353
354 DssiSynthIF* sif = new DssiSynthIF(synti);
355 ++_instances;
356 sif->init(this);
357
358 return sif;
359 }
360
361 //---------------------------------------------------------
362 // guiVisible
363 //---------------------------------------------------------
364
nativeGuiVisible() const365 bool DssiSynthIF::nativeGuiVisible() const
366 {
367 #ifdef OSC_SUPPORT
368 return _oscif.oscGuiVisible();
369 #endif
370 return false;
371 }
372
373 //---------------------------------------------------------
374 // showNativeGui
375 //---------------------------------------------------------
376
showNativeGui(bool v)377 void DssiSynthIF::showNativeGui(bool
378 #if defined(OSC_SUPPORT)
379 v
380 #endif
381 )
382 {
383 #ifdef OSC_SUPPORT
384
385 #ifdef DSSI_DEBUG
386 printf("DssiSynthIF::showNativeGui(): v:%d visible:%d\n", v, guiVisible());
387 #endif
388
389 _oscif.oscShowGui(v);
390
391 #endif // OSC_SUPPORT
392 }
393
394 //---------------------------------------------------------
395 // receiveEvent
396 //---------------------------------------------------------
397
receiveEvent()398 MidiPlayEvent DssiSynthIF::receiveEvent()
399 {
400 return MidiPlayEvent();
401 }
402
403 //---------------------------------------------------------
404 // init
405 //---------------------------------------------------------
406
init(DssiSynth * s)407 bool DssiSynthIF::init(DssiSynth* s)
408 {
409 #ifdef DSSI_DEBUG
410 printf("DssiSynthIF::init\n");
411 #endif
412
413 _synth = s;
414 const DSSI_Descriptor* dssi = _synth->dssi;
415 const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
416 _handle = ld->instantiate(ld, MusEGlobal::sampleRate);
417
418 #ifdef OSC_SUPPORT
419 _oscif.oscSetSynthIF(this);
420 #endif
421
422 queryPrograms();
423
424 int inports = _synth->_inports;
425 if(inports != 0)
426 {
427 int rv = posix_memalign((void**)&_audioInSilenceBuf, 16, sizeof(float) * MusEGlobal::segmentSize);
428 if(rv != 0)
429 {
430 fprintf(stderr, "ERROR: DssiSynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
431 abort();
432 }
433 if(MusEGlobal::config.useDenormalBias)
434 {
435 for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
436 _audioInSilenceBuf[q] = MusEGlobal::denormalBias;
437 }
438 else
439 memset(_audioInSilenceBuf, 0, sizeof(float) * MusEGlobal::segmentSize);
440
441 _audioInBuffers = new float*[inports];
442 for(int k = 0; k < inports; ++k)
443 {
444 int rv = posix_memalign((void**)&_audioInBuffers[k], 16, sizeof(float) * MusEGlobal::segmentSize);
445 if(rv != 0)
446 {
447 fprintf(stderr, "ERROR: DssiSynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
448 abort();
449 }
450 if(MusEGlobal::config.useDenormalBias)
451 {
452 for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
453 _audioInBuffers[k][q] = MusEGlobal::denormalBias;
454 }
455 else
456 memset(_audioInBuffers[k], 0, sizeof(float) * MusEGlobal::segmentSize);
457 ld->connect_port(_handle, _synth->iIdx[k], _audioInBuffers[k]);
458 }
459 }
460
461 int outports = _synth->_outports;
462 if(outports != 0)
463 {
464 _audioOutBuffers = new float*[outports];
465 for(int k = 0; k < outports; ++k)
466 {
467 int rv = posix_memalign((void**)&_audioOutBuffers[k], 16, sizeof(float) * MusEGlobal::segmentSize);
468 if(rv != 0)
469 {
470 fprintf(stderr, "ERROR: DssiSynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
471 abort();
472 }
473 if(MusEGlobal::config.useDenormalBias)
474 {
475 for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
476 _audioOutBuffers[k][q] = MusEGlobal::denormalBias;
477 }
478 else
479 memset(_audioOutBuffers[k], 0, sizeof(float) * MusEGlobal::segmentSize);
480 ld->connect_port(_handle, _synth->oIdx[k], _audioOutBuffers[k]);
481 }
482 }
483
484 int controlPorts = _synth->_controlInPorts;
485 int controlOutPorts = _synth->_controlOutPorts;
486
487 if(controlPorts != 0)
488 _controls = new Port[controlPorts];
489 else
490 _controls = 0;
491
492 if(controlOutPorts != 0)
493 _controlsOut = new Port[controlOutPorts];
494 else
495 _controlsOut = 0;
496
497 _synth->midiCtl2PortMap.clear();
498 _synth->port2MidiCtlMap.clear();
499
500 int cip = 0;
501 int cop = 0;
502 for (unsigned long k = 0; k < _synth->_portCount; ++k)
503 {
504 LADSPA_PortDescriptor pd = ld->PortDescriptors[k];
505
506 #ifdef DSSI_DEBUG
507 printf("DssiSynth::init ladspa plugin Port:%lu Name:%s descriptor:%x\n", k, ld->PortNames[k], pd);
508 #endif
509
510 if (LADSPA_IS_PORT_CONTROL(pd))
511 {
512 if (LADSPA_IS_PORT_INPUT(pd))
513 {
514 _controls[cip].idx = k;
515 float val;
516 ladspaDefaultValue(ld, k, &val);
517 _controls[cip].val = val;
518 _controls[cip].tmpVal = val;
519 _controls[cip].enCtrl = true;
520
521 #ifdef DSSI_DEBUG
522 printf("DssiSynthIF::init control port:%d port idx:%lu name:%s\n", cip, k, ld->PortNames[k]);
523 #endif
524
525 // This code is duplicated in ::getControllerInfo()
526
527
528 int ctlnum = DSSI_NONE;
529 if(dssi->get_midi_controller_for_port)
530 ctlnum = dssi->get_midi_controller_for_port(_handle, k);
531
532 // No controller number? Try to give it a unique one...
533 if(ctlnum == DSSI_NONE)
534 {
535 // FIXME: Be more careful. Must make sure to pick numbers not already chosen or which WILL BE chosen.
536 // Simple but flawed solution: Start them at 0x60000 + 0x2000 = 0x62000. Max NRPN number is 0x3fff.
537 // TODO: Update: Actually we want to try to use CC Controller7 controllers if possible (or a choice) because what if
538 // the user's controller hardware doesn't support RPN?
539 // If CC Controller7 is chosen we must make sure to use only non-common numbers. An already limited range
540 // of 127 now becomes narrower. See the cool document midi-controllers.txt in the DSSI source for a
541 // nice roundup of numbers and how to choose them and how they relate to synths and DSSI synths etc. !
542 ctlnum = CTRL_NRPN14_OFFSET + 0x2000 + cip;
543 }
544 else
545 {
546 int c = ctlnum;
547 // Can be both CC and NRPN! Prefer CC over NRPN.
548 if(DSSI_IS_CC(ctlnum))
549 {
550 #ifdef DSSI_DEBUG
551 printf("DssiSynthIF::init is CC control\n");
552 #endif
553
554 ctlnum = DSSI_CC_NUMBER(c);
555 #ifdef DSSI_DEBUG
556 if(DSSI_IS_NRPN(ctlnum))
557 printf("DssiSynthIF::init is also NRPN control. Using CC.\n");
558 #endif
559 }
560 else
561 if(DSSI_IS_NRPN(ctlnum))
562 {
563 #ifdef DSSI_DEBUG
564 printf("DssiSynthIF::init is NRPN control\n");
565 #endif
566
567 ctlnum = DSSI_NRPN_NUMBER(c) + CTRL_NRPN14_OFFSET;
568 }
569
570 }
571
572 #ifdef DSSI_DEBUG
573 printf("DssiSynthIF::init inserting to midiCtl2PortMap: ctlnum:%d k:%d\n", ctlnum, cip);
574 #endif
575
576 // We have a controller number! Insert it and the DSSI port number into both maps.
577 _synth->midiCtl2PortMap.insert(std::pair<int, int>(ctlnum, cip));
578 _synth->port2MidiCtlMap.insert(std::pair<int, int>(cip, ctlnum));
579
580 // Support a special block for dssi synth ladspa controllers.
581 // Put the ID at a special block after plugins (far after).
582 int id = genACnum(MusECore::MAX_PLUGINS, cip);
583 const char* name = ld->PortNames[k];
584 float min, max;
585 ladspaControlRange(ld, k, &min, &max);
586 CtrlList* cl;
587 CtrlListList* cll = track()->controller();
588 iCtrlList icl = cll->find(id);
589 if (icl == cll->end())
590 {
591 cl = new CtrlList(id);
592 cll->add(cl);
593 cl->setCurVal(_controls[cip].val);
594 }
595 else
596 {
597 cl = icl->second;
598 _controls[cip].val = cl->curVal();
599 }
600 cl->setRange(min, max);
601 cl->setName(QString(name));
602 cl->setValueType(ladspaCtrlValueType(ld, k));
603 cl->setMode(ladspaCtrlMode(ld, k));
604
605 ld->connect_port(_handle, k, &_controls[cip].val);
606
607 ++cip;
608 }
609 else if (LADSPA_IS_PORT_OUTPUT(pd))
610 {
611 const char* pname = ld->PortNames[k];
612 if(pname == QString("latency") || pname == QString("_latency"))
613 {
614 _hasLatencyOutPort = true;
615 _latencyOutPort = cop;
616 }
617 _controlsOut[cop].idx = k;
618 _controlsOut[cop].val = 0.0;
619 _controlsOut[cop].tmpVal = 0.0;
620 _controlsOut[cop].enCtrl = false;
621
622 #ifdef DSSI_DEBUG
623 printf("DssiSynthIF::init control output port:%d port idx:%lu name:%s\n", cop, k, ld->PortNames[k]);
624 #endif
625
626 // Control outs are not handled but still must be connected to something.
627 ld->connect_port(_handle, k, &_controlsOut[cop].val);
628
629 ++cop;
630 }
631 }
632 }
633
634 activate();
635
636 // Set current configuration values.
637 if(dssi->configure)
638 {
639 char *rv = dssi->configure(_handle, DSSI_PROJECT_DIRECTORY_KEY,
640 MusEGlobal::museProject.toLatin1().constData()); //MusEGlobal::song->projectPath()
641
642 if(rv)
643 {
644 fprintf(stderr, "MusE: Warning: plugin doesn't like project directory: \"%s\"\n", rv);
645 free(rv);
646 }
647
648 for(ciStringParamMap r = synti->_initConfig._stringParamMap.begin(); r != synti->_initConfig._stringParamMap.end(); ++r)
649 {
650 rv = 0;
651 rv = dssi->configure(_handle, r->first.c_str(), r->second.c_str());
652 if(rv)
653 {
654 fprintf(stderr, "MusE: Warning: plugin config key: %s value: %s \"%s\"\n", r->first.c_str(), r->second.c_str(), rv);
655 free(rv);
656 }
657 }
658 }
659
660 //
661 // For stored initial control values, let SynthI::initInstance() take care of that via ::setParameter().
662 //
663
664 return true;
665 }
666
667 //---------------------------------------------------------
668 // DssiSynthIF
669 //---------------------------------------------------------
670
DssiSynthIF(SynthI * s)671 DssiSynthIF::DssiSynthIF(SynthI* s)
672 : SynthIF(s)
673 {
674 #ifdef DSSI_DEBUG
675 printf("DssiSynthIF::DssiSynthIF\n");
676 #endif
677 _synth = 0;
678 _handle = NULL;
679 _controls = 0;
680 _controlsOut = 0;
681 _hasLatencyOutPort = false;
682 _latencyOutPort = 0;
683 _audioInBuffers = 0;
684 _audioInSilenceBuf = 0;
685 _audioOutBuffers = 0;
686 }
687
688 //---------------------------------------------------------
689 // ~DssiSynthIF
690 //---------------------------------------------------------
691
~DssiSynthIF()692 DssiSynthIF::~DssiSynthIF()
693 {
694 #ifdef DSSI_DEBUG
695 printf("DssiSynthIF::~DssiSynthIF\n");
696 #endif
697
698 #ifdef OSC_SUPPORT
699 _oscif.oscSetSynthIF(NULL);
700 #endif
701
702 if(_synth)
703 {
704 #ifdef DSSI_DEBUG
705 printf("DssiSynthIF::~DssiSynthIF synth:%p\n", synth);
706 #endif
707
708 if(_synth->dssi)
709 {
710 #ifdef DSSI_DEBUG
711 printf("DssiSynthIF::~DssiSynthIF synth->dssi:%p\n", synth->dssi);
712 #endif
713
714 if(_synth->dssi->LADSPA_Plugin)
715 {
716 #ifdef DSSI_DEBUG
717 printf("DssiSynthIF::~DssiSynthIFsynth->dssi->LADSPA_Plugin:%p\n", synth->dssi->LADSPA_Plugin);
718 #endif
719 }
720 }
721 }
722
723 if(_synth && _synth->dssi && _synth->dssi->LADSPA_Plugin)
724 {
725 const DSSI_Descriptor* dssi = _synth->dssi;
726 const LADSPA_Descriptor* descr = dssi->LADSPA_Plugin;
727
728 #ifdef DSSI_DEBUG
729 printf("DssiSynthIF::~DssiSynthIF checking cleanup function exists\n");
730 #endif
731
732 if(descr->cleanup)
733 {
734 #ifdef DSSI_DEBUG
735 printf("DssiSynthIF::~DssiSynthIF calling cleanup function\n");
736 #endif
737
738 descr->cleanup(_handle);
739 }
740 }
741 if(_audioInBuffers)
742 {
743 for(unsigned long i = 0; i < _synth->_inports; ++i)
744 {
745 if(_audioInBuffers[i])
746 free(_audioInBuffers[i]);
747 }
748 delete[] _audioInBuffers;
749 }
750
751 if(_audioInSilenceBuf)
752 free(_audioInSilenceBuf);
753
754 if(_audioOutBuffers)
755 {
756 for(unsigned long i = 0; i < _synth->_outports; ++i)
757 {
758 if(_audioOutBuffers[i])
759 free(_audioOutBuffers[i]);
760 }
761 delete[] _audioOutBuffers;
762 }
763
764 if(_controls)
765 delete[] _controls;
766
767 if(_controlsOut)
768 delete[] _controlsOut;
769 }
770
oldMidiStateHeader(const unsigned char ** data) const771 int DssiSynthIF::oldMidiStateHeader(const unsigned char** data) const
772 {
773 static unsigned char const d[2] = {MUSE_SYNTH_SYSEX_MFG_ID, DSSI_SYNTH_UNIQUE_ID};
774 *data = &d[0];
775 return 2;
776 }
777
hasLatencyOutPort() const778 bool DssiSynthIF::hasLatencyOutPort() const
779 {
780 return _hasLatencyOutPort;
781 }
782
latencyOutPortIndex() const783 unsigned long DssiSynthIF::latencyOutPortIndex() const
784 {
785 return _latencyOutPort;
786 }
787
788 //---------------------------------------------------------
789 // latency
790 //---------------------------------------------------------
791
latency() const792 float DssiSynthIF::latency() const
793 {
794 // Do not report any latency if the plugin is not on.
795 if(!on())
796 return 0.0;
797 if(cquirks()._overrideReportedLatency)
798 return cquirks()._latencyOverrideValue;
799 if(!hasLatencyOutPort())
800 return 0.0;
801 return _controlsOut[latencyOutPortIndex()].val;
802 }
803
804
805 //---------------------------------------------------------
806 // getParameter
807 //---------------------------------------------------------
808
getParameter(unsigned long n) const809 double DssiSynthIF::getParameter(unsigned long n) const
810 {
811 if(n >= _synth->_controlInPorts)
812 {
813 printf("DssiSynthIF::getParameter param number %lu out of range of ports:%lu\n", n, _synth->_controlInPorts);
814 return 0.0;
815 }
816
817 if(!_controls)
818 return 0.0;
819
820 return _controls[n].val;
821 }
822 //---------------------------------------------------------
823 // getParameter
824 //---------------------------------------------------------
825
getParameterOut(unsigned long n) const826 double DssiSynthIF::getParameterOut(unsigned long n) const
827 {
828 if(n >= _synth->_controlOutPorts)
829 {
830 printf("DssiSynthIF::getParameterOut param number %lu out of range of ports:%lu\n", n, _synth->_controlOutPorts);
831 return 0.0;
832 }
833
834 if(!_controlsOut)
835 return 0.0;
836
837 return _controlsOut[n].val;
838 }
839
840 //---------------------------------------------------------
841 // setParameter
842 //---------------------------------------------------------
843
setParameter(unsigned long n,double v)844 void DssiSynthIF::setParameter(unsigned long n, double v)
845 {
846 addScheduledControlEvent(n, v, MusEGlobal::audio->curFrame());
847 }
848
849 //---------------------------------------------------------
850 // write
851 //---------------------------------------------------------
852
write(int level,Xml & xml) const853 void DssiSynthIF::write(int level, Xml& xml) const
854 {
855 #ifdef DSSI_VST_CHUNK_SUPPORT
856 if(_synth->dssi->getCustomData)
857 {
858 //---------------------------------------------
859 // dump current state of synth
860 //---------------------------------------------
861 printf("dumping DSSI custom data! %p\n", _synth->dssi->getCustomData);
862
863 // this is only needed and supported if
864 // we are talking to a VST plugin at the other end.
865 std::string name = _synth->dssi->LADSPA_Plugin->Name;
866 if ((name.length()> 4) && name.substr(name.length() - 4) == " VST")
867 {
868 printf("is vst plugin, commencing data dump, apiversion=%d!\n", _synth->dssi->DSSI_API_Version);
869 unsigned long len = 0;
870 void* p = 0;
871 _synth->dssi->getCustomData(_handle,&p, &len);
872 if (len) {
873 xml.tag(level++, " version=\"%d\"", SYNTH_MIDI_STATE_SAVE_VERSION);
874 xml.nput(level++, "<event type=\"%d\"", Sysex);
875 xml.nput(" datalen=\"%d\">\n", len+9 /* 9 = 2 bytes header + "VSTSAVE"*/);
876 xml.nput(level, "");
877 xml.nput("%02x %02x ", (char)MUSE_SYNTH_SYSEX_MFG_ID, (char)DSSI_SYNTH_UNIQUE_ID); // Wrap in a proper header
878 xml.nput("56 53 54 53 41 56 45 "); // embed a save marker "string 'VSTSAVE'
879 for (long unsigned int i = 0; i < len; ++i) {
880 if (i && (((i+9) % 16) == 0)) {
881 xml.nput("\n");
882 xml.nput(level, "");
883 }
884 xml.nput("%02x ", ((char*)(p))[i] & 0xff);
885 }
886 xml.nput("\n");
887 xml.tag(level--, "/event");
888 xml.etag(level--, "midistate");
889 }
890 }
891 }
892 #else
893 printf("support for vst chunks not compiled in!\n");
894 #endif
895
896 // DELETETHIS 97 ???
897 /*
898 // p3.3.39 Store the state of current program and bank and all input control values, but only if VSTSAVE above didn't do it already!
899 // TODO: Not quite good enough, we would want to store all controls for EACH program, not just the current one.
900 // Need to modify controls array to be inside a program array and act as a cache when the user changes a control on a particular program.
901 if(!vstsaved)
902 {
903 if(synth->_controlInPorts)
904 {
905 // TODO: Hmm, what if these sizes change (platform etc.)? Hard code? Not good - need to store complete value.
906 const int fs = sizeof(float);
907 const int uls = sizeof(unsigned long);
908
909 // Data length: Version major and minor bytes, bank + program, and controllers.
910 const unsigned long len = 2 + 2 * uls + synth->_controlInPorts * fs;
911
912 unsigned long prog = _curBank;
913 unsigned long bnk = _curProgram;
914
915 xml.tag(level++, "midistate");
916 xml.nput(level++, "<event type=\"%d\"", Sysex);
917 xml.nput(" datalen=\"%d\">\n", len+9); // "PARAMSAVE" length + data length.
918 xml.nput(level, "");
919 xml.nput("50 41 52 41 4d 53 41 56 45 "); // Embed a save marker string "PARAMSAVE".
920
921 unsigned long i = 9;
922
923 // Store PARAMSAVE version major...
924 char uc = DSSI_PARAMSAVE_VERSION_MAJOR;
925 if(i && ((i % 16) == 0))
926 {
927 xml.nput("\n");
928 xml.nput(level, "");
929 }
930 xml.nput("%02x ", uc & 0xff);
931 ++i;
932
933 // Store PARAMSAVE version minor...
934 uc = DSSI_PARAMSAVE_VERSION_MINOR;
935 if(i && ((i % 16) == 0))
936 {
937 xml.nput("\n");
938 xml.nput(level, "");
939 }
940 xml.nput("%02x ", uc & 0xff);
941 ++i;
942
943 // Store bank...
944 void* p = &bnk;
945 for(int j = 0; j < uls; ++j)
946 {
947 if(i && ((i % 16) == 0))
948 {
949 xml.nput("\n");
950 xml.nput(level, "");
951 }
952 xml.nput("%02x ", ((char*)(p))[j] & 0xff);
953 ++i;
954 }
955
956 // Store program...
957 p = &prog;
958 for(int j = 0; j < uls; ++j)
959 {
960 if(i && ((i % 16) == 0))
961 {
962 xml.nput("\n");
963 xml.nput(level, "");
964 }
965 xml.nput("%02x ", ((char*)(p))[j] & 0xff);
966 ++i;
967 }
968
969 // Store controls...
970 for(unsigned long c = 0; c < synth->_controlInPorts; ++c)
971 {
972 float v = controls[c].val;
973 p = &v;
974 for(int j = 0; j < fs; ++j)
975 {
976 if(i && ((i % 16) == 0))
977 {
978 xml.nput("\n");
979 xml.nput(level, "");
980 }
981 xml.nput("%02x ", ((char*)(p))[j] & 0xff);
982 ++i;
983 }
984 }
985 xml.nput("\n");
986 xml.tag(level--, "/event");
987 xml.etag(level--, "midistate");
988 }
989 }
990 */
991
992 // Store controls as parameters...
993 for(unsigned long c = 0; c < _synth->_controlInPorts; ++c)
994 xml.doubleTag(level, "param", _controls[c].val);
995 }
996
997 //---------------------------------------------------------
998 // processEvent
999 // Return true if event pointer filled.
1000 //--------------------------------------------------------
1001
processEvent(const MidiPlayEvent & e,snd_seq_event_t * event)1002 bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
1003 {
1004 const DSSI_Descriptor* dssi = _synth->dssi;
1005
1006 int chn = e.channel();
1007 int a = e.dataA();
1008 int b = e.dataB();
1009
1010 #ifdef DSSI_DEBUG
1011 fprintf(stderr, "DssiSynthIF::processEvent midi event type:%d chn:%d a:%d b:%d\n", e.type(), chn, a, b);
1012 #endif
1013
1014 const MidiInstrument::NoteOffMode nom = synti->noteOffMode();
1015
1016 switch(e.type())
1017 {
1018 case ME_NOTEON:
1019 #ifdef DSSI_DEBUG
1020 fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_NOTEON\n");
1021 #endif
1022
1023 snd_seq_ev_clear(event);
1024 event->queue = SND_SEQ_QUEUE_DIRECT;
1025
1026 if(b == 0)
1027 {
1028 // Handle zero-velocity note ons. Technically this is an error because internal midi paths
1029 // are now all 'note-off' without zero-vel note ons - they're converted to note offs.
1030 // Nothing should be setting a Note type Event's on velocity to zero.
1031 // But just in case... If we get this warning, it means there is still code to change.
1032 fprintf(stderr, "DssiSynthIF::processEvent: Warning: Zero-vel note on: time:%d type:%d (ME_NOTEON) ch:%d A:%d B:%d\n", e.time(), e.type(), chn, a, b);
1033 switch(nom)
1034 {
1035 // Instrument uses note offs. Convert to zero-vel note off.
1036 case MidiInstrument::NoteOffAll:
1037 //if(MusEGlobal::midiOutputTrace)
1038 // fprintf(stderr, "MidiOut: DSSI: Following event will be converted to zero-velocity note off:\n");
1039 snd_seq_ev_set_noteoff(event, chn, a, 0);
1040 break;
1041
1042 // Instrument uses no note offs at all. Send as-is.
1043 case MidiInstrument::NoteOffNone:
1044 // Instrument converts all note offs to zero-vel note ons. Send as-is.
1045 case MidiInstrument::NoteOffConvertToZVNoteOn:
1046 snd_seq_ev_set_noteon(event, chn, a, b);
1047 break;
1048 }
1049 }
1050 else
1051 snd_seq_ev_set_noteon(event, chn, a, b);
1052
1053
1054
1055 break;
1056 case ME_NOTEOFF:
1057 #ifdef DSSI_DEBUG
1058 fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_NOTEOFF\n");
1059 #endif
1060
1061 snd_seq_ev_clear(event);
1062 event->queue = SND_SEQ_QUEUE_DIRECT;
1063
1064 switch(nom)
1065 {
1066 // Instrument uses note offs. Send as-is.
1067 case MidiInstrument::NoteOffAll:
1068 snd_seq_ev_set_noteoff(event, chn, a, b);
1069 break;
1070
1071 // Instrument uses no note offs at all. Send nothing. Eat up the event - return false.
1072 case MidiInstrument::NoteOffNone:
1073 return false;
1074
1075 // Instrument converts all note offs to zero-vel note ons. Convert to zero-vel note on.
1076 case MidiInstrument::NoteOffConvertToZVNoteOn:
1077 //if(MusEGlobal::midiOutputTrace)
1078 // fprintf(stderr, "MidiOut: DSSI: Following event will be converted to zero-velocity note on:\n");
1079 snd_seq_ev_set_noteon(event, chn, a, 0);
1080 break;
1081 }
1082
1083 break;
1084 // Synths are not allowed to receive ME_PROGRAM, CTRL_HBANK, or CTRL_LBANK alone anymore.
1085 case ME_PROGRAM:
1086 {
1087 #ifdef DSSI_DEBUG
1088 fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_PROGRAM\n");
1089 #endif
1090
1091 int hb, lb;
1092 synti->currentProg(chn, NULL, &lb, &hb);
1093 synti->setCurrentProg(chn, a & 0xff, lb, hb);
1094 doSelectProgram(_handle, hb, lb, a);
1095 // Event pointer not filled. Return false.
1096 return false;
1097 }
1098 break;
1099 case ME_CONTROLLER:
1100 {
1101 #ifdef DSSI_DEBUG
1102 fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_CONTROLLER\n");
1103 #endif
1104
1105 // Our internal hwCtrl controllers support the 'unknown' value.
1106 // Don't send 'unknown' values to the driver. Ignore and return no error.
1107 if(b == CTRL_VAL_UNKNOWN)
1108 return false;
1109
1110 if(a == CTRL_PROGRAM)
1111 {
1112 #ifdef DSSI_DEBUG
1113 fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_PROGRAM\n");
1114 #endif
1115
1116 int hb = (b >> 16) & 0xff;
1117 int lb = (b >> 8) & 0xff;
1118 int pr = b & 0xff;
1119 synti->setCurrentProg(chn, pr, lb, hb);
1120 doSelectProgram(_handle, hb, lb, pr);
1121 // Event pointer not filled. Return false.
1122 return false;
1123 }
1124
1125 if(a == CTRL_HBANK)
1126 {
1127 int lb, pr;
1128 synti->currentProg(chn, &pr, &lb, NULL);
1129 synti->setCurrentProg(chn, pr, lb, b & 0xff);
1130 doSelectProgram(_handle, b, lb, pr);
1131 // Event pointer not filled. Return false.
1132 return false;
1133 }
1134
1135 if(a == CTRL_LBANK)
1136 {
1137 int hb, pr;
1138 synti->currentProg(chn, &pr, NULL, &hb);
1139 synti->setCurrentProg(chn, pr, b & 0xff, hb);
1140 doSelectProgram(_handle, hb, b, pr);
1141 // Event pointer not filled. Return false.
1142 return false;
1143 }
1144
1145 if(a == CTRL_PITCH)
1146 {
1147 #ifdef DSSI_DEBUG
1148 fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_PITCH\n");
1149 #endif
1150
1151 snd_seq_ev_clear(event);
1152 event->queue = SND_SEQ_QUEUE_DIRECT;
1153 snd_seq_ev_set_pitchbend(event, chn, b);
1154 // Event pointer filled. Return true.
1155 return true;
1156 }
1157
1158 if(a == CTRL_AFTERTOUCH)
1159 {
1160 #ifdef DSSI_DEBUG
1161 fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_AFTERTOUCH\n");
1162 #endif
1163
1164 snd_seq_ev_clear(event);
1165 event->queue = SND_SEQ_QUEUE_DIRECT;
1166 snd_seq_ev_set_chanpress(event, chn, b);
1167 // Event pointer filled. Return true.
1168 return true;
1169 }
1170
1171 if((a | 0xff) == CTRL_POLYAFTER)
1172 {
1173 #ifdef DSSI_DEBUG
1174 fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_POLYAFTER\n");
1175 #endif
1176
1177 snd_seq_ev_clear(event);
1178 event->queue = SND_SEQ_QUEUE_DIRECT;
1179 snd_seq_ev_set_keypress(event, chn, a & 0x7f, b & 0x7f);
1180 // Event pointer filled. Return true.
1181 return true;
1182 }
1183
1184 const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
1185
1186 ciMidiCtl2LadspaPort ip = _synth->midiCtl2PortMap.find(a);
1187 // Is it just a regular midi controller, not mapped to a LADSPA port (either by the plugin or by us)?
1188 // NOTE: There's no way to tell which of these controllers is supported by the plugin.
1189 // For example sustain footpedal or pitch bend may be supported, but not mapped to any LADSPA port.
1190 if(ip == _synth->midiCtl2PortMap.end())
1191 {
1192 int ctlnum = a;
1193 if(midiControllerType(a) != MidiController::Controller7)
1194 return false; // Event pointer not filled. Return false.
1195 else
1196 {
1197 #ifdef DSSI_DEBUG
1198 fprintf(stderr, "DssiSynthIF::processEvent non-ladspa midi event is Controller7. Current dataA:%d\n", a);
1199 #endif
1200 a &= 0x7f;
1201 ctlnum = DSSI_CC_NUMBER(ctlnum);
1202 }
1203
1204 // Fill the event.
1205 #ifdef DSSI_DEBUG
1206 printf("DssiSynthIF::processEvent non-ladspa filling midi event chn:%d dataA:%d dataB:%d\n", chn, a, b);
1207 #endif
1208 snd_seq_ev_clear(event);
1209 event->queue = SND_SEQ_QUEUE_DIRECT;
1210 snd_seq_ev_set_controller(event, chn, a, b);
1211 return true;
1212 }
1213
1214 unsigned long k = ip->second;
1215 unsigned long i = _controls[k].idx;
1216 int ctlnum = DSSI_NONE;
1217 if(dssi->get_midi_controller_for_port)
1218 ctlnum = dssi->get_midi_controller_for_port(_handle, i);
1219
1220 // No midi controller for the ladspa port? Send to ladspa control.
1221 if(ctlnum == DSSI_NONE)
1222 {
1223 // Sanity check.
1224 if(k > _synth->_controlInPorts)
1225 return false;
1226
1227 // Simple but flawed solution: Start them at 0x60000 + 0x2000 = 0x62000. Max NRPN number is 0x3fff.
1228 ctlnum = k + (CTRL_NRPN14_OFFSET + 0x2000);
1229 }
1230 else
1231 {
1232 #ifdef DSSI_DEBUG
1233 printf("DssiSynthIF::processEvent plugin requests DSSI-style ctlnum:%x(h) %d(d) be mapped to control port:%lu...\n", ctlnum, ctlnum, i);
1234 #endif
1235
1236 int c = ctlnum;
1237 // Can be both CC and NRPN! Prefer CC over NRPN.
1238 if(DSSI_IS_CC(ctlnum))
1239 {
1240 ctlnum = DSSI_CC_NUMBER(c);
1241
1242 #ifdef DSSI_DEBUG
1243 printf("DssiSynthIF::processEvent is CC ctlnum:%d\n", ctlnum);
1244 #endif
1245
1246 #ifdef DSSI_DEBUG
1247 if(DSSI_IS_NRPN(ctlnum))
1248 printf("DssiSynthIF::processEvent is also NRPN control. Using CC.\n");
1249 #endif
1250 }
1251 else
1252 if(DSSI_IS_NRPN(ctlnum))
1253 {
1254 ctlnum = DSSI_NRPN_NUMBER(c) + CTRL_NRPN14_OFFSET;
1255
1256 #ifdef DSSI_DEBUG
1257 printf("DssiSynthIF::processEvent is NRPN ctlnum:%x(h) %d(d)\n", ctlnum, ctlnum);
1258 #endif
1259 }
1260
1261 }
1262
1263 float val = midi2LadspaValue(ld, i, ctlnum, b);
1264
1265 #ifdef DSSI_DEBUG
1266 fprintf(stderr, "DssiSynthIF::processEvent control port:%lu port:%lu dataA:%d Converting val from:%d to ladspa:%f\n", i, k, a, b, val);
1267 #endif
1268
1269 // Set the ladspa port value.
1270 _controls[k].val = val;
1271
1272 // Need to update the automation value, otherwise it overwrites later with the last automation value.
1273 if(id() != -1)
1274 // We're in the audio thread context: no need to send a message, just modify directly.
1275 synti->setPluginCtrlVal(genACnum(id(), k), val);
1276
1277 // Since we absorbed the message as a ladspa control change, return false - the event is not filled.
1278 return false;
1279 }
1280 break;
1281 case ME_PITCHBEND:
1282 snd_seq_ev_clear(event);
1283 event->queue = SND_SEQ_QUEUE_DIRECT;
1284 snd_seq_ev_set_pitchbend(event, chn, a);
1285 break;
1286 case ME_AFTERTOUCH:
1287 snd_seq_ev_clear(event);
1288 event->queue = SND_SEQ_QUEUE_DIRECT;
1289 snd_seq_ev_set_chanpress(event, chn, a);
1290 break;
1291 case ME_POLYAFTER:
1292 snd_seq_ev_clear(event);
1293 event->queue = SND_SEQ_QUEUE_DIRECT;
1294 snd_seq_ev_set_keypress(event, chn, a & 0x7f, b & 0x7f);
1295 break;
1296 case ME_SYSEX:
1297 {
1298 #ifdef DSSI_DEBUG
1299 fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_SYSEX\n");
1300 #endif
1301
1302 const unsigned char* data = e.constData();
1303 if(e.len() >= 2)
1304 {
1305 if(data[0] == MUSE_SYNTH_SYSEX_MFG_ID)
1306 {
1307 if(data[1] == DSSI_SYNTH_UNIQUE_ID)
1308 {
1309 if(e.len() >= 9)
1310 {
1311 if (QString((const char*)(data + 2)).startsWith("VSTSAVE")) {
1312 #ifdef DSSI_VST_CHUNK_SUPPORT
1313 if(dssi->setCustomData)
1314 {
1315 printf("loading chunk from sysex %s!\n", data+9);
1316 usleep(300000);
1317 dssi->setCustomData(_handle, (unsigned char*)(data+9) /* len of str*/,e.len()-9);
1318 usleep(300000);
1319 }
1320 #else
1321 printf("support for vst chunks not compiled in!\n");
1322 #endif
1323 // Event not filled.
1324 return false;
1325 }
1326 }
1327 }
1328 }
1329 }
1330
1331 // DELETETHIS, 50 clean it up or fix it?
1332 /*
1333 // p3.3.39 Read the state of current bank and program and all input control values.
1334 // TODO: Needs to be better. See write().
1335 //else
1336 if (QString((const char*)e.data()).startsWith("PARAMSAVE"))
1337 {
1338 #ifdef DSSI_DEBUG
1339 fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_SYSEX PARAMSAVE\n");
1340 #endif
1341
1342 unsigned long dlen = e.len() - 9; // Minus "PARAMSAVE"
1343 if(dlen > 0)
1344 {
1345 //if(dlen < 2 * sizeof(unsigned long))
1346 if(dlen < (2 + 2 * sizeof(unsigned long))) // Version major and minor bytes, bank and program.
1347 printf("DssiSynthIF::processEvent Error: PARAMSAVE data length does not include at least version major and minor, bank and program!\n");
1348 else
1349 {
1350 // Not required, yet.
1351 //char vmaj = *((char*)(e.data() + 9)); // After "PARAMSAVE"
1352 //char vmin = *((char*)(e.data() + 10));
1353
1354 unsigned long* const ulp = (unsigned long*)(e.data() + 11); // After "PARAMSAVE" + version major and minor.
1355 // TODO: TODO: Set plugin bank and program.
1356 _curBank = ulp[0];
1357 _curProgram = ulp[1];
1358
1359 dlen -= (2 + 2 * sizeof(unsigned long)); // After the version major and minor, bank and program.
1360
1361 if(dlen > 0)
1362 {
1363 if((dlen % sizeof(float)) != 0)
1364 printf("DssiSynthIF::processEvent Error: PARAMSAVE float data length not integral multiple of float size!\n");
1365 else
1366 {
1367 const unsigned long n = dlen / sizeof(float);
1368 if(n != synth->_controlInPorts)
1369 printf("DssiSynthIF::processEvent Warning: PARAMSAVE number of floats:%lu != number of controls:%lu\n", n, synth->_controlInPorts);
1370
1371 // Point to location after "PARAMSAVE", version major and minor, bank and progam.
1372 float* const fp = (float*)(e.data() + 9 + 2 + 2 * sizeof(unsigned long));
1373
1374 for(unsigned long i = 0; i < synth->_controlInPorts && i < n; ++i)
1375 {
1376 const float v = fp[i];
1377 controls[i].val = v;
1378 }
1379 }
1380 }
1381 }
1382 }
1383 // Event not filled.
1384 return false;
1385 }
1386 */
1387 //else
1388 {
1389 // NOTE: There is a limit on the size of a sysex. Got this:
1390 // "DssiSynthIF::processEvent midi event is ME_SYSEX"
1391 // "WARNING: MIDI event of type ? decoded to 367 bytes, discarding"
1392 // That might be ALSA doing that.
1393
1394 const int len = e.len();
1395 char buf[len + 2];
1396
1397 buf[0] = 0xF0;
1398 memcpy(buf + 1, e.constData(), len);
1399 buf[len + 1] = 0xF7;
1400
1401 snd_seq_ev_clear(event);
1402 snd_seq_ev_set_sysex(event, len + 2, buf);
1403 event->queue = SND_SEQ_QUEUE_DIRECT;
1404
1405 // NOTE: Don't move this out, 'buf' would go out of scope.
1406 // Event was filled. Return true.
1407 return true;
1408 }
1409 }
1410 break;
1411 default:
1412 if(MusEGlobal::debugMsg)
1413 fprintf(stderr, "DssiSynthIF::processEvent midi event unknown type:%d\n", e.type());
1414 // Event not filled.
1415 return false;
1416 break;
1417 }
1418
1419 return true;
1420 }
1421
1422 //---------------------------------------------------------
1423 // getData
1424 // If ports is 0, just process controllers only, not audio (do not 'run').
1425 //---------------------------------------------------------
1426
getData(MidiPort *,unsigned pos,int ports,unsigned nframes,float ** buffer)1427 bool DssiSynthIF::getData(MidiPort* /*mp*/, unsigned pos, int ports, unsigned nframes, float** buffer)
1428 {
1429 const unsigned long syncFrame = MusEGlobal::audio->curSyncFrame();
1430
1431 #ifdef DSSI_DEBUG_PROCESS
1432 fprintf(stderr, "DssiSynthIF::getData: pos:%u ports:%d nframes:%u syncFrame:%lu\n", pos, ports, nframes, syncFrame);
1433 #endif
1434
1435 // All ports must be connected to something!
1436 const unsigned long in_ports = _synth->inPorts();
1437 const unsigned long out_ports = _synth->outPorts();
1438 const unsigned long nop = ((unsigned long) ports) > out_ports ? out_ports : ((unsigned long) ports);
1439
1440 const DSSI_Descriptor* dssi = _synth->dssi;
1441 const LADSPA_Descriptor* descr = dssi->LADSPA_Plugin;
1442 unsigned long sample = 0;
1443
1444 // NOTE Tested: Variable run-lengths worked superbly for LADSPA and DSSI synths. But DSSI-VST definitely
1445 // does NOT like changing sample run length. It crashes the plugin and Wine (but MusE keeps running!).
1446 // Furthermore, it resizes the shared memory (mmap, remap) upon each run length DIFFERENT from the last.
1447 // And all of this done through client-server communications. It doesn't seem designed for this technique.
1448 //
1449 // So we could support an alternate technique: A fixed control processing rate, in number of samples.
1450 //
1451 // Allow user to choose either a fixed rate or these 'packets' for LADSPA and DSSI plugins/synths,
1452 // but make fixed-rate MANDATORY for DSSI-VST plugins and synths.
1453 //
1454 // Or K.I.S.S - Just use fixed rates only, but allow it to be changed. I'm worried about libraries and
1455 // plugins other than DSSI-VST. What if they need the fixed-rate, too?
1456 // How to tell, and manage it all...?
1457 // But this 'packet' method sure seems to work nicely so far, so we'll throw it in...
1458 //
1459 // Must make this detectable for dssi vst synths, just like the plugins' in-place blacklist.
1460 // FIXME Better support for PluginPowerOf2BlockSize, by quantizing the control period times.
1461 // For now we treat it like fixed size.
1462 const bool usefixedrate = (requiredFeatures() & (PluginFixedBlockSize | PluginPowerOf2BlockSize | PluginCoarseBlockSize));
1463
1464 // Note for dssi-vst this MUST equal MusEGlobal::audio period. It doesn't like broken-up runs (it stutters),
1465 // even with fixed sizes. Could be a Wine + Jack thing, wanting a full Jack buffer's length.
1466 // For now, the fixed size is clamped to the MusEGlobal::audio buffer size.
1467 // TODO: We could later add slower processing over several cycles -
1468 // so that users can select a small MusEGlobal::audio period but a larger control period.
1469 const unsigned long min_per = (usefixedrate || MusEGlobal::config.minControlProcessPeriod > nframes) ? nframes : MusEGlobal::config.minControlProcessPeriod;
1470 const unsigned long min_per_mask = min_per-1; // min_per must be power of 2
1471
1472 AudioTrack* atrack = track();
1473 const AutomationType at = atrack->automationType();
1474 const bool no_auto = !MusEGlobal::automation || at == AUTO_OFF;
1475 const unsigned long in_ctrls = _synth->inControls();
1476 CtrlListList* cll = atrack->controller();
1477 ciCtrlList icl_first;
1478 const int plug_id = id();
1479 if(plug_id != -1 && ports != 0) // Don't bother if not 'running'.
1480 icl_first = cll->lower_bound(genACnum(plug_id, 0));
1481
1482 #ifdef DSSI_DEBUG_PROCESS
1483 fprintf(stderr, "DssiSynthIF::getData: Handling inputs...\n");
1484 #endif
1485
1486 bool used_in_chan_array[in_ports]; // Don't bother initializing if not 'running'.
1487
1488 // Don't bother if not 'running'.
1489 if(ports != 0)
1490 {
1491 // Initialize the array.
1492 for(unsigned long i = 0; i < in_ports; ++i)
1493 used_in_chan_array[i] = false;
1494
1495 if(!atrack->noInRoute())
1496 {
1497 RouteList *irl = atrack->inRoutes();
1498 for(ciRoute i = irl->begin(); i != irl->end(); ++i)
1499 {
1500 if(i->track->isMidiTrack())
1501 continue;
1502 // Only this synth knows how many destination channels there are,
1503 // while only the track knows how many source channels there are.
1504 // So take care of the destination channels here, and let the track handle the source channels.
1505 const int dst_ch = i->channel <= -1 ? 0 : i->channel;
1506 if((unsigned long)dst_ch >= in_ports)
1507 continue;
1508 const int dst_chs = i->channels <= -1 ? in_ports : i->channels;
1509 //const int total_ins = atrack->totalRoutableInputs(Route::TRACK_ROUTE);
1510 const int src_ch = i->remoteChannel <= -1 ? 0 : i->remoteChannel;
1511 const int src_chs = i->channels;
1512
1513 int fin_dst_chs = dst_chs;
1514 if((unsigned long)(dst_ch + fin_dst_chs) > in_ports)
1515 fin_dst_chs = in_ports - dst_ch;
1516
1517 static_cast<AudioTrack*>(i->track)->copyData(pos,
1518 dst_ch, dst_chs, fin_dst_chs,
1519 src_ch, src_chs,
1520 nframes, &_audioInBuffers[0],
1521 false, used_in_chan_array);
1522 const int nxt_ch = dst_ch + fin_dst_chs;
1523 for(int ch = dst_ch; ch < nxt_ch; ++ch)
1524 used_in_chan_array[ch] = true;
1525 }
1526 }
1527 }
1528
1529 #ifdef DSSI_DEBUG_PROCESS
1530 fprintf(stderr, "DssiSynthIF::getData: Processing automation control values...\n");
1531 #endif
1532
1533 int cur_slice = 0;
1534 while(sample < nframes)
1535 {
1536 unsigned long nsamp = nframes - sample;
1537 const unsigned long slice_frame = pos + sample;
1538
1539 //
1540 // Process automation control values, while also determining the maximum acceptable
1541 // size of this run. Further processing, from FIFOs for example, can lower the size
1542 // from there, but this section determines where the next highest maximum frame
1543 // absolutely needs to be for smooth playback of the controller value stream...
1544 //
1545 if(ports != 0) // Don't bother if not 'running'.
1546 {
1547 ciCtrlList icl = icl_first;
1548 for(unsigned long k = 0; k < in_ctrls; ++k)
1549 {
1550 CtrlList* cl = (cll && plug_id != -1 && icl != cll->end()) ? icl->second : NULL;
1551 CtrlInterpolate& ci = _controls[k].interp;
1552 // Always refresh the interpolate struct at first, since things may have changed.
1553 // Or if the frame is outside of the interpolate range - and eStop is not true. // FIXME TODO: Be sure these comparisons are correct.
1554 if(cur_slice == 0 || (!ci.eStop && MusEGlobal::audio->isPlaying() &&
1555 (slice_frame < (unsigned long)ci.sFrame || (ci.eFrameValid && slice_frame >= (unsigned long)ci.eFrame)) ) )
1556 {
1557 if(cl && plug_id != -1 && (unsigned long)cl->id() == genACnum(plug_id, k))
1558 {
1559 cl->getInterpolation(slice_frame, no_auto || !_controls[k].enCtrl, &ci);
1560 if(icl != cll->end())
1561 ++icl;
1562 }
1563 else
1564 {
1565 // No matching controller, or end. Just copy the current value into the interpolator.
1566 // Keep the current icl iterator, because since they are sorted by frames,
1567 // if the IDs didn't match it means we can just let k catch up with icl.
1568 ci.sFrame = 0;
1569 ci.eFrame = 0;
1570 ci.eFrameValid = false;
1571 ci.sVal = _controls[k].val;
1572 ci.eVal = ci.sVal;
1573 ci.doInterp = false;
1574 ci.eStop = false;
1575 }
1576 }
1577 else
1578 {
1579 if(ci.eStop && ci.eFrameValid && slice_frame >= (unsigned long)ci.eFrame) // FIXME TODO: Get that comparison right.
1580 {
1581 // Clear the stop condition and set up the interp struct appropriately as an endless value.
1582 ci.sFrame = 0; //ci->eFrame;
1583 ci.eFrame = 0;
1584 ci.eFrameValid = false;
1585 ci.sVal = ci.eVal;
1586 ci.doInterp = false;
1587 ci.eStop = false;
1588 }
1589 if(cl && cll && icl != cll->end())
1590 ++icl;
1591 }
1592
1593 if(!usefixedrate && MusEGlobal::audio->isPlaying())
1594 {
1595 unsigned long samps = nsamp;
1596 if(ci.eFrameValid)
1597 samps = (unsigned long)ci.eFrame - slice_frame;
1598
1599 if(!ci.doInterp && samps > min_per)
1600 {
1601 samps &= ~min_per_mask;
1602 if((samps & min_per_mask) != 0)
1603 samps += min_per;
1604 }
1605 else
1606 samps = min_per;
1607
1608 if(samps < nsamp)
1609 nsamp = samps;
1610
1611 }
1612
1613 if(ci.doInterp && cl)
1614 _controls[k].val = cl->interpolate(MusEGlobal::audio->isPlaying() ? slice_frame : pos, ci);
1615 else
1616 _controls[k].val = ci.sVal;
1617
1618 #ifdef DSSI_DEBUG_PROCESS
1619 fprintf(stderr, "DssiSynthIF::getData k:%lu sample:%lu frame:%lu ci.eFrame:%d nsamp:%lu \n", k, sample, frame, ci.eFrame, nsamp);
1620 #endif
1621
1622 }
1623 }
1624
1625 #ifdef DSSI_DEBUG_PROCESS
1626 fprintf(stderr, "DssiSynthIF::getData sample:%lu nsamp:%lu\n", sample, nsamp);
1627 #endif
1628
1629 bool found = false;
1630 unsigned long frame = 0;
1631 unsigned long index = 0;
1632 unsigned long evframe;
1633 // Get all control ring buffer items valid for this time period...
1634 while(!_controlFifo.isEmpty())
1635 {
1636 const ControlEvent& v = _controlFifo.peek();
1637 // The events happened in the last period or even before that. Shift into this period with + n. This will sync with audio.
1638 // If the events happened even before current frame - n, make sure they are counted immediately as zero-frame.
1639 evframe = (syncFrame > v.frame + nframes) ? 0 : v.frame - syncFrame + nframes;
1640
1641 #ifdef DSSI_DEBUG
1642 fprintf(stderr, "DssiSynthIF::getData found:%d evframe:%lu frame:%lu event frame:%lu idx:%lu val:%f unique:%d\n",
1643 found, evframe, frame, v.frame, v.idx, v.value, v.unique);
1644 #endif
1645
1646 // Protection. Observed this condition. Why? Supposed to be linear timestamps.
1647 if(found && evframe < frame)
1648 {
1649 fprintf(stderr,
1650 "DssiSynthIF::getData *** Error: Event out of order: evframe:%lu < frame:%lu idx:%lu val:%f unique:%d syncFrame:%lu nframes:%u v.frame:%lu\n",
1651 evframe, frame, v.idx, v.value, v.unique, syncFrame, nframes, v.frame);
1652
1653 // No choice but to ignore it.
1654 _controlFifo.remove(); // Done with the ring buffer's item. Remove it.
1655 continue;
1656 }
1657
1658 if(evframe >= nframes // Next events are for a later period.
1659 || (!usefixedrate && !found && !v.unique && (evframe - sample >= nsamp)) // Next events are for a later run in this period. (Autom took prio.)
1660 || (found && !v.unique && (evframe - sample >= min_per)) // Eat up events within minimum slice - they're too close.
1661 || (usefixedrate && found && v.unique && v.idx == index)) // Special for dssi-vst: Fixed rate and must reply to all.
1662 break;
1663
1664 if(v.idx >= in_ctrls) // Sanity check.
1665 {
1666 _controlFifo.remove(); // Done with the ring buffer's item. Remove it.
1667 break;
1668 }
1669
1670 found = true;
1671 frame = evframe;
1672 index = v.idx;
1673
1674 if(ports == 0) // Don't bother if not 'running'.
1675 _controls[v.idx].val = v.value; // Might as well at least update these.
1676 else
1677 {
1678 CtrlInterpolate* ci = &_controls[v.idx].interp;
1679 // Tell it to stop the current ramp at this frame, when it does stop, set this value:
1680 ci->eFrame = frame;
1681 ci->eFrameValid = true;
1682 ci->eVal = v.value;
1683 ci->eStop = true;
1684 }
1685
1686 // Need to update the automation value, otherwise it overwrites later with the last automation value.
1687 if(plug_id != -1)
1688 synti->setPluginCtrlVal(genACnum(plug_id, v.idx), v.value);
1689
1690 _controlFifo.remove(); // Done with the ring buffer's item. Remove it.
1691 }
1692
1693 if(found && !usefixedrate) // If a control FIFO item was found, takes priority over automation controller stream.
1694 nsamp = frame - sample;
1695
1696 if(sample + nsamp > nframes) // Safety check.
1697 nsamp = nframes - sample;
1698
1699 // TODO: Don't allow zero-length runs. This could/should be checked in the control loop instead.
1700 // Note this means it is still possible to get stuck in the top loop (at least for a while).
1701 if(nsamp != 0)
1702 {
1703 unsigned long nevents = 0;
1704 // Get the state of the stop flag.
1705 const bool do_stop = synti->stopFlag();
1706
1707 MidiPlayEvent buf_ev;
1708
1709 // Transfer the user lock-free buffer events to the user sorted multi-set.
1710 // False = don't use the size snapshot, but update it.
1711 const unsigned int usr_buf_sz = synti->eventBuffers(MidiDevice::UserBuffer)->getSize(false);
1712 for(unsigned int i = 0; i < usr_buf_sz; ++i)
1713 {
1714 if(synti->eventBuffers(MidiDevice::UserBuffer)->get(buf_ev))
1715 synti->_outUserEvents.insert(buf_ev);
1716 }
1717
1718 // Transfer the playback lock-free buffer events to the playback sorted multi-set.
1719 const unsigned int pb_buf_sz = synti->eventBuffers(MidiDevice::PlaybackBuffer)->getSize(false);
1720 for(unsigned int i = 0; i < pb_buf_sz; ++i)
1721 {
1722 // Are we stopping? Just remove the item.
1723 if(do_stop)
1724 synti->eventBuffers(MidiDevice::PlaybackBuffer)->remove();
1725 // Otherwise get the item.
1726 else if(synti->eventBuffers(MidiDevice::PlaybackBuffer)->get(buf_ev))
1727 synti->_outPlaybackEvents.insert(buf_ev);
1728 }
1729
1730 // Are we stopping?
1731 if(do_stop)
1732 {
1733 // Transport has stopped, purge ALL further scheduled playback events now.
1734 synti->_outPlaybackEvents.clear();
1735 // Reset the flag.
1736 synti->setStopFlag(false);
1737 }
1738
1739 // Count how many events we need.
1740 for(ciMPEvent impe = synti->_outPlaybackEvents.begin(); impe != synti->_outPlaybackEvents.end(); ++impe)
1741 {
1742 const MidiPlayEvent& e = *impe;
1743 if(e.time() >= (syncFrame + sample + nsamp))
1744 break;
1745 ++nevents;
1746 }
1747 for(ciMPEvent impe = synti->_outUserEvents.begin(); impe != synti->_outUserEvents.end(); ++impe)
1748 {
1749 const MidiPlayEvent& e = *impe;
1750 if(e.time() >= (syncFrame + sample + nsamp))
1751 break;
1752 ++nevents;
1753 }
1754
1755 snd_seq_event_t events[nevents];
1756
1757 iMPEvent impe_pb = synti->_outPlaybackEvents.begin();
1758 iMPEvent impe_us = synti->_outUserEvents.begin();
1759 bool using_pb;
1760
1761 unsigned long event_counter = 0;
1762 while(1)
1763 {
1764 if(impe_pb != synti->_outPlaybackEvents.end() && impe_us != synti->_outUserEvents.end())
1765 using_pb = *impe_pb < *impe_us;
1766 else if(impe_pb != synti->_outPlaybackEvents.end())
1767 using_pb = true;
1768 else if(impe_us != synti->_outUserEvents.end())
1769 using_pb = false;
1770 else break;
1771
1772 const MidiPlayEvent& e = using_pb ? *impe_pb : *impe_us;
1773
1774 #ifdef DSSI_DEBUG
1775 fprintf(stderr, "DssiSynthIF::getData eventFifos event time:%d\n", e.time());
1776 #endif
1777
1778 if(e.time() >= (syncFrame + sample + nsamp))
1779 break;
1780
1781 if(ports != 0) // Don't bother if not 'running'.
1782 {
1783 // Returns false if the event was not filled. It was handled, but some other way.
1784 if(processEvent(e, &events[event_counter]))
1785 {
1786 // Time-stamp the event.
1787 unsigned int ft = (e.time() < syncFrame) ? 0 : e.time() - syncFrame;
1788 ft = (ft < sample) ? 0 : ft - sample;
1789 if (ft >= nsamp)
1790 {
1791 fprintf(stderr, "DssiSynthIF::getData: eventFifos event time:%d out of range. pos:%d syncFrame:%lu ft:%u sample:%lu nsamp:%lu\n",
1792 e.time(), pos, syncFrame, ft, sample, nsamp);
1793 ft = nsamp - 1;
1794 }
1795 // "Each event is timestamped relative to the start of the block, (mis)using the ALSA "tick time" field as a frame count.
1796 // The host is responsible for ensuring that events with differing timestamps are already ordered by time." - From dssi.h
1797 events[event_counter].time.tick = ft;
1798
1799 ++event_counter;
1800 }
1801 }
1802
1803 // Done with ring buffer's event. Remove it.
1804 // C++11.
1805 if(using_pb)
1806 impe_pb = synti->_outPlaybackEvents.erase(impe_pb);
1807 else
1808 impe_us = synti->_outUserEvents.erase(impe_us);
1809 }
1810
1811 if(event_counter < nevents)
1812 nevents = event_counter;
1813
1814 #ifdef DSSI_DEBUG_PROCESS
1815 fprintf(stderr, "DssiSynthIF::getData: Connecting and running. sample:%lu nsamp:%lu nevents:%lu\n", sample, nsamp, nevents);
1816 #endif
1817
1818 if(ports != 0) // Don't bother if not 'running'.
1819 {
1820 // Connect the given buffers directly to the ports, up to a max of synth ports.
1821 for(unsigned long k = 0; k < nop; ++k)
1822 descr->connect_port(_handle, _synth->oIdx[k], buffer[k] + sample);
1823 // Connect the remaining ports to some local buffers (not used yet).
1824 for(unsigned long k = nop; k < out_ports; ++k)
1825 descr->connect_port(_handle, _synth->oIdx[k], _audioOutBuffers[k] + sample);
1826 // Connect all inputs either to some local buffers, or a silence buffer.
1827 for(unsigned long k = 0; k < in_ports; ++k)
1828 {
1829 if(used_in_chan_array[k])
1830 descr->connect_port(_handle, _synth->iIdx[k], _audioInBuffers[k] + sample);
1831 else
1832 descr->connect_port(_handle, _synth->iIdx[k], _audioInSilenceBuf + sample);
1833 }
1834
1835 // Run the synth for a period of time. This processes events and gets/fills our local buffers...
1836 if(_synth->dssi->run_synth)
1837 {
1838 _synth->dssi->run_synth(_handle, nsamp, events, nevents);
1839 }
1840 else if (_synth->dssi->run_multiple_synths)
1841 {
1842 snd_seq_event_t* ev = events;
1843 _synth->dssi->run_multiple_synths(1, &_handle, nsamp, &ev, &nevents);
1844 }
1845 // TIP: Until we add programs to plugins, uncomment these four checks to load dssi effects as synths, in order to have programs.
1846 //else
1847 //if(synth->dssi->LADSPA_Plugin->run)
1848 //{
1849 // synth->dssi->LADSPA_Plugin->run(handle, nsamp);
1850 //}
1851 }
1852
1853 sample += nsamp;
1854 }
1855
1856 ++cur_slice; // Slice is done. Moving on to any next slice now...
1857 }
1858
1859 return true;
1860 }
1861
1862 //---------------------------------------------------------
1863 // incInstances
1864 //---------------------------------------------------------
1865
incInstances(int val)1866 void DssiSynth::incInstances(int val)
1867 {
1868 _instances += val;
1869 if (_instances == 0)
1870 {
1871 if (handle)
1872 {
1873 #ifdef DSSI_DEBUG
1874 fprintf(stderr, "DssiSynth::incInstances no more instances, closing library\n");
1875 #endif
1876
1877 dlclose(handle);
1878 }
1879 handle = 0;
1880 dssi = NULL;
1881 df = NULL;
1882 iIdx.clear();
1883 oIdx.clear();
1884 rpIdx.clear();
1885 midiCtl2PortMap.clear();
1886 port2MidiCtlMap.clear();
1887 }
1888 }
1889
1890 //---------------------------------------------------------
1891 // guiHeartBeat
1892 //---------------------------------------------------------
1893
guiHeartBeat()1894 void DssiSynthIF::guiHeartBeat()
1895 {
1896 #ifdef OSC_SUPPORT
1897 int chn = 0; // TODO: Channel?
1898 int hb, lb, pr;
1899 synti->currentProg(chn, &pr, &lb, &hb);
1900 if(hb > 127) // Map "dont care" to 0
1901 hb = 0;
1902 if(lb > 127)
1903 lb = 0;
1904 if(pr > 127)
1905 pr = 0;
1906 // Update the gui's program if needed.
1907 _oscif.oscSendProgram(pr, (hb << 8) + lb);
1908
1909 // Update the gui's controls if needed.
1910 unsigned long ports = _synth->_controlInPorts;
1911
1912 for(unsigned long i = 0; i < ports; ++i)
1913 _oscif.oscSendControl(_controls[i].idx, _controls[i].val);
1914 #endif
1915 }
1916
1917 #ifdef OSC_SUPPORT
1918 //---------------------------------------------------------
1919 // oscUpdate
1920 //---------------------------------------------------------
1921
oscUpdate()1922 int DssiSynthIF::oscUpdate()
1923 {
1924 // Send project directory.
1925 _oscif.oscSendConfigure(DSSI_PROJECT_DIRECTORY_KEY, MusEGlobal::museProject.toLatin1().constData()); // MusEGlobal::song->projectPath()
1926
1927 // Send current string configuration parameters.
1928 int i = 0;
1929 for(ciStringParamMap r = synti->_initConfig._stringParamMap.begin(); r != synti->_initConfig._stringParamMap.end(); ++r)
1930 {
1931 _oscif.oscSendConfigure(r->first.c_str(), r->second.c_str());
1932 // Avoid overloading the GUI if there are lots and lots of params.
1933 if((i+1) % 50 == 0)
1934 usleep(300000);
1935 ++i;
1936 }
1937
1938 // Send current bank and program.
1939 int chn = 0; // TODO: Channel?
1940 int hb, lb, pr;
1941 synti->currentProg(chn, &pr, &lb, &hb);
1942 if(hb > 127) // Map "dont care" to 0
1943 hb = 0;
1944 if(lb > 127)
1945 lb = 0;
1946 if(pr > 127)
1947 pr = 0;
1948 _oscif.oscSendProgram(pr, (hb << 8) + lb, true /*force*/);
1949
1950 // Send current control values.
1951 unsigned long ports = _synth->_controlInPorts;
1952 for(unsigned long i = 0; i < ports; ++i)
1953 {
1954 _oscif.oscSendControl(_controls[i].idx, _controls[i].val, true /*force*/);
1955 // Avoid overloading the GUI if there are lots and lots of ports.
1956 if((i+1) % 50 == 0)
1957 usleep(300000);
1958 }
1959
1960 return 0;
1961 }
1962
1963 //---------------------------------------------------------
1964 // oscProgram
1965 //---------------------------------------------------------
1966
oscProgram(unsigned long program,unsigned long bank)1967 int DssiSynthIF::oscProgram(unsigned long program, unsigned long bank)
1968 {
1969 int ch = 0; // TODO: ??
1970 int port = synti->midiPort();
1971
1972 // 16384 banks arranged as 128 hi and lo banks each with up to the first 128 programs supported.
1973 int hb = bank >> 8;
1974 int lb = bank & 0xff;
1975 if(hb > 127 || lb > 127 || program > 127)
1976 return 0;
1977 hb &= 0x7f;
1978 lb &= 0x7f;
1979
1980 synti->setCurrentProg(ch, program, lb, hb);
1981
1982 if(port != -1)
1983 {
1984 // Synths are not allowed to receive ME_PROGRAM, CTRL_HBANK, or CTRL_LBANK alone anymore.
1985 const MidiPlayEvent event(0, port, ch, ME_CONTROLLER, CTRL_PROGRAM, (hb << 16) | (lb << 8) | program);
1986
1987 #ifdef DSSI_DEBUG
1988 fprintf(stderr, "DssiSynthIF::oscProgram midi event chn:%d a:%d b:%d\n", event.channel(), event.dataA(), event.dataB());
1989 #endif
1990
1991 MusEGlobal::midiPorts[port].putEvent(event);
1992 }
1993
1994 return 0;
1995 }
1996
1997 //---------------------------------------------------------
1998 // oscControl
1999 //---------------------------------------------------------
2000
oscControl(unsigned long port,float value)2001 int DssiSynthIF::oscControl(unsigned long port, float value)
2002 {
2003 #ifdef DSSI_DEBUG
2004 printf("DssiSynthIF::oscControl received oscControl port:%lu val:%f\n", port, value);
2005 #endif
2006
2007 if(port >= _synth->rpIdx.size())
2008 {
2009 fprintf(stderr, "DssiSynthIF::oscControl: port number:%lu is out of range of index list size:%zd\n", port, _synth->rpIdx.size());
2010 return 0;
2011 }
2012
2013 // Convert from DSSI port number to control input port index.
2014 unsigned long cport = _synth->rpIdx[port];
2015
2016 if((int)cport == -1)
2017 {
2018 fprintf(stderr, "DssiSynthIF::oscControl: port number:%lu is not a control input\n", port);
2019 return 0;
2020 }
2021
2022 // Record automation:
2023 // Take care of this immediately, because we don't want the silly delay associated with
2024 // processing the fifo one-at-a-time in the apply().
2025 // NOTE: With some vsts we don't receive control events until the user RELEASES a control.
2026 // So the events all arrive at once when the user releases a control.
2027 // That makes this pretty useless... But what the heck...
2028 if(id() != -1)
2029 {
2030 unsigned long pid = genACnum(id(), cport);
2031 synti->recordAutomation(pid, value);
2032 }
2033
2034 // DELETETHIS????: is the below still correct? of so, then keep it of course!
2035 // p3.3.39 Set the DSSI control input port's value.
2036 // Observations: With a native DSSI synth like LessTrivialSynth, the native GUI's controls do not change the sound at all
2037 // ie. they don't update the DSSI control port values themselves.
2038 // Hence in response to the call to this oscControl, sent by the native GUI, it is required to that here.
2039 /// controls[cport].val = value; DELETETHIS
2040 // DSSI-VST synths however, unlike DSSI synths, DO change their OWN sound in response to their gui controls.
2041 // AND this function is called.
2042 // Despite the descrepency we are STILL required to update the DSSI control port values here
2043 // because dssi-vst is WAITING FOR A RESPONSE. (A CHANGE in the control port value).
2044 // It will output something like "...4 events expected..." and count that number down as 4 actual control port value CHANGES
2045 // are done here in response. Normally it says "...0 events expected..." when MusE is the one doing the DSSI control changes.
2046 //
2047 // NOTE: NOTE: This line in RemoteVSTServer::setParameter(int p, float v) in dssi-vst-server.cpp :
2048 //
2049 // " if (tv.tv_sec > m_lastGuiComms.tv_sec + 10) "
2050 //
2051 // explains an observation that after ten seconds, the server automatically clears the expected number to 0.
2052 // You can't send any 'new' values until either you a): send all the expected events or b): wait ten seconds.
2053 // (Because the server simply ignores the 'expected' messages.)
2054 //
2055 // Well, at least here are the fifos. Try this ...
2056
2057 // Schedules a timed control change:
2058 ControlEvent ce;
2059 ce.unique = _synth->isDssiVst(); // Special for messages from vst gui to host - requires processing every message.
2060 ce.fromGui = true; // It came from the plugin's own GUI.
2061 ce.idx = cport;
2062 ce.value = value;
2063 // Don't use timestamp(), because it's circular, which is making it impossible to deal
2064 // with 'modulo' events which slip in 'under the wire' before processing the ring buffers.
2065 ce.frame = MusEGlobal::audio->curFrame();
2066 if(_controlFifo.put(ce))
2067 fprintf(stderr, "DssiSynthIF::oscControl: fifo overflow: in control number:%lu\n", cport);
2068
2069 enableController(cport, false); //TODO maybe re-enable the ctrl soon?
2070
2071 return 0;
2072 }
2073
2074 //---------------------------------------------------------
2075 // oscMidi
2076 //---------------------------------------------------------
2077
oscMidi(int a,int b,int c)2078 int DssiSynthIF::oscMidi(int a, int b, int c)
2079 {
2080 // From the DSSI RFC document:
2081 // <base path>/midi
2082 // "Send an arbitrary MIDI event to the plugin. Takes a four-byte MIDI string.
2083 // This is expected to be used for note data generated from a test panel on the UI,
2084 // for example. It should not be used for program or controller changes, sysex data, etc.
2085 // A host should feel free to drop any values it doesn't wish to pass on.
2086 // No guarantees are provided about timing accuracy, etc, of the MIDI communication."
2087
2088 // From dssi.h:
2089 // " A host must not attempt to switch notes off by sending
2090 // zero-velocity NOTE_ON events. It should always send true
2091 // NOTE_OFFs. It is the host's responsibility to remap events in
2092 // cases where an external MIDI source has sent it zero-velocity
2093 // NOTE_ONs."
2094
2095 int type = a & 0xf0;
2096 if (type == ME_NOTEON && c == 0) {
2097 type = ME_NOTEOFF;
2098 c = 64;
2099 }
2100
2101 const int channel = a & 0x0f;
2102
2103 const int port = synti->midiPort();
2104
2105 if(port != -1)
2106 {
2107 // Time-stamp the event.
2108 MidiPlayEvent event(MusEGlobal::audio->curFrame(), port, channel, type, b, c);
2109
2110 #ifdef DSSI_DEBUG
2111 printf("DssiSynthIF::oscMidi midi event port:%d type:%d chn:%d a:%d b:%d\n", event.port(), event.type(), event.channel(), event.dataA(), event.dataB());
2112 #endif
2113
2114 // Just in case someone decides to send controllers, sysex, or stuff
2115 // OTHER than "test notes", contrary to the rules...
2116 // Since this is a thread other than audio or gui, it may not be safe to
2117 // even ask whether a controller exists, so MidiPort::putEvent or putHwCtrlEvent
2118 // would not be safe here. Ask the gui to do it for us.
2119 // Is it a controller message? Send the message to the gui.
2120 //if(event.translateCtrlNum() >= 0)
2121 MusEGlobal::song->putIpcInEvent(event);
2122
2123 // Send the message to the device.
2124 if(MidiDevice* md = MusEGlobal::midiPorts[port].device())
2125 md->putEvent(event, MidiDevice::Late);
2126 }
2127
2128 return 0;
2129 }
2130
2131 //---------------------------------------------------------
2132 // oscConfigure
2133 //---------------------------------------------------------
2134
oscConfigure(const char * key,const char * value)2135 int DssiSynthIF::oscConfigure(const char *key, const char *value)
2136 {
2137 // "The host has the option to remember the set of (key,value)
2138 // pairs associated with a particular instance, so that if it
2139 // wants to restore the "same" instance on another occasion it can
2140 // just call configure() on it for each of those pairs and so
2141 // restore state without any input from a GUI."
2142
2143 #ifdef DSSI_DEBUG
2144 printf("DssiSynthIF::oscConfigure synth name:%s key:%s value:%s\n", synti->name().toLatin1().constData(), key, value);
2145 #endif
2146
2147 // Add or modify the configuration map item.
2148 synti->_initConfig._stringParamMap.set(key, value);
2149
2150 if (!strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX,
2151 strlen(DSSI_RESERVED_CONFIGURE_PREFIX))) {
2152 fprintf(stderr, "MusE: OSC: UI for plugin '%s' attempted to use reserved configure key \"%s\", ignoring\n",
2153 synti->name().toLatin1().constData(), key);
2154 return 0;
2155 }
2156
2157 if (!_synth->dssi->configure)
2158 return 0;
2159
2160 char* message = _synth->dssi->configure(_handle, key, value);
2161 if (message) {
2162 printf("MusE: on configure '%s' '%s', plugin '%s' returned error '%s'\n",
2163 key, value, synti->name().toLatin1().constData(), message);
2164 free(message);
2165 }
2166
2167 // DELETETHIS 6 ???
2168 // "also call back on UIs for plugins other than the one
2169 // that requested this:"
2170 // if (n != instance->number && instances[n].uiTarget) {
2171 // lo_send(instances[n].uiTarget,
2172 // instances[n].ui_osc_configure_path, "ss", key, value);
2173 // }
2174
2175 // configure invalidates bank and program information, so
2176 // we should do this again now:
2177 queryPrograms();
2178 return 0;
2179 }
2180 #endif // OSC_SUPPORT
2181
2182 //---------------------------------------------------------
2183 // queryPrograms
2184 //---------------------------------------------------------
2185
queryPrograms()2186 void DssiSynthIF::queryPrograms()
2187 {
2188 for (std::vector<DSSI_Program_Descriptor>::const_iterator i = programs.begin();
2189 i != programs.end(); ++i) {
2190 free((void*)(i->Name));
2191 }
2192 programs.clear();
2193
2194 if (!_synth->dssi->get_program)
2195 return;
2196
2197 for (int i = 0;; ++i) {
2198 const DSSI_Program_Descriptor* pd = _synth->dssi->get_program(_handle, i);
2199 if (pd == 0)
2200 break;
2201
2202 // 16384 banks arranged as 128 hi and lo banks each with up to the first 128 programs supported.
2203 if((pd->Bank >> 8) > 127 ||
2204 (pd->Bank & 0xff) > 127 ||
2205 pd->Program > 127)
2206 continue;
2207
2208 DSSI_Program_Descriptor d;
2209 d.Name = strdup(pd->Name);
2210 d.Program = pd->Program;
2211 d.Bank = pd->Bank;
2212 programs.push_back(d);
2213 }
2214 }
2215
doSelectProgram(LADSPA_Handle handle,int bankH,int bankL,int prog)2216 void DssiSynthIF::doSelectProgram(LADSPA_Handle handle, int bankH, int bankL, int prog)
2217 {
2218 if(bankH > 127) // Map "dont care" to 0
2219 bankH = 0;
2220 if(bankL > 127)
2221 bankL = 0;
2222 if(prog > 127)
2223 prog = 0;
2224
2225 const int bank = (bankH << 8) | bankL;
2226
2227 const DSSI_Descriptor* dssi = _synth->dssi;
2228 dssi->select_program(handle, bank, prog);
2229
2230 // Need to update the automation value, otherwise it overwrites later with the last automation value.
2231 // "A plugin is permitted to re-write the values of its input control ports when select_program is called.
2232 // The host should re-read the input control port values and update its own records appropriately.
2233 // (This is the only circumstance in which a DSSI plugin is allowed to modify its own input ports.)" From dssi.h
2234 if(id() != -1)
2235 {
2236 for(unsigned long k = 0; k < _synth->_controlInPorts; ++k)
2237 {
2238 // We're in the audio thread context: no need to send a message, just modify directly.
2239 synti->setPluginCtrlVal(genACnum(id(), k), _controls[k].val);
2240 }
2241 }
2242 }
2243
2244 //---------------------------------------------------------
2245 // getPatchName
2246 //---------------------------------------------------------
2247
getPatchName(int,int prog,bool) const2248 QString DssiSynthIF::getPatchName(int /*chan*/, int prog, bool /*drum*/) const
2249 {
2250 unsigned program = prog & 0xff;
2251 unsigned lbank = (prog >> 8) & 0xff;
2252 unsigned hbank = (prog >> 16) & 0xff;
2253
2254 if (program > 127) // Map "dont care" to 0
2255 program = 0;
2256 if (lbank > 127)
2257 lbank = 0;
2258 if (hbank > 127)
2259 hbank = 0;
2260 const unsigned bank = (hbank << 8) + lbank;
2261
2262 for (std::vector<DSSI_Program_Descriptor>::const_iterator i = programs.begin();
2263 i != programs.end(); ++i) {
2264 if (i->Bank == bank && i->Program ==program)
2265 return i->Name;
2266 }
2267 return "?";
2268 }
2269
2270 //---------------------------------------------------------
2271 // populatePatchPopup
2272 //---------------------------------------------------------
2273
populatePatchPopup(MusEGui::PopupMenu * menu,int,bool)2274 void DssiSynthIF::populatePatchPopup(MusEGui::PopupMenu* menu, int /*ch*/, bool /*drum*/)
2275 {
2276 // The plugin can change the programs, patches etc.
2277 // So make sure we're up to date by calling queryPrograms.
2278 queryPrograms();
2279
2280 menu->clear();
2281
2282 for (std::vector<DSSI_Program_Descriptor>::const_iterator i = programs.begin();
2283 i != programs.end(); ++i) {
2284 // 16384 banks arranged as 128 hi and lo banks each with up to the first 128 programs supported.
2285 int hb = i->Bank >> 8;
2286 int lb = i->Bank & 0xff;
2287 if(hb > 127 || lb > 127 || i->Program > 127)
2288 continue;
2289 hb &= 0x7f;
2290 lb &= 0x7f;
2291
2292 QString astr;
2293 astr += QString::number(hb + 1) + QString(":");
2294 astr += QString::number(lb + 1) + QString(":");
2295 astr += QString::number(i->Program + 1);
2296 astr += QString(" ");
2297 astr += QString(i->Name);
2298
2299 QAction *act = menu->addAction(astr);
2300 act->setData((hb << 16) | (lb << 8) | (int)i->Program);
2301 }
2302 }
2303
getControllerInfo(int id,QString * name,int * ctrl,int * min,int * max,int * initval)2304 int DssiSynthIF::getControllerInfo(int id, QString* name, int* ctrl, int* min, int* max, int* initval)
2305 {
2306 int controlPorts = _synth->_controlInPorts;
2307 if(id == controlPorts || id == controlPorts + 1)
2308 {
2309 //
2310 // It is unknown at this point whether or not a synth recognizes aftertouch and poly aftertouch
2311 // (channel and key pressure) midi messages, so add support for them now (as controllers).
2312 //
2313 if(id == controlPorts)
2314 *ctrl = CTRL_POLYAFTER;
2315 else if(id == controlPorts + 1)
2316 *ctrl = CTRL_AFTERTOUCH;
2317 *min = 0;
2318 *max = 127;
2319 *initval = CTRL_VAL_UNKNOWN;
2320 *name = midiCtrlName(*ctrl);
2321 return ++id;
2322 }
2323 else if(id >= controlPorts + 2)
2324 return 0;
2325
2326 const DSSI_Descriptor* dssi = _synth->dssi;
2327 const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
2328
2329 unsigned long i = _controls[id].idx;
2330
2331 #ifdef DSSI_DEBUG
2332 printf("DssiSynthIF::getControllerInfo control port:%d port idx:%lu name:%s\n", id, i, ld->PortNames[i]);
2333 #endif
2334
2335 int ctlnum = DSSI_NONE;
2336 if(dssi->get_midi_controller_for_port)
2337 ctlnum = dssi->get_midi_controller_for_port(_handle, i);
2338
2339
2340 // No controller number? Give it one.
2341 if(ctlnum == DSSI_NONE)
2342 {
2343 // Simple but flawed solution: Start them at 0x60000 + 0x2000 = 0x62000. Max NRPN number is 0x3fff.
2344 ctlnum = CTRL_NRPN14_OFFSET + 0x2000 + id;
2345 }
2346 else
2347 {
2348 #ifdef DSSI_DEBUG
2349 printf("DssiSynthIF::getControllerInfo ctlnum:%d\n", ctlnum);
2350 #endif
2351
2352 int c = ctlnum;
2353 // Can be both CC and NRPN! Prefer CC over NRPN.
2354 if(DSSI_IS_CC(ctlnum))
2355 {
2356 #ifdef DSSI_DEBUG
2357 printf("DssiSynthIF::getControllerInfo is CC control\n");
2358 #endif
2359
2360 ctlnum = DSSI_CC_NUMBER(c);
2361
2362 #ifdef DSSI_DEBUG
2363 if(DSSI_IS_NRPN(ctlnum))
2364 printf("DssiSynthIF::getControllerInfo is also NRPN control. Using CC.\n");
2365 #endif
2366 }
2367 else
2368 if(DSSI_IS_NRPN(ctlnum))
2369 {
2370 #ifdef DSSI_DEBUG
2371 printf("DssiSynthIF::getControllerInfo is NRPN control\n");
2372 #endif
2373
2374 ctlnum = DSSI_NRPN_NUMBER(c) + CTRL_NRPN14_OFFSET;
2375 }
2376 }
2377
2378 int def = CTRL_VAL_UNKNOWN;
2379 if(ladspa2MidiControlValues(ld, i, ctlnum, min, max, &def))
2380 *initval = def;
2381 else
2382 *initval = CTRL_VAL_UNKNOWN;
2383
2384 #ifdef DSSI_DEBUG
2385 printf("DssiSynthIF::getControllerInfo passed ctlnum:%d min:%d max:%d initval:%d\n", ctlnum, *min, *max, *initval);
2386 #endif
2387
2388 *ctrl = ctlnum;
2389 *name = QString(ld->PortNames[i]);
2390 return ++id;
2391 }
2392
channels() const2393 int DssiSynthIF::channels() const
2394 {
2395 return ((int)_synth->_outports) > MusECore::MAX_CHANNELS ? MusECore::MAX_CHANNELS : ((int)_synth->_outports) ;
2396 }
2397
totalOutChannels() const2398 int DssiSynthIF::totalOutChannels() const
2399 {
2400 return _synth->_outports;
2401 }
2402
totalInChannels() const2403 int DssiSynthIF::totalInChannels() const
2404 {
2405 return _synth->_inports;
2406 }
2407
deactivate3()2408 void DssiSynthIF::deactivate3()
2409 {
2410 deactivate();
2411 }
2412
2413
2414 //--------------------------------
2415 // Methods for PluginIBase:
2416 //--------------------------------
2417
pluginID()2418 unsigned long DssiSynthIF::pluginID() { return (_synth && _synth->dssi) ? _synth->dssi->LADSPA_Plugin->UniqueID : 0; }
id()2419 int DssiSynthIF::id() { return MusECore::MAX_PLUGINS; } // Set for special block reserved for dssi synth. p4.0.20
pluginLabel() const2420 QString DssiSynthIF::pluginLabel() const { return (_synth && _synth->dssi) ? QString(_synth->dssi->LADSPA_Plugin->Label) : QString(); }
lib() const2421 QString DssiSynthIF::lib() const { return _synth ? _synth->completeBaseName() : QString(); }
uri() const2422 QString DssiSynthIF::uri() const { return _synth ? _synth->uri() : QString(); }
dirPath() const2423 QString DssiSynthIF::dirPath() const { return _synth ? _synth->absolutePath() : QString(); }
fileName() const2424 QString DssiSynthIF::fileName() const { return _synth ? _synth->fileName() : QString(); }
enableController(unsigned long i,bool v)2425 void DssiSynthIF::enableController(unsigned long i, bool v) { _controls[i].enCtrl = v; }
controllerEnabled(unsigned long i) const2426 bool DssiSynthIF::controllerEnabled(unsigned long i) const { return _controls[i].enCtrl; }
enableAllControllers(bool v)2427 void DssiSynthIF::enableAllControllers(bool v)
2428 {
2429 if(!_synth)
2430 return;
2431 for(unsigned long i = 0; i < _synth->_controlInPorts; ++i)
2432 _controls[i].enCtrl = v;
2433 }
updateControllers()2434 void DssiSynthIF::updateControllers() { }
activate()2435 void DssiSynthIF::activate()
2436 {
2437 if(_synth && _synth->dssi && _synth->dssi->LADSPA_Plugin && _synth->dssi->LADSPA_Plugin->activate)
2438 //for (int i = 0; i < instances; ++i)
2439 // _plugin->activate(handle[i]);
2440 _synth->dssi->LADSPA_Plugin->activate(_handle);
2441
2442 // REMOVE Tim. Or keep? From PluginI::activate().
2443 // if (initControlValues) {
2444 // for (unsigned long i = 0; i < controlPorts; ++i) {
2445 // controls[i].val = controls[i].tmpVal;
2446 // }
2447 // }
2448 // else {
2449 // // get initial control values from plugin
2450 // for (unsigned long i = 0; i < controlPorts; ++i) {
2451 // controls[i].tmpVal = controls[i].val;
2452 // }
2453 // }
2454 }
deactivate()2455 void DssiSynthIF::deactivate()
2456 {
2457 if(!_synth || !_synth->dssi || !_synth->dssi->LADSPA_Plugin ||!_synth->dssi->LADSPA_Plugin->deactivate)
2458 return;
2459 //for (int i = 0; i < instances; ++i)
2460 // synth->dssi->LADSPA_Plugin->deactivate(handle[i]);
2461 _synth->dssi->LADSPA_Plugin->deactivate(_handle);
2462 }
2463
parameters() const2464 unsigned long DssiSynthIF::parameters() const { return _synth ? _synth->_controlInPorts : 0; }
parametersOut() const2465 unsigned long DssiSynthIF::parametersOut() const { return _synth ? _synth->_controlOutPorts : 0; }
setParam(unsigned long i,double val)2466 void DssiSynthIF::setParam(unsigned long i, double val) { setParameter(i, val); }
param(unsigned long i) const2467 double DssiSynthIF::param(unsigned long i) const { return getParameter(i); }
paramOut(unsigned long i) const2468 double DssiSynthIF::paramOut(unsigned long i) const { return getParameterOut(i); }
paramName(unsigned long i)2469 const char* DssiSynthIF::paramName(unsigned long i) { return (_synth && _synth->dssi) ? _synth->dssi->LADSPA_Plugin->PortNames[_controls[i].idx] : 0; }
paramOutName(unsigned long i)2470 const char* DssiSynthIF::paramOutName(unsigned long i) { return (_synth && _synth->dssi) ? _synth->dssi->LADSPA_Plugin->PortNames[_controlsOut[i].idx] : 0; }
range(unsigned long i)2471 LADSPA_PortRangeHint DssiSynthIF::range(unsigned long i) { return _synth->dssi->LADSPA_Plugin->PortRangeHints[_controls[i].idx]; }
rangeOut(unsigned long i)2472 LADSPA_PortRangeHint DssiSynthIF::rangeOut(unsigned long i) { return _synth->dssi->LADSPA_Plugin->PortRangeHints[_controlsOut[i].idx]; }
ctrlValueType(unsigned long i) const2473 CtrlValueType DssiSynthIF::ctrlValueType(unsigned long i) const { return ladspaCtrlValueType(_synth->dssi->LADSPA_Plugin, _controls[i].idx); }
ctrlMode(unsigned long i) const2474 CtrlList::Mode DssiSynthIF::ctrlMode(unsigned long i) const { return ladspaCtrlMode(_synth->dssi->LADSPA_Plugin, _controls[i].idx); };
2475
2476 } // namespace MusECore
2477
2478 #else //DSSI_SUPPORT
2479 namespace MusECore {
initDSSI()2480 void initDSSI() {}
2481 }
2482 #endif
2483
2484