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