annotate plugin/DSSIPluginInstance.cpp @ 808:67003fb58ba4

Merge from branch "qt5". This revision actually builds with Qt4 (late releases) or Qt5, though it will warn on configure with Qt4.
author Chris Cannam
date Tue, 14 May 2013 12:36: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