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