annotate plugin/LADSPAPluginInstance.cpp @ 14:b101cc2ae1ab

* Introduce potentially-separate read and write ring buffers, so we can swap in a new set when something changes -- thus allowing us to respond quickly when something changes during playback, without losing the long buffers * Some fixes for display & editing
author Chris Cannam
date Fri, 27 Jan 2006 18:04:07 +0000
parents d86891498eef
children 2fb933f88604
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@2 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 /*
Chris@0 11 This is a modified version of a source file from the
Chris@0 12 Rosegarden MIDI and audio sequencer and notation editor.
Chris@0 13 This file copyright 2000-2005 Chris Cannam and Richard Bown.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include <iostream>
Chris@0 17 #include <cassert>
Chris@0 18
Chris@0 19 #include "LADSPAPluginInstance.h"
Chris@0 20 #include "LADSPAPluginFactory.h"
Chris@0 21
Chris@0 22 //#define DEBUG_LADSPA 1
Chris@0 23
Chris@0 24
Chris@0 25 LADSPAPluginInstance::LADSPAPluginInstance(RealTimePluginFactory *factory,
Chris@0 26 int clientId,
Chris@0 27 QString identifier,
Chris@0 28 int position,
Chris@0 29 unsigned long sampleRate,
Chris@0 30 size_t blockSize,
Chris@0 31 int idealChannelCount,
Chris@0 32 const LADSPA_Descriptor* descriptor) :
Chris@0 33 RealTimePluginInstance(factory, identifier),
Chris@0 34 m_client(clientId),
Chris@0 35 m_position(position),
Chris@0 36 m_instanceCount(0),
Chris@0 37 m_descriptor(descriptor),
Chris@0 38 m_blockSize(blockSize),
Chris@0 39 m_sampleRate(sampleRate),
Chris@0 40 m_latencyPort(0),
Chris@0 41 m_run(false),
Chris@0 42 m_bypassed(false)
Chris@0 43 {
Chris@0 44 init(idealChannelCount);
Chris@0 45
Chris@0 46 m_inputBuffers = new sample_t*[m_instanceCount * m_audioPortsIn.size()];
Chris@0 47 m_outputBuffers = new sample_t*[m_instanceCount * m_audioPortsOut.size()];
Chris@0 48
Chris@0 49 for (size_t i = 0; i < m_instanceCount * m_audioPortsIn.size(); ++i) {
Chris@0 50 m_inputBuffers[i] = new sample_t[blockSize];
Chris@0 51 }
Chris@0 52 for (size_t i = 0; i < m_instanceCount * m_audioPortsOut.size(); ++i) {
Chris@0 53 m_outputBuffers[i] = new sample_t[blockSize];
Chris@0 54 }
Chris@0 55
Chris@0 56 m_ownBuffers = true;
Chris@0 57
Chris@0 58 instantiate(sampleRate);
Chris@0 59 if (isOK()) {
Chris@0 60 connectPorts();
Chris@0 61 activate();
Chris@0 62 }
Chris@0 63 }
Chris@0 64
Chris@0 65 LADSPAPluginInstance::LADSPAPluginInstance(RealTimePluginFactory *factory,
Chris@0 66 int clientId,
Chris@0 67 QString identifier,
Chris@0 68 int position,
Chris@0 69 unsigned long sampleRate,
Chris@0 70 size_t blockSize,
Chris@0 71 sample_t **inputBuffers,
Chris@0 72 sample_t **outputBuffers,
Chris@0 73 const LADSPA_Descriptor* descriptor) :
Chris@0 74 RealTimePluginInstance(factory, identifier),
Chris@0 75 m_client(clientId),
Chris@0 76 m_position(position),
Chris@0 77 m_instanceCount(0),
Chris@0 78 m_descriptor(descriptor),
Chris@0 79 m_blockSize(blockSize),
Chris@0 80 m_inputBuffers(inputBuffers),
Chris@0 81 m_outputBuffers(outputBuffers),
Chris@0 82 m_ownBuffers(false),
Chris@0 83 m_sampleRate(sampleRate),
Chris@0 84 m_latencyPort(0),
Chris@0 85 m_run(false),
Chris@0 86 m_bypassed(false)
Chris@0 87 {
Chris@0 88 init();
Chris@0 89
Chris@0 90 instantiate(sampleRate);
Chris@0 91 if (isOK()) {
Chris@0 92 connectPorts();
Chris@0 93 activate();
Chris@0 94 }
Chris@0 95 }
Chris@0 96
Chris@0 97
Chris@0 98 void
Chris@0 99 LADSPAPluginInstance::init(int idealChannelCount)
Chris@0 100 {
Chris@0 101 #ifdef DEBUG_LADSPA
Chris@0 102 std::cerr << "LADSPAPluginInstance::init(" << idealChannelCount << "): plugin has "
Chris@0 103 << m_descriptor->PortCount << " ports" << std::endl;
Chris@0 104 #endif
Chris@0 105
Chris@0 106 // Discover ports numbers and identities
Chris@0 107 //
Chris@0 108 for (unsigned long i = 0; i < m_descriptor->PortCount; ++i)
Chris@0 109 {
Chris@0 110 if (LADSPA_IS_PORT_AUDIO(m_descriptor->PortDescriptors[i]))
Chris@0 111 {
Chris@0 112 if (LADSPA_IS_PORT_INPUT(m_descriptor->PortDescriptors[i])) {
Chris@0 113 #ifdef DEBUG_LADSPA
Chris@0 114 std::cerr << "LADSPAPluginInstance::init: port " << i << " is audio in" << std::endl;
Chris@0 115 #endif
Chris@0 116 m_audioPortsIn.push_back(i);
Chris@0 117 } else {
Chris@0 118 #ifdef DEBUG_LADSPA
Chris@0 119 std::cerr << "LADSPAPluginInstance::init: port " << i << " is audio out" << std::endl;
Chris@0 120 #endif
Chris@0 121 m_audioPortsOut.push_back(i);
Chris@0 122 }
Chris@0 123 }
Chris@0 124 else
Chris@0 125 if (LADSPA_IS_PORT_CONTROL(m_descriptor->PortDescriptors[i]))
Chris@0 126 {
Chris@0 127 if (LADSPA_IS_PORT_INPUT(m_descriptor->PortDescriptors[i])) {
Chris@0 128 #ifdef DEBUG_LADSPA
Chris@0 129 std::cerr << "LADSPAPluginInstance::init: port " << i << " is control in" << std::endl;
Chris@0 130 #endif
Chris@0 131 LADSPA_Data *data = new LADSPA_Data(0.0);
Chris@0 132 m_controlPortsIn.push_back(
Chris@0 133 std::pair<unsigned long, LADSPA_Data*>(i, data));
Chris@0 134 } else {
Chris@0 135 #ifdef DEBUG_LADSPA
Chris@0 136 std::cerr << "LADSPAPluginInstance::init: port " << i << " is control out" << std::endl;
Chris@0 137 #endif
Chris@0 138 LADSPA_Data *data = new LADSPA_Data(0.0);
Chris@0 139 m_controlPortsOut.push_back(
Chris@0 140 std::pair<unsigned long, LADSPA_Data*>(i, data));
Chris@0 141 if (!strcmp(m_descriptor->PortNames[i], "latency") ||
Chris@0 142 !strcmp(m_descriptor->PortNames[i], "_latency")) {
Chris@0 143 #ifdef DEBUG_LADSPA
Chris@0 144 std::cerr << "Wooo! We have a latency port!" << std::endl;
Chris@0 145 #endif
Chris@0 146 m_latencyPort = data;
Chris@0 147 }
Chris@0 148 }
Chris@0 149 }
Chris@0 150 #ifdef DEBUG_LADSPA
Chris@0 151 else
Chris@0 152 std::cerr << "LADSPAPluginInstance::init - "
Chris@0 153 << "unrecognised port type" << std::endl;
Chris@0 154 #endif
Chris@0 155 }
Chris@0 156
Chris@0 157 m_instanceCount = 1;
Chris@0 158
Chris@0 159 if (idealChannelCount > 0) {
Chris@0 160 if (m_audioPortsIn.size() == 1) {
Chris@0 161 // mono plugin: duplicate it if need be
Chris@0 162 m_instanceCount = idealChannelCount;
Chris@0 163 }
Chris@0 164 }
Chris@0 165 }
Chris@0 166
Chris@0 167 size_t
Chris@0 168 LADSPAPluginInstance::getLatency()
Chris@0 169 {
Chris@0 170 if (m_latencyPort) {
Chris@0 171 if (!m_run) run(RealTime::zeroTime);
Chris@0 172 if (*m_latencyPort > 0) return (size_t)*m_latencyPort;
Chris@0 173 }
Chris@0 174 return 0;
Chris@0 175 }
Chris@0 176
Chris@0 177 void
Chris@0 178 LADSPAPluginInstance::silence()
Chris@0 179 {
Chris@0 180 if (isOK()) {
Chris@0 181 deactivate();
Chris@0 182 activate();
Chris@0 183 }
Chris@0 184 }
Chris@0 185
Chris@0 186 void
Chris@0 187 LADSPAPluginInstance::setIdealChannelCount(size_t channels)
Chris@0 188 {
Chris@0 189 if (m_audioPortsIn.size() != 1 || channels == m_instanceCount) {
Chris@0 190 silence();
Chris@0 191 return;
Chris@0 192 }
Chris@0 193
Chris@0 194 if (isOK()) {
Chris@0 195 deactivate();
Chris@0 196 }
Chris@0 197
Chris@0 198 //!!! don't we need to reallocate inputBuffers and outputBuffers?
Chris@0 199
Chris@0 200 cleanup();
Chris@0 201 m_instanceCount = channels;
Chris@0 202 instantiate(m_sampleRate);
Chris@0 203 if (isOK()) {
Chris@0 204 connectPorts();
Chris@0 205 activate();
Chris@0 206 }
Chris@0 207 }
Chris@0 208
Chris@0 209
Chris@0 210 LADSPAPluginInstance::~LADSPAPluginInstance()
Chris@0 211 {
Chris@0 212 #ifdef DEBUG_LADSPA
Chris@0 213 std::cerr << "LADSPAPluginInstance::~LADSPAPluginInstance" << std::endl;
Chris@0 214 #endif
Chris@0 215
Chris@0 216 if (m_instanceHandles.size() != 0) { // "isOK()"
Chris@0 217 deactivate();
Chris@0 218 }
Chris@0 219
Chris@0 220 cleanup();
Chris@0 221
Chris@0 222 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i)
Chris@0 223 delete m_controlPortsIn[i].second;
Chris@0 224
Chris@0 225 for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i)
Chris@0 226 delete m_controlPortsOut[i].second;
Chris@0 227
Chris@0 228 m_controlPortsIn.clear();
Chris@0 229 m_controlPortsOut.clear();
Chris@0 230
Chris@0 231 if (m_ownBuffers) {
Chris@0 232 for (size_t i = 0; i < m_audioPortsIn.size(); ++i) {
Chris@0 233 delete[] m_inputBuffers[i];
Chris@0 234 }
Chris@0 235 for (size_t i = 0; i < m_audioPortsOut.size(); ++i) {
Chris@0 236 delete[] m_outputBuffers[i];
Chris@0 237 }
Chris@0 238
Chris@0 239 delete[] m_inputBuffers;
Chris@0 240 delete[] m_outputBuffers;
Chris@0 241 }
Chris@0 242
Chris@0 243 m_audioPortsIn.clear();
Chris@0 244 m_audioPortsOut.clear();
Chris@0 245 }
Chris@0 246
Chris@0 247
Chris@0 248 void
Chris@0 249 LADSPAPluginInstance::instantiate(unsigned long sampleRate)
Chris@0 250 {
Chris@0 251 #ifdef DEBUG_LADSPA
Chris@0 252 std::cout << "LADSPAPluginInstance::instantiate - plugin unique id = "
Chris@0 253 << m_descriptor->UniqueID << std::endl;
Chris@0 254 #endif
Chris@0 255 if (!m_descriptor) return;
Chris@0 256
Chris@0 257 if (!m_descriptor->instantiate) {
Chris@0 258 std::cerr << "Bad plugin: plugin id " << m_descriptor->UniqueID
Chris@0 259 << ":" << m_descriptor->Label
Chris@0 260 << " has no instantiate method!" << std::endl;
Chris@0 261 return;
Chris@0 262 }
Chris@0 263
Chris@0 264 for (size_t i = 0; i < m_instanceCount; ++i) {
Chris@0 265 m_instanceHandles.push_back
Chris@0 266 (m_descriptor->instantiate(m_descriptor, sampleRate));
Chris@0 267 }
Chris@0 268 }
Chris@0 269
Chris@0 270 void
Chris@0 271 LADSPAPluginInstance::activate()
Chris@0 272 {
Chris@0 273 if (!m_descriptor || !m_descriptor->activate) return;
Chris@0 274
Chris@0 275 for (std::vector<LADSPA_Handle>::iterator hi = m_instanceHandles.begin();
Chris@0 276 hi != m_instanceHandles.end(); ++hi) {
Chris@0 277 m_descriptor->activate(*hi);
Chris@0 278 }
Chris@0 279 }
Chris@0 280
Chris@0 281 void
Chris@0 282 LADSPAPluginInstance::connectPorts()
Chris@0 283 {
Chris@0 284 if (!m_descriptor || !m_descriptor->connect_port) return;
Chris@0 285
Chris@0 286 assert(sizeof(LADSPA_Data) == sizeof(float));
Chris@0 287 assert(sizeof(sample_t) == sizeof(float));
Chris@0 288
Chris@0 289 int inbuf = 0, outbuf = 0;
Chris@0 290
Chris@0 291 for (std::vector<LADSPA_Handle>::iterator hi = m_instanceHandles.begin();
Chris@0 292 hi != m_instanceHandles.end(); ++hi) {
Chris@0 293
Chris@0 294 for (unsigned int i = 0; i < m_audioPortsIn.size(); ++i) {
Chris@0 295 m_descriptor->connect_port(*hi,
Chris@0 296 m_audioPortsIn[i],
Chris@0 297 (LADSPA_Data *)m_inputBuffers[inbuf]);
Chris@0 298 ++inbuf;
Chris@0 299 }
Chris@0 300
Chris@0 301 for (unsigned int i = 0; i < m_audioPortsOut.size(); ++i) {
Chris@0 302 m_descriptor->connect_port(*hi,
Chris@0 303 m_audioPortsOut[i],
Chris@0 304 (LADSPA_Data *)m_outputBuffers[outbuf]);
Chris@0 305 ++outbuf;
Chris@0 306 }
Chris@0 307
Chris@0 308 // If there is more than one instance, they all share the same
Chris@0 309 // control port ins (and outs, for the moment, because we
Chris@0 310 // don't actually do anything with the outs anyway -- but they
Chris@0 311 // do have to be connected as the plugin can't know if they're
Chris@0 312 // not and will write to them anyway).
Chris@0 313
Chris@0 314 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
Chris@0 315 m_descriptor->connect_port(*hi,
Chris@0 316 m_controlPortsIn[i].first,
Chris@0 317 m_controlPortsIn[i].second);
Chris@0 318 }
Chris@0 319
Chris@0 320 for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) {
Chris@0 321 m_descriptor->connect_port(*hi,
Chris@0 322 m_controlPortsOut[i].first,
Chris@0 323 m_controlPortsOut[i].second);
Chris@0 324 }
Chris@0 325 }
Chris@0 326 }
Chris@0 327
Chris@0 328 unsigned int
Chris@0 329 LADSPAPluginInstance::getParameterCount() const
Chris@0 330 {
Chris@0 331 return m_controlPortsIn.size();
Chris@0 332 }
Chris@0 333
Chris@0 334 void
Chris@0 335 LADSPAPluginInstance::setParameterValue(unsigned int parameter, float value)
Chris@0 336 {
Chris@0 337 if (parameter >= m_controlPortsIn.size()) return;
Chris@0 338
Chris@0 339 unsigned int portNumber = m_controlPortsIn[parameter].first;
Chris@0 340
Chris@0 341 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
Chris@0 342 if (f) {
Chris@0 343 if (value < f->getPortMinimum(m_descriptor, portNumber)) {
Chris@0 344 value = f->getPortMinimum(m_descriptor, portNumber);
Chris@0 345 }
Chris@0 346 if (value > f->getPortMaximum(m_descriptor, portNumber)) {
Chris@0 347 value = f->getPortMaximum(m_descriptor, portNumber);
Chris@0 348 }
Chris@0 349 }
Chris@0 350
Chris@0 351 (*m_controlPortsIn[parameter].second) = value;
Chris@0 352 }
Chris@0 353
Chris@0 354 float
Chris@0 355 LADSPAPluginInstance::getParameterValue(unsigned int parameter) const
Chris@0 356 {
Chris@0 357 if (parameter >= m_controlPortsIn.size()) return 0.0;
Chris@0 358 return (*m_controlPortsIn[parameter].second);
Chris@0 359 }
Chris@0 360
Chris@0 361 float
Chris@0 362 LADSPAPluginInstance::getParameterDefault(unsigned int parameter) const
Chris@0 363 {
Chris@0 364 if (parameter >= m_controlPortsIn.size()) return 0.0;
Chris@0 365
Chris@0 366 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
Chris@0 367 if (f) {
Chris@0 368 return f->getPortDefault(m_descriptor, m_controlPortsIn[parameter].first);
Chris@0 369 } else {
Chris@0 370 return 0.0f;
Chris@0 371 }
Chris@0 372 }
Chris@0 373
Chris@0 374 void
Chris@0 375 LADSPAPluginInstance::run(const RealTime &)
Chris@0 376 {
Chris@0 377 if (!m_descriptor || !m_descriptor->run) return;
Chris@0 378
Chris@0 379 for (std::vector<LADSPA_Handle>::iterator hi = m_instanceHandles.begin();
Chris@0 380 hi != m_instanceHandles.end(); ++hi) {
Chris@0 381 m_descriptor->run(*hi, m_blockSize);
Chris@0 382 }
Chris@0 383
Chris@0 384 m_run = true;
Chris@0 385 }
Chris@0 386
Chris@0 387 void
Chris@0 388 LADSPAPluginInstance::deactivate()
Chris@0 389 {
Chris@0 390 if (!m_descriptor || !m_descriptor->deactivate) return;
Chris@0 391
Chris@0 392 for (std::vector<LADSPA_Handle>::iterator hi = m_instanceHandles.begin();
Chris@0 393 hi != m_instanceHandles.end(); ++hi) {
Chris@0 394 m_descriptor->deactivate(*hi);
Chris@0 395 }
Chris@0 396 }
Chris@0 397
Chris@0 398 void
Chris@0 399 LADSPAPluginInstance::cleanup()
Chris@0 400 {
Chris@0 401 if (!m_descriptor) return;
Chris@0 402
Chris@0 403 if (!m_descriptor->cleanup) {
Chris@0 404 std::cerr << "Bad plugin: plugin id " << m_descriptor->UniqueID
Chris@0 405 << ":" << m_descriptor->Label
Chris@0 406 << " has no cleanup method!" << std::endl;
Chris@0 407 return;
Chris@0 408 }
Chris@0 409
Chris@0 410 for (std::vector<LADSPA_Handle>::iterator hi = m_instanceHandles.begin();
Chris@0 411 hi != m_instanceHandles.end(); ++hi) {
Chris@0 412 m_descriptor->cleanup(*hi);
Chris@0 413 }
Chris@0 414
Chris@0 415 m_instanceHandles.clear();
Chris@0 416 }
Chris@0 417
Chris@0 418