svcore  1.9
DSSIPluginInstance.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version. See the file
12  COPYING included with this distribution for more information.
13 */
14 
15 /*
16  This is a modified version of a source file from the
17  Rosegarden MIDI and audio sequencer and notation editor.
18  This file copyright 2000-2006 Chris Cannam.
19 */
20 
21 #include <iostream>
22 #include <cassert>
23 
24 #include "DSSIPluginInstance.h"
25 #include "PluginIdentifier.h"
26 #include "LADSPAPluginFactory.h"
27 
28 #include <cstdlib>
29 
30 #ifndef Q_OS_WIN32
31 #include <alloca.h>
32 #else
33 #include <memory.h>
34 #endif
35 
36 //#define DEBUG_DSSI 1
37 #define DEBUG_DSSI_PROCESS 1
38 
39 #define EVENT_BUFFER_SIZE 1023
40 
41 #ifdef DEBUG_DSSI
42 static std::ostream &operator<<(std::ostream& o, const QString &s)
43 {
44  o << s;
45  return o;
46 }
47 #endif
48 
53 std::map<LADSPA_Handle, std::set<DSSIPluginInstance::NonRTPluginThread *> > DSSIPluginInstance::m_threads;
54 
55 
57  int clientId,
58  QString identifier,
59  int position,
60  unsigned long sampleRate,
61  size_t blockSize,
62  int idealChannelCount,
63  const DSSI_Descriptor* descriptor) :
64  RealTimePluginInstance(factory, identifier),
65  m_client(clientId),
66  m_position(position),
67  m_instanceHandle(0),
68  m_descriptor(descriptor),
69  m_programCacheValid(false),
70  m_eventBuffer(EVENT_BUFFER_SIZE),
71  m_blockSize(blockSize),
72  m_idealChannelCount(idealChannelCount),
73  m_sampleRate(sampleRate),
74  m_latencyPort(0),
75  m_run(false),
76  m_bypassed(false),
77  m_grouped(false),
78  m_haveLastEventSendTime(false)
79 {
80 #ifdef DEBUG_DSSI
81  SVDEBUG << "DSSIPluginInstance::DSSIPluginInstance(" << identifier << ")"
82  << endl;
83 #endif
84 
85  init();
86 
87  m_inputBuffers = new sample_t*[m_audioPortsIn.size()];
89 
90  for (size_t i = 0; i < m_audioPortsIn.size(); ++i) {
91  m_inputBuffers[i] = new sample_t[blockSize];
92  }
93  for (size_t i = 0; i < m_outputBufferCount; ++i) {
94  m_outputBuffers[i] = new sample_t[blockSize];
95  }
96 
97  m_ownBuffers = true;
98 
100 
101  instantiate(sampleRate);
102  if (isOK()) {
103  connectPorts();
104  activate();
106  }
107 }
108 
109 std::string
111 {
112  return m_descriptor->LADSPA_Plugin->Label;
113 }
114 
115 std::string
117 {
118  return m_descriptor->LADSPA_Plugin->Name;
119 }
120 
121 std::string
123 {
124  return "";
125 }
126 
127 std::string
129 {
130  return m_descriptor->LADSPA_Plugin->Maker;
131 }
132 
133 int
135 {
136  return -1;
137 }
138 
139 std::string
141 {
142  return m_descriptor->LADSPA_Plugin->Copyright;
143 }
144 
145 DSSIPluginInstance::ParameterList
147 {
148  ParameterList list;
149  LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
150  if (!f) return list;
151 
152  for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
153 
154  ParameterDescriptor pd;
155  unsigned int pn = m_controlPortsIn[i].first;
156 
157  pd.identifier = m_descriptor->LADSPA_Plugin->PortNames[pn];
158  pd.name = pd.identifier;
159  pd.description = "";
160  pd.minValue = f->getPortMinimum(m_descriptor->LADSPA_Plugin, pn);
161  pd.maxValue = f->getPortMaximum(m_descriptor->LADSPA_Plugin, pn);
162  pd.defaultValue = f->getPortDefault(m_descriptor->LADSPA_Plugin, pn);
163 
164  float q = f->getPortQuantization(m_descriptor->LADSPA_Plugin, pn);
165  if (q == 0.0) {
166  pd.isQuantized = false;
167  } else {
168  pd.isQuantized = true;
169  pd.quantizeStep = q;
170  }
171 
172  list.push_back(pd);
173  }
174 
175  return list;
176 }
177 
178 float
179 DSSIPluginInstance::getParameter(std::string id) const
180 {
181 #ifdef DEBUG_DSSI
182  SVDEBUG << "DSSIPluginInstance::getParameter(" << id << ")" << endl;
183 #endif
184  for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
185  if (id == m_descriptor->LADSPA_Plugin->PortNames[m_controlPortsIn[i].first]) {
186 #ifdef DEBUG_DSSI
187  cerr << "Matches port " << i << endl;
188 #endif
189  float v = getParameterValue(i);
190 #ifdef DEBUG_DSSI
191  SVDEBUG << "Returning " << v << endl;
192 #endif
193  return v;
194  }
195  }
196 
197  return 0.0;
198 }
199 
200 void
201 DSSIPluginInstance::setParameter(std::string id, float value)
202 {
203 #ifdef DEBUG_DSSI
204  SVDEBUG << "DSSIPluginInstance::setParameter(" << id << ", " << value << ")" << endl;
205 #endif
206 
207  for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
208  if (id == m_descriptor->LADSPA_Plugin->PortNames[m_controlPortsIn[i].first]) {
209  setParameterValue(i, value);
210  break;
211  }
212  }
213 }
214 
215 void
217 {
218 #ifdef DEBUG_DSSI
219  SVDEBUG << "DSSIPluginInstance::init" << endl;
220 #endif
221 
222  // Discover ports numbers and identities
223  //
224  const LADSPA_Descriptor *descriptor = m_descriptor->LADSPA_Plugin;
225 
226  for (unsigned long i = 0; i < descriptor->PortCount; ++i)
227  {
228  if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[i]))
229  {
230  if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) {
231  m_audioPortsIn.push_back(i);
232  } else {
233  m_audioPortsOut.push_back(i);
234  }
235  }
236  else
237  if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i]))
238  {
239  if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) {
240 
241  LADSPA_Data *data = new LADSPA_Data(0.0);
242 
243  m_controlPortsIn.push_back(std::pair<unsigned long, LADSPA_Data*>
244  (i, data));
245 
246  m_backupControlPortsIn.push_back(0.0);
247 
248  } else {
249  LADSPA_Data *data = new LADSPA_Data(0.0);
250  m_controlPortsOut.push_back(
251  std::pair<unsigned long, LADSPA_Data*>(i, data));
252  if (!strcmp(descriptor->PortNames[i], "latency") ||
253  !strcmp(descriptor->PortNames[i], "_latency")) {
254 #ifdef DEBUG_DSSI
255  cerr << "Wooo! We have a latency port!" << endl;
256 #endif
257  m_latencyPort = data;
258  }
259  }
260  }
261 #ifdef DEBUG_DSSI
262  else
263  SVDEBUG << "DSSIPluginInstance::DSSIPluginInstance - "
264  << "unrecognised port type" << endl;
265 #endif
266  }
267 
269 }
270 
271 size_t
273 {
274  size_t latency = 0;
275 
276 #ifdef DEBUG_DSSI_PROCESS
277  SVDEBUG << "DSSIPluginInstance::getLatency(): m_latencyPort " << m_latencyPort << ", m_run " << m_run << endl;
278 #endif
279 
280  if (m_latencyPort) {
281  if (!m_run) {
282  for (size_t i = 0; i < getAudioInputCount(); ++i) {
283  for (size_t j = 0; j < m_blockSize; ++j) {
284  m_inputBuffers[i][j] = 0.f;
285  }
286  }
287  run(Vamp::RealTime::zeroTime);
288  }
289  latency = (size_t)(*m_latencyPort + 0.1);
290  }
291 
292 #ifdef DEBUG_DSSI_PROCESS
293  SVDEBUG << "DSSIPluginInstance::getLatency(): latency is " << latency << endl;
294 #endif
295 
296  return latency;
297 }
298 
299 void
301 {
302  if (m_instanceHandle != 0) {
303  deactivate();
304  activate();
305  }
306 }
307 
308 void
310 {
312 }
313 
314 void
316 {
317 #ifdef DEBUG_DSSI
318  SVDEBUG << "DSSIPluginInstance::setIdealChannelCount: channel count "
319  << channels << " (was " << m_idealChannelCount << ")" << endl;
320 #endif
321 
322  if (channels == m_idealChannelCount) {
323  silence();
324  return;
325  }
326 
327  if (m_instanceHandle != 0) {
328  deactivate();
329  }
330 
331  m_idealChannelCount = channels;
332 
333  if (channels > m_outputBufferCount) {
334 
335  for (size_t i = 0; i < m_outputBufferCount; ++i) {
336  delete[] m_outputBuffers[i];
337  }
338 
339  delete[] m_outputBuffers;
340 
341  m_outputBufferCount = channels;
342 
344 
345  for (size_t i = 0; i < m_outputBufferCount; ++i) {
347  }
348 
349  connectPorts();
350  }
351 
352  if (m_instanceHandle != 0) {
353  activate();
354  }
355 }
356 
357 void
359 {
360  if (!m_grouped) return;
361  m_groupMap[m_identifier].erase(this);
362  m_grouped = false;
363 }
364 
365 void
367 {
368  if (!m_descriptor->run_multiple_synths) {
369  m_grouped = false;
370  return;
371  }
372 
374 
375  size_t pluginsInGroup = m_groupMap[m_identifier].size();
376 
377  if (++pluginsInGroup > m_groupLocalEventBufferCount) {
378 
379  size_t nextBufferCount = pluginsInGroup * 2;
380 
381  snd_seq_event_t **eventLocalBuffers = new snd_seq_event_t *[nextBufferCount];
382 
383  for (size_t i = 0; i < m_groupLocalEventBufferCount; ++i) {
384  eventLocalBuffers[i] = m_groupLocalEventBuffers[i];
385  }
386  for (size_t i = m_groupLocalEventBufferCount; i < nextBufferCount; ++i) {
387  eventLocalBuffers[i] = new snd_seq_event_t[EVENT_BUFFER_SIZE];
388  }
389 
393  }
394 
395  m_groupLocalEventBuffers = eventLocalBuffers;
396  m_groupLocalEventBufferCount = nextBufferCount;
397  }
398 
399  m_grouped = true;
400  m_groupMap[m_identifier].insert(this);
401 }
402 
404 {
405 #ifdef DEBUG_DSSI
406  SVDEBUG << "DSSIPluginInstance::~DSSIPluginInstance" << endl;
407 #endif
408 
409  if (m_threads.find(m_instanceHandle) != m_threads.end()) {
410 
411  for (std::set<NonRTPluginThread *>::iterator i =
412  m_threads[m_instanceHandle].begin();
413  i != m_threads[m_instanceHandle].end(); ++i) {
414 
415  (*i)->setExiting();
416  (*i)->wait();
417  delete *i;
418  }
419 
421  }
422 
423  detachFromGroup();
424 
425  if (m_instanceHandle != 0) {
426  deactivate();
427  }
428 
429  cleanup();
430 
431  for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i)
432  delete m_controlPortsIn[i].second;
433 
434  for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i)
435  delete m_controlPortsOut[i].second;
436 
437  m_controlPortsIn.clear();
438  m_controlPortsOut.clear();
439 
440  if (m_ownBuffers) {
441  for (size_t i = 0; i < m_audioPortsIn.size(); ++i) {
442  delete[] m_inputBuffers[i];
443  }
444  for (size_t i = 0; i < m_outputBufferCount; ++i) {
445  delete[] m_outputBuffers[i];
446  }
447 
448  delete[] m_inputBuffers;
449  delete[] m_outputBuffers;
450  }
451 
452  m_audioPortsIn.clear();
453  m_audioPortsOut.clear();
454 }
455 
456 
457 void
458 DSSIPluginInstance::instantiate(unsigned long sampleRate)
459 {
460  if (!m_descriptor) return;
461 
462 #ifdef DEBUG_DSSI
463  cout << "DSSIPluginInstance::instantiate - plugin \"unique\" id = "
464  << m_descriptor->LADSPA_Plugin->UniqueID << endl;
465 #endif
466  const LADSPA_Descriptor *descriptor = m_descriptor->LADSPA_Plugin;
467 
468  if (!descriptor->instantiate) {
469  cerr << "Bad plugin: plugin id " << descriptor->UniqueID
470  << ":" << descriptor->Label
471  << " has no instantiate method!" << endl;
472  return;
473  }
474 
475  m_instanceHandle = descriptor->instantiate(descriptor, sampleRate);
476 
477  if (m_instanceHandle) {
478 
479  if (m_descriptor->get_midi_controller_for_port) {
480 
481  for (unsigned long i = 0; i < descriptor->PortCount; ++i) {
482 
483  if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i]) &&
484  LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) {
485 
486  int controller = m_descriptor->get_midi_controller_for_port
487  (m_instanceHandle, i);
488 
489  if (controller != 0 && controller != 32 &&
490  DSSI_IS_CC(controller)) {
491 
492  m_controllerMap[DSSI_CC_NUMBER(controller)] = i;
493  }
494  }
495  }
496  }
497  }
498 }
499 
500 void
502 {
503  if (m_programCacheValid) return;
504  m_cachedPrograms.clear();
505 
506 #ifdef DEBUG_DSSI
507  SVDEBUG << "DSSIPluginInstance::checkProgramCache" << endl;
508 #endif
509 
510  if (!m_descriptor || !m_descriptor->get_program) {
511  m_programCacheValid = true;
512  return;
513  }
514 
515  unsigned long index = 0;
516  const DSSI_Program_Descriptor *programDescriptor;
517  while ((programDescriptor = m_descriptor->get_program(m_instanceHandle, index))) {
518  ++index;
520  d.bank = programDescriptor->Bank;
521  d.program = programDescriptor->Program;
522  d.name = programDescriptor->Name;
523  m_cachedPrograms.push_back(d);
524  }
525 
526 #ifdef DEBUG_DSSI
527  SVDEBUG << "DSSIPluginInstance::checkProgramCache: have " << m_cachedPrograms.size() << " programs" << endl;
528 #endif
529 
530  m_programCacheValid = true;
531 }
532 
533 DSSIPluginInstance::ProgramList
535 {
536 #ifdef DEBUG_DSSI
537  SVDEBUG << "DSSIPluginInstance::getPrograms" << endl;
538 #endif
539 
540  if (!m_descriptor) return ProgramList();
541 
543 
544  ProgramList programs;
545 
546  for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin();
547  i != m_cachedPrograms.end(); ++i) {
548  programs.push_back(i->name);
549  }
550 
551  return programs;
552 }
553 
554 std::string
555 DSSIPluginInstance::getProgram(int bank, int program) const
556 {
557 #ifdef DEBUG_DSSI
558  SVDEBUG << "DSSIPluginInstance::getProgram(" << bank << "," << program << ")" << endl;
559 #endif
560 
561  if (!m_descriptor) return std::string();
562 
564 
565  for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin();
566  i != m_cachedPrograms.end(); ++i) {
567  if (i->bank == bank && i->program == program) return i->name;
568  }
569 
570  return std::string();
571 }
572 
573 unsigned long
574 DSSIPluginInstance::getProgram(std::string name) const
575 {
576 #ifdef DEBUG_DSSI
577  SVDEBUG << "DSSIPluginInstance::getProgram(" << name << ")" << endl;
578 #endif
579 
580  if (!m_descriptor) return 0;
581 
583 
584  unsigned long rv;
585 
586  for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin();
587  i != m_cachedPrograms.end(); ++i) {
588  if (i->name == name) {
589  rv = i->bank;
590  rv = (rv << 16) + i->program;
591  return rv;
592  }
593  }
594 
595  return 0;
596 }
597 
598 std::string
600 {
601  return m_program;
602 }
603 
604 void
606 {
607  selectProgramAux(program, true);
608 }
609 
610 void
611 DSSIPluginInstance::selectProgramAux(std::string program, bool backupPortValues)
612 {
613 #ifdef DEBUG_DSSI
614  SVDEBUG << "DSSIPluginInstance::selectProgram(" << program << ")" << endl;
615 #endif
616 
617  if (!m_descriptor) return;
618 
620 
621  if (!m_descriptor->select_program) return;
622 
623  bool found = false;
624  unsigned long bankNo = 0, programNo = 0;
625 
626  for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin();
627  i != m_cachedPrograms.end(); ++i) {
628 
629  if (i->name == program) {
630 
631  bankNo = i->bank;
632  programNo = i->program;
633  found = true;
634 
635 #ifdef DEBUG_DSSI
636  SVDEBUG << "DSSIPluginInstance::selectProgram(" << program << "): found at bank " << bankNo << ", program " << programNo << endl;
637 #endif
638 
639  break;
640  }
641  }
642 
643  if (!found) return;
644  m_program = program;
645 
646  // DSSI select_program is an audio context call
647  m_processLock.lock();
648  m_descriptor->select_program(m_instanceHandle, bankNo, programNo);
649  m_processLock.unlock();
650 
651 #ifdef DEBUG_DSSI
652  SVDEBUG << "DSSIPluginInstance::selectProgram(" << program << "): made select_program(" << bankNo << "," << programNo << ") call" << endl;
653 #endif
654 
655  if (backupPortValues) {
656  for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) {
658  }
659  }
660 }
661 
662 void
664 {
665 #ifdef DEBUG_DSSI
666  SVDEBUG << "DSSIPluginInstance::activate" << endl;
667 #endif
668 
669  if (!m_descriptor || !m_descriptor->LADSPA_Plugin->activate) return;
670  m_descriptor->LADSPA_Plugin->activate(m_instanceHandle);
671 
672  if (m_program != "") {
673 #ifdef DEBUG_DSSI
674  SVDEBUG << "DSSIPluginInstance::activate: restoring program " << m_program << endl;
675 #endif
676  selectProgramAux(m_program, false);
677  }
678 
679  for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) {
680 #ifdef DEBUG_DSSI
681  SVDEBUG << "DSSIPluginInstance::activate: setting port " << m_controlPortsIn[i].first << " to " << m_backupControlPortsIn[i] << endl;
682 #endif
684  }
685 }
686 
687 void
689 {
690  if (!m_descriptor || !m_descriptor->LADSPA_Plugin->connect_port) return;
691 #ifdef DEBUG_DSSI
692  SVDEBUG << "DSSIPluginInstance::connectPorts: " << m_audioPortsIn.size()
693  << " audio ports in, " << m_audioPortsOut.size() << " out, "
694  << m_outputBufferCount << " output buffers" << endl;
695 #endif
696 
697  assert(sizeof(LADSPA_Data) == sizeof(float));
698  assert(sizeof(sample_t) == sizeof(float));
699 
700  LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
701  int inbuf = 0, outbuf = 0;
702 
703  for (unsigned int i = 0; i < m_audioPortsIn.size(); ++i) {
704  m_descriptor->LADSPA_Plugin->connect_port
706  m_audioPortsIn[i],
707  (LADSPA_Data *)m_inputBuffers[inbuf]);
708  ++inbuf;
709  }
710 
711  for (unsigned int i = 0; i < m_audioPortsOut.size(); ++i) {
712  m_descriptor->LADSPA_Plugin->connect_port
714  m_audioPortsOut[i],
715  (LADSPA_Data *)m_outputBuffers[outbuf]);
716  ++outbuf;
717  }
718 
719  for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
720  m_descriptor->LADSPA_Plugin->connect_port
722  m_controlPortsIn[i].first,
723  m_controlPortsIn[i].second);
724 
725  if (f) {
726  float defaultValue = f->getPortDefault
727  (m_descriptor->LADSPA_Plugin, m_controlPortsIn[i].first);
728  *m_controlPortsIn[i].second = defaultValue;
729  m_backupControlPortsIn[i] = defaultValue;
730 #ifdef DEBUG_DSSI
731  SVDEBUG << "DSSIPluginInstance::connectPorts: set control port " << i << " to default value " << defaultValue << endl;
732 #endif
733  }
734  }
735 
736  for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) {
737  m_descriptor->LADSPA_Plugin->connect_port
739  m_controlPortsOut[i].first,
740  m_controlPortsOut[i].second);
741  }
742 }
743 
744 unsigned int
746 {
747  return m_controlPortsIn.size();
748 }
749 
750 void
751 DSSIPluginInstance::setParameterValue(unsigned int parameter, float value)
752 {
753 #ifdef DEBUG_DSSI
754  SVDEBUG << "DSSIPluginInstance::setParameterValue(" << parameter << ") to " << value << endl;
755 #endif
756  if (parameter >= m_controlPortsIn.size()) return;
757 
758  unsigned int portNumber = m_controlPortsIn[parameter].first;
759 
760  LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
761  if (f) {
762  if (value < f->getPortMinimum(m_descriptor->LADSPA_Plugin, portNumber)) {
763  value = f->getPortMinimum(m_descriptor->LADSPA_Plugin, portNumber);
764  }
765  if (value > f->getPortMaximum(m_descriptor->LADSPA_Plugin, portNumber)) {
766  value = f->getPortMaximum(m_descriptor->LADSPA_Plugin, portNumber);
767  }
768  }
769 
770  (*m_controlPortsIn[parameter].second) = value;
771  m_backupControlPortsIn[parameter] = value;
772 }
773 
774 void
776 {
777 #ifdef DEBUG_DSSI
778  SVDEBUG << "DSSIPluginInstance::setPortValueFromController(" << port << ") to " << cv << endl;
779 #endif
780 
781  const LADSPA_Descriptor *p = m_descriptor->LADSPA_Plugin;
782  LADSPA_PortRangeHintDescriptor d = p->PortRangeHints[port].HintDescriptor;
783  LADSPA_Data lb = p->PortRangeHints[port].LowerBound;
784  LADSPA_Data ub = p->PortRangeHints[port].UpperBound;
785 
786  float value = (float)cv;
787 
788  if (!LADSPA_IS_HINT_BOUNDED_BELOW(d)) {
789  if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) {
790  /* unbounded: might as well leave the value alone. */
791  } else {
792  /* bounded above only. just shift the range. */
793  value = ub - 127.0f + value;
794  }
795  } else {
796  if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) {
797  /* bounded below only. just shift the range. */
798  value = lb + value;
799  } else {
800  /* bounded both ends. more interesting. */
801  /* XXX !!! todo: fill in logarithmic, sample rate &c */
802  value = lb + ((ub - lb) * value / 127.0f);
803  }
804  }
805 
806  for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
807  if (m_controlPortsIn[i].first == port) {
808  setParameterValue(i, value);
809  }
810  }
811 }
812 
813 float
815 {
816  if (output > m_controlPortsOut.size()) return 0.0;
817  return (*m_controlPortsOut[output].second);
818 }
819 
820 float
821 DSSIPluginInstance::getParameterValue(unsigned int parameter) const
822 {
823 #ifdef DEBUG_DSSI
824  SVDEBUG << "DSSIPluginInstance::getParameterValue(" << parameter << ")" << endl;
825 #endif
826  if (parameter >= m_controlPortsIn.size()) return 0.0;
827  return (*m_controlPortsIn[parameter].second);
828 }
829 
830 float
831 DSSIPluginInstance::getParameterDefault(unsigned int parameter) const
832 {
833  if (parameter >= m_controlPortsIn.size()) return 0.0;
834 
835  LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
836  if (f) {
837  return f->getPortDefault(m_descriptor->LADSPA_Plugin,
838  m_controlPortsIn[parameter].first);
839  } else {
840  return 0.0f;
841  }
842 }
843 
844 int
845 DSSIPluginInstance::getParameterDisplayHint(unsigned int parameter) const
846 {
847  if (parameter >= m_controlPortsIn.size()) return 0.0;
848 
849  LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
850  if (f) {
851  return f->getPortDisplayHint(m_descriptor->LADSPA_Plugin,
852  m_controlPortsIn[parameter].first);
853  } else {
854  return PortHint::NoHint;
855  }
856 }
857 
858 std::string
860  std::string value)
861 {
862  if (!m_descriptor || !m_descriptor->configure) return std::string();
863 
864  if (key == PluginIdentifier::RESERVED_PROJECT_DIRECTORY_KEY.toStdString()) {
865 #ifdef DSSI_PROJECT_DIRECTORY_KEY
866  key = DSSI_PROJECT_DIRECTORY_KEY;
867 #else
868  return std::string();
869 #endif
870  }
871 
872 
873 #ifdef DEBUG_DSSI
874  SVDEBUG << "DSSIPluginInstance::configure(" << key << "," << value << ")" << endl;
875 #endif
876 
877  char *message = m_descriptor->configure(m_instanceHandle,
878  key.c_str(),
879  value.c_str());
880 
881  m_programCacheValid = false;
882 
883  m_configurationData[key] = value;
884 
885  std::string qm;
886 
887  // Ignore return values from reserved key configuration calls such
888  // as project directory
889 #ifdef DSSI_RESERVED_CONFIGURE_PREFIX
890  if (QString(key.c_str()).startsWith(DSSI_RESERVED_CONFIGURE_PREFIX)) {
891  return qm;
892  }
893 #endif
894 
895  if (message) {
896  if (m_descriptor->LADSPA_Plugin && m_descriptor->LADSPA_Plugin->Label) {
897  qm = std::string(m_descriptor->LADSPA_Plugin->Label) + ": ";
898  }
899  qm = qm + message;
900  free(message);
901 
902  cerr << "DSSIPluginInstance::configure: warning: configure returned message: \"" << qm << "\"" << endl;
903  }
904 
905  return qm;
906 }
907 
908 void
909 DSSIPluginInstance::sendEvent(const Vamp::RealTime &eventTime,
910  const void *e)
911 {
912 #ifdef DEBUG_DSSI_PROCESS
913  SVDEBUG << "DSSIPluginInstance::sendEvent: last was " << m_lastEventSendTime << " (valid " << m_haveLastEventSendTime << "), this is " << eventTime << endl;
914 #endif
915 
916  // The process mechanism only works correctly if the events are
917  // sorted. It's the responsibility of the caller to ensure that:
918  // we will happily drop events here if we find the timeline going
919  // backwards.
921  m_lastEventSendTime > eventTime) {
922 #ifdef DEBUG_DSSI_PROCESS
923  cerr << "... clearing down" << endl;
924 #endif
925  m_haveLastEventSendTime = false;
926  clearEvents();
927  }
928 
929  snd_seq_event_t *event = (snd_seq_event_t *)e;
930 #ifdef DEBUG_DSSI_PROCESS
931  SVDEBUG << "DSSIPluginInstance::sendEvent at " << eventTime << endl;
932 #endif
933  snd_seq_event_t ev(*event);
934 
935  ev.time.time.tv_sec = eventTime.sec;
936  ev.time.time.tv_nsec = eventTime.nsec;
937 
938  // DSSI doesn't use MIDI channels, it uses run_multiple_synths instead.
939  ev.data.note.channel = 0;
940 
941  m_eventBuffer.write(&ev, 1);
942 
943  m_lastEventSendTime = eventTime;
945 }
946 
947 void
949 {
950  m_haveLastEventSendTime = false;
952 }
953 
954 bool
956 {
957  int controller = ev->data.control.param;
958 
959 #ifdef DEBUG_DSSI_PROCESS
960  SVDEBUG << "DSSIPluginInstance::handleController " << controller << endl;
961 #endif
962 
963  if (controller == 0) { // bank select MSB
964 
965  m_pending.msb = ev->data.control.value;
966 
967  } else if (controller == 32) { // bank select LSB
968 
969  m_pending.lsb = ev->data.control.value;
970 
971  } else if (controller > 0 && controller < 128) {
972 
973  if (m_controllerMap.find(controller) != m_controllerMap.end()) {
974  int port = m_controllerMap[controller];
975  setPortValueFromController(port, ev->data.control.value);
976  } else {
977  return true; // pass through to plugin
978  }
979  }
980 
981  return false;
982 }
983 
984 void
985 DSSIPluginInstance::run(const Vamp::RealTime &blockTime, size_t count)
986 {
987  static snd_seq_event_t localEventBuffer[EVENT_BUFFER_SIZE];
988  int evCount = 0;
989 
990  if (count == 0) count = m_blockSize;
991 
992  bool needLock = false;
993  if (m_descriptor && m_descriptor->select_program) needLock = true;
994 
995  if (needLock) {
996  if (!m_processLock.tryLock()) {
997  for (size_t ch = 0; ch < m_audioPortsOut.size(); ++ch) {
998  memset(m_outputBuffers[ch], 0, m_blockSize * sizeof(sample_t));
999  }
1000  return;
1001  }
1002  }
1003 
1004  if (m_grouped) {
1005  runGrouped(blockTime);
1006  goto done;
1007  }
1008 
1009  if (!m_descriptor || !m_descriptor->run_synth) {
1011  m_haveLastEventSendTime = false;
1012  if (m_descriptor && m_descriptor->LADSPA_Plugin->run) {
1013  m_descriptor->LADSPA_Plugin->run(m_instanceHandle, count);
1014  } else {
1015  for (size_t ch = 0; ch < m_audioPortsOut.size(); ++ch) {
1016  memset(m_outputBuffers[ch], 0, m_blockSize * sizeof(sample_t));
1017  }
1018  }
1019  m_run = true;
1020  if (needLock) m_processLock.unlock();
1021  return;
1022  }
1023 
1024 #ifdef DEBUG_DSSI_PROCESS
1025  SVDEBUG << "DSSIPluginInstance::run(" << blockTime << ")" << endl;
1026 #endif
1027 
1028 #ifdef DEBUG_DSSI_PROCESS
1029  if (m_eventBuffer.getReadSpace() > 0) {
1030  SVDEBUG << "DSSIPluginInstance::run: event buffer has "
1031  << m_eventBuffer.getReadSpace() << " event(s) in it" << endl;
1032  }
1033 #endif
1034 
1035  while (m_eventBuffer.getReadSpace() > 0) {
1036 
1037  snd_seq_event_t *ev = localEventBuffer + evCount;
1038  *ev = m_eventBuffer.peekOne();
1039  bool accept = true;
1040 
1041  Vamp::RealTime evTime(ev->time.time.tv_sec, ev->time.time.tv_nsec);
1042 
1043  int frameOffset = 0;
1044  if (evTime > blockTime) {
1045  frameOffset = Vamp::RealTime::realTime2Frame(evTime - blockTime, m_sampleRate);
1046  }
1047 
1048 #ifdef DEBUG_DSSI_PROCESS
1049  SVDEBUG << "DSSIPluginInstance::run: evTime " << evTime << ", blockTime " << blockTime << ", frameOffset " << frameOffset
1050  << ", blockSize " << m_blockSize << endl;
1051  cerr << "Type: " << int(ev->type) << ", pitch: " << int(ev->data.note.note) << ", velocity: " << int(ev->data.note.velocity) << endl;
1052 #endif
1053 
1054  if (frameOffset >= int(count)) break;
1055  if (frameOffset < 0) {
1056  frameOffset = 0;
1057  if (ev->type == SND_SEQ_EVENT_NOTEON) {
1058  m_eventBuffer.skip(1);
1059  continue;
1060  }
1061  }
1062 
1063  ev->time.tick = frameOffset;
1064  m_eventBuffer.skip(1);
1065 
1066  if (ev->type == SND_SEQ_EVENT_CONTROLLER) {
1067  accept = handleController(ev);
1068  } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) {
1069  m_pending.program = ev->data.control.value;
1070  accept = false;
1071  }
1072 
1073  if (accept) {
1074  if (++evCount >= EVENT_BUFFER_SIZE) break;
1075  }
1076  }
1077 
1078  if (m_pending.program >= 0 && m_descriptor->select_program) {
1079 
1080  int program = m_pending.program;
1081  int bank = m_pending.lsb + 128 * m_pending.msb;
1082 
1083 #ifdef DEBUG_DSSI
1084  SVDEBUG << "DSSIPluginInstance::run: making select_program(" << bank << "," << program << ") call" << endl;
1085 #endif
1086 
1088  m_descriptor->select_program(m_instanceHandle, bank, program);
1089 
1090 #ifdef DEBUG_DSSI
1091  SVDEBUG << "DSSIPluginInstance::run: made select_program(" << bank << "," << program << ") call" << endl;
1092 #endif
1093  }
1094 
1095 #ifdef DEBUG_DSSI_PROCESS
1096  SVDEBUG << "DSSIPluginInstance::run: running with " << evCount << " events"
1097  << endl;
1098 #endif
1099 
1100  m_descriptor->run_synth(m_instanceHandle, count,
1101  localEventBuffer, evCount);
1102 
1103 #ifdef DEBUG_DSSI_PROCESS
1104 // for (int i = 0; i < count; ++i) {
1105 // cout << m_outputBuffers[0][i] << " ";
1106 // if (i % 8 == 0) cout << endl;
1107 // }
1108 #endif
1109 
1110  done:
1111  if (needLock) m_processLock.unlock();
1112 
1113  if (m_audioPortsOut.size() == 0) {
1114  // copy inputs to outputs
1115  for (size_t ch = 0; ch < m_idealChannelCount; ++ch) {
1116  size_t sch = ch % m_audioPortsIn.size();
1117  for (size_t i = 0; i < m_blockSize; ++i) {
1118  m_outputBuffers[ch][i] = m_inputBuffers[sch][i];
1119  }
1120  }
1121  } else if (m_idealChannelCount < m_audioPortsOut.size()) {
1122  if (m_idealChannelCount == 1) {
1123  // mix down to mono
1124  for (size_t ch = 1; ch < m_audioPortsOut.size(); ++ch) {
1125  for (size_t i = 0; i < m_blockSize; ++i) {
1126  m_outputBuffers[0][i] += m_outputBuffers[ch][i];
1127  }
1128  }
1129  }
1130  } else if (m_idealChannelCount > m_audioPortsOut.size()) {
1131  // duplicate
1132  for (size_t ch = m_audioPortsOut.size(); ch < m_idealChannelCount; ++ch) {
1133  size_t sch = (ch - m_audioPortsOut.size()) % m_audioPortsOut.size();
1134  for (size_t i = 0; i < m_blockSize; ++i) {
1135  m_outputBuffers[ch][i] = m_outputBuffers[sch][i];
1136  }
1137  }
1138  }
1139 
1140  m_lastRunTime = blockTime;
1141  m_run = true;
1142 }
1143 
1144 void
1145 DSSIPluginInstance::runGrouped(const Vamp::RealTime &blockTime)
1146 {
1147  // If something else in our group has just been called for this
1148  // block time (but we haven't) then we should just write out the
1149  // results and return; if we have just been called for this block
1150  // time or nothing else in the group has been, we should run the
1151  // whole group.
1152 
1153  bool needRun = true;
1154 
1156 
1157 #ifdef DEBUG_DSSI_PROCESS
1158  SVDEBUG << "DSSIPluginInstance::runGrouped(" << blockTime << "): this is " << this << "; " << s.size() << " elements in m_groupMap[" << m_identifier << "]" << endl;
1159 #endif
1160 
1161  if (m_lastRunTime != blockTime) {
1162  for (PluginSet::iterator i = s.begin(); i != s.end(); ++i) {
1164  if (instance != this && instance->m_lastRunTime == blockTime) {
1165 #ifdef DEBUG_DSSI_PROCESS
1166  SVDEBUG << "DSSIPluginInstance::runGrouped(" << blockTime << "): plugin " << instance << " has already been run" << endl;
1167 #endif
1168  needRun = false;
1169  }
1170  }
1171  }
1172 
1173  if (!needRun) {
1174 #ifdef DEBUG_DSSI_PROCESS
1175  SVDEBUG << "DSSIPluginInstance::runGrouped(" << blockTime << "): already run, returning" << endl;
1176 #endif
1177  return;
1178  }
1179 
1180 #ifdef DEBUG_DSSI_PROCESS
1181  SVDEBUG << "DSSIPluginInstance::runGrouped(" << blockTime << "): I'm the first, running" << endl;
1182 #endif
1183 
1184  size_t index = 0;
1185  unsigned long *counts = (unsigned long *)
1186  alloca(m_groupLocalEventBufferCount * sizeof(unsigned long));
1187  LADSPA_Handle *instances = (LADSPA_Handle *)
1188  alloca(m_groupLocalEventBufferCount * sizeof(LADSPA_Handle));
1189 
1190  for (PluginSet::iterator i = s.begin(); i != s.end(); ++i) {
1191 
1192  if (index >= m_groupLocalEventBufferCount) break;
1193 
1195  counts[index] = 0;
1196  instances[index] = instance->m_instanceHandle;
1197 
1198 #ifdef DEBUG_DSSI_PROCESS
1199  SVDEBUG << "DSSIPluginInstance::runGrouped(" << blockTime << "): running " << instance << endl;
1200 #endif
1201 
1202  if (instance->m_pending.program >= 0 &&
1203  instance->m_descriptor->select_program) {
1204  int program = instance->m_pending.program;
1205  int bank = instance->m_pending.lsb + 128 * instance->m_pending.msb;
1206  instance->m_pending.lsb = instance->m_pending.msb = instance->m_pending.program = -1;
1207  instance->m_descriptor->select_program
1208  (instance->m_instanceHandle, bank, program);
1209  }
1210 
1211  while (instance->m_eventBuffer.getReadSpace() > 0) {
1212 
1213  snd_seq_event_t *ev = m_groupLocalEventBuffers[index] + counts[index];
1214  *ev = instance->m_eventBuffer.peekOne();
1215  bool accept = true;
1216 
1217  Vamp::RealTime evTime(ev->time.time.tv_sec, ev->time.time.tv_nsec);
1218 
1219  int frameOffset = 0;
1220  if (evTime > blockTime) {
1221  frameOffset = Vamp::RealTime::realTime2Frame(evTime - blockTime, m_sampleRate);
1222  }
1223 
1224 #ifdef DEBUG_DSSI_PROCESS
1225  SVDEBUG << "DSSIPluginInstance::runGrouped: evTime " << evTime << ", frameOffset " << frameOffset
1226  << ", block size " << m_blockSize << endl;
1227 #endif
1228 
1229  if (frameOffset >= int(m_blockSize)) break;
1230  if (frameOffset < 0) frameOffset = 0;
1231 
1232  ev->time.tick = frameOffset;
1233  instance->m_eventBuffer.skip(1);
1234 
1235  if (ev->type == SND_SEQ_EVENT_CONTROLLER) {
1236  accept = instance->handleController(ev);
1237  } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) {
1238  instance->m_pending.program = ev->data.control.value;
1239  accept = false;
1240  }
1241 
1242  if (accept) {
1243  if (++counts[index] >= EVENT_BUFFER_SIZE) break;
1244  }
1245  }
1246 
1247  ++index;
1248  }
1249 
1250  m_descriptor->run_multiple_synths(index,
1251  instances,
1252  m_blockSize,
1254  counts);
1255 }
1256 
1257 int
1258 DSSIPluginInstance::requestMidiSend(LADSPA_Handle /* instance */,
1259  unsigned char /* ports */,
1260  unsigned char /* channels */)
1261 {
1262  // This is called from a non-RT context (during instantiate)
1263 
1264  SVDEBUG << "DSSIPluginInstance::requestMidiSend" << endl;
1265  return 1;
1266 }
1267 
1268 void
1269 DSSIPluginInstance::midiSend(LADSPA_Handle /* instance */,
1270  snd_seq_event_t * /* events */,
1271  unsigned long /* eventCount */)
1272 {
1273  // This is likely to be called from an RT context
1274 
1275  SVDEBUG << "DSSIPluginInstance::midiSend" << endl;
1276 }
1277 
1278 void
1280 {
1281  while (!m_exiting) {
1283  usleep(100000);
1284  }
1285 }
1286 
1287 int
1289  void (*runFunction)(LADSPA_Handle))
1290 {
1291  NonRTPluginThread *thread = new NonRTPluginThread(instance, runFunction);
1292  m_threads[instance].insert(thread);
1293  thread->start();
1294  return 0;
1295 }
1296 
1297 void
1299 {
1300 #ifdef DEBUG_DSSI
1301  SVDEBUG << "DSSIPluginInstance::deactivate " << m_identifier << endl;
1302 #endif
1303  if (!m_descriptor || !m_descriptor->LADSPA_Plugin->deactivate) return;
1304 
1305  for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) {
1306  m_backupControlPortsIn[i] = *m_controlPortsIn[i].second;
1307  }
1308 
1309  m_descriptor->LADSPA_Plugin->deactivate(m_instanceHandle);
1310 #ifdef DEBUG_DSSI
1311  SVDEBUG << "DSSIPluginInstance::deactivate " << m_identifier << " done" << endl;
1312 #endif
1313 
1315 }
1316 
1317 void
1319 {
1320 #ifdef DEBUG_DSSI
1321  SVDEBUG << "DSSIPluginInstance::cleanup " << m_identifier << endl;
1322 #endif
1323  if (!m_descriptor) return;
1324 
1325  if (!m_descriptor->LADSPA_Plugin->cleanup) {
1326  cerr << "Bad plugin: plugin id "
1327  << m_descriptor->LADSPA_Plugin->UniqueID
1328  << ":" << m_descriptor->LADSPA_Plugin->Label
1329  << " has no cleanup method!" << endl;
1330  return;
1331  }
1332 
1333  m_descriptor->LADSPA_Plugin->cleanup(m_instanceHandle);
1334  m_instanceHandle = 0;
1335 #ifdef DEBUG_DSSI
1336  SVDEBUG << "DSSIPluginInstance::cleanup " << m_identifier << " done" << endl;
1337 #endif
1338 }
1339 
DSSIPluginInstance(RealTimePluginFactory *factory, int client, QString identifier, int position, unsigned long sampleRate, size_t blockSize, int idealChannelCount, const DSSI_Descriptor *descriptor)
T peekOne(int R=0) const
Read one sample from the buffer, if available, without advancing the read pointer – i....
Definition: RingBuffer.h:449
std::vector< LADSPA_Data > m_backupControlPortsIn
virtual void sendEvent(const Vamp::RealTime &eventTime, const void *event)
static int requestMidiSend(LADSPA_Handle instance, unsigned char ports, unsigned char channels)
static std::map< LADSPA_Handle, std::set< NonRTPluginThread * > > m_threads
int getPortDisplayHint(const LADSPA_Descriptor *, int port)
void instantiate(unsigned long sampleRate)
static QString RESERVED_PROJECT_DIRECTORY_KEY
static const int NoHint
static void midiSend(LADSPA_Handle instance, snd_seq_event_t *events, unsigned long eventCount)
std::map< int, int > m_controllerMap
std::vector< std::pair< unsigned long, LADSPA_Data * > > m_controlPortsIn
void runGrouped(const Vamp::RealTime &)
virtual bool isOK() const
bool handleController(snd_seq_event_t *ev)
A very simple class that facilitates running things like plugins without locking, by collecting unwan...
Definition: Scavenger.h:45
virtual int getParameterDisplayHint(unsigned int parameter) const
void start()
Definition: Thread.cpp:34
static snd_seq_event_t ** m_groupLocalEventBuffers
void scavenge(bool clearNow=false)
Call from a non-RT thread.
Definition: Scavenger.h:151
virtual void run(const Vamp::RealTime &, size_t count=0)
Run for one block, starting at the given time.
virtual std::string getIdentifier() const
virtual std::string getDescription() const
ConfigurationPairMap m_configurationData
RingBuffer< snd_seq_event_t > m_eventBuffer
void selectProgramAux(std::string program, bool backupPortValues)
virtual size_t getLatency()
void reset()
Reset read and write pointers, thus emptying the buffer.
Definition: RingBuffer.h:262
float getPortDefault(const LADSPA_Descriptor *, int port)
virtual std::string getMaker() const
void checkProgramCache() const
std::vector< ProgramDescriptor > m_cachedPrograms
virtual void clearEvents()
virtual void setIdealChannelCount(size_t channels)
virtual float getControlOutputValue(size_t n) const
std::vector< int > m_audioPortsOut
float getPortMaximum(const LADSPA_Descriptor *, int port)
const DSSI_Descriptor * m_descriptor
virtual size_t getAudioInputCount() const
float getPortQuantization(const LADSPA_Descriptor *, int port)
std::vector< std::pair< unsigned long, LADSPA_Data * > > m_controlPortsOut
QDebug & operator<<(QDebug &dbg, const std::string &s)
Definition: Debug.cpp:84
virtual int getPluginVersion() const
static Scavenger< ScavengerArrayWrapper< snd_seq_event_t * > > m_bufferScavenger
virtual void setParameter(std::string, float)
virtual ProgramList getPrograms() const
A wrapper to permit arrays to be scavenged.
Definition: Scavenger.h:85
Vamp::RealTime m_lastRunTime
void setPortValueFromController(unsigned int portNumber, int controlValue)
virtual std::string getName() const
virtual void selectProgram(std::string program)
virtual void setParameterValue(unsigned int parameter, float value)
int write(const T *source, int n)
Write n samples to the buffer.
Definition: RingBuffer.h:491
#define EVENT_BUFFER_SIZE
static int requestNonRTThread(LADSPA_Handle instance, void(*runFunction)(LADSPA_Handle))
#define SVDEBUG
Definition: Debug.h:42
RealTimePluginFactory * m_factory
static RealTimePluginFactory * instance(QString pluginType)
virtual float getParameterDefault(unsigned int parameter) const
virtual ParameterList getParameterDescriptors() const
virtual std::string getCopyright() const
int skip(int n, int R=0)
Pretend to read n samples from the buffer, for reader R, without actually returning them (i....
Definition: RingBuffer.h:470
virtual std::string getProgram(int bank, int program) const
virtual unsigned int getParameterCount() const
virtual std::string configure(std::string key, std::string value)
void claim(T *t)
Call from an RT thread etc., to pass ownership of t to us.
Definition: Scavenger.h:126
static size_t m_groupLocalEventBufferCount
ProgramControl m_pending
static GroupMap m_groupMap
virtual float getParameterValue(unsigned int parameter) const
Vamp::RealTime m_lastEventSendTime
virtual std::string getCurrentProgram() const
int getReadSpace(int R=0) const
Return the amount of data available for reading by reader R, in samples.
Definition: RingBuffer.h:274
virtual void detachFromGroup()
std::vector< int > m_audioPortsIn
float getPortMinimum(const LADSPA_Descriptor *, int port)
std::map< QString, PluginSet > GroupMap
virtual void discardEvents()
virtual float getParameter(std::string) const
std::set< DSSIPluginInstance * > PluginSet
LADSPA_Handle m_instanceHandle