annotate plugin/DSSIPluginInstance.cpp @ 34:aaf73f7309f2

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