annotate plugin/DSSIPluginInstance.cpp @ 239:71f869dac40b

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