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