annotate plugin/DSSIPluginInstance.cpp @ 360:ac300d385ab2

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