annotate plugin/DSSIPluginInstance.cpp @ 1008:d9e0e59a1581

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