annotate plugin/DSSIPluginInstance.cpp @ 1202:3b84f9bd0048 3.0-integration

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