annotate plugin/DSSIPluginInstance.cpp @ 458:f60360209e5c

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