annotate plugin/DSSIPluginInstance.cpp @ 1412:b7a9edee85e0 scale-ticks

Change loop to something that feels more correct, though it makes no difference to the tests here. More tests, one failing.
author Chris Cannam
date Thu, 04 May 2017 08:32:41 +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