annotate plugin/DSSIPluginInstance.cpp @ 836:f3c98e89cf75

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