1 /*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any purpose with
6 * or without fee is hereby granted, provided that the above copyright notice and this
7 * permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "DistrhoPluginInternal.hpp"
18
19 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
20 # error Cannot use MIDI Output with LADSPA or DSSI
21 #endif
22
23 #ifdef DISTRHO_PLUGIN_TARGET_DSSI
24 # include "dssi/dssi.h"
25 # if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
26 # error DSSI does not support MIDI output
27 # endif
28 #else
29 # include "ladspa/ladspa.h"
30 # if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
31 # error Cannot use MIDI with LADSPA
32 # endif
33 # if DISTRHO_PLUGIN_WANT_STATE && !defined(DISTRHO_NO_WARNINGS)
34 # warning LADSPA cannot handle states
35 # endif
36 #endif
37
38 #if DISTRHO_PLUGIN_WANT_TIMEPOS && !defined(DISTRHO_NO_WARNINGS)
39 # warning LADSPA/DSSI does not support TimePos
40 #endif
41
42 START_NAMESPACE_DISTRHO
43
44 // -----------------------------------------------------------------------
45
46 class PluginLadspaDssi
47 {
48 public:
PluginLadspaDssi()49 PluginLadspaDssi()
50 : fPlugin(nullptr, nullptr),
51 fPortControls(nullptr),
52 fLastControlValues(nullptr)
53 {
54 #if DISTRHO_PLUGIN_NUM_INPUTS > 0
55 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
56 fPortAudioIns[i] = nullptr;
57 #else
58 fPortAudioIns = nullptr;
59 #endif
60
61 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
62 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
63 fPortAudioOuts[i] = nullptr;
64 #else
65 fPortAudioOuts = nullptr;
66 #endif
67
68 if (const uint32_t count = fPlugin.getParameterCount())
69 {
70 fPortControls = new LADSPA_Data*[count];
71 fLastControlValues = new LADSPA_Data[count];
72
73 for (uint32_t i=0; i < count; ++i)
74 {
75 fPortControls[i] = nullptr;
76 fLastControlValues[i] = fPlugin.getParameterValue(i);
77 }
78 }
79 else
80 {
81 fPortControls = nullptr;
82 fLastControlValues = nullptr;
83 }
84
85 #if DISTRHO_PLUGIN_WANT_LATENCY
86 fPortLatency = nullptr;
87 #endif
88 }
89
~PluginLadspaDssi()90 ~PluginLadspaDssi() noexcept
91 {
92 if (fPortControls != nullptr)
93 {
94 delete[] fPortControls;
95 fPortControls = nullptr;
96 }
97
98 if (fLastControlValues != nullptr)
99 {
100 delete[] fLastControlValues;
101 fLastControlValues = nullptr;
102 }
103 }
104
105 // -------------------------------------------------------------------
106
ladspa_activate()107 void ladspa_activate()
108 {
109 fPlugin.activate();
110 }
111
ladspa_deactivate()112 void ladspa_deactivate()
113 {
114 fPlugin.deactivate();
115 }
116
117 // -------------------------------------------------------------------
118
ladspa_connect_port(const ulong port,LADSPA_Data * const dataLocation)119 void ladspa_connect_port(const ulong port, LADSPA_Data* const dataLocation) noexcept
120 {
121 ulong index = 0;
122
123 #if DISTRHO_PLUGIN_NUM_INPUTS > 0
124 for (ulong i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
125 {
126 if (port == index++)
127 {
128 fPortAudioIns[i] = dataLocation;
129 return;
130 }
131 }
132 #endif
133
134 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
135 for (ulong i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
136 {
137 if (port == index++)
138 {
139 fPortAudioOuts[i] = dataLocation;
140 return;
141 }
142 }
143 #endif
144
145 #if DISTRHO_PLUGIN_WANT_LATENCY
146 if (port == index++)
147 {
148 fPortLatency = dataLocation;
149 return;
150 }
151 #endif
152
153 for (ulong i=0, count=fPlugin.getParameterCount(); i < count; ++i)
154 {
155 if (port == index++)
156 {
157 fPortControls[i] = dataLocation;
158 return;
159 }
160 }
161 }
162
163 // -------------------------------------------------------------------
164
165 #ifdef DISTRHO_PLUGIN_TARGET_DSSI
ladspa_run(const ulong sampleCount)166 void ladspa_run(const ulong sampleCount)
167 {
168 dssi_run_synth(sampleCount, nullptr, 0);
169 }
170
dssi_run_synth(const ulong sampleCount,snd_seq_event_t * const events,const ulong eventCount)171 void dssi_run_synth(const ulong sampleCount, snd_seq_event_t* const events, const ulong eventCount)
172 #else
173 void ladspa_run(const ulong sampleCount)
174 #endif
175 {
176 // pre-roll
177 if (sampleCount == 0)
178 return updateParameterOutputsAndTriggers();
179
180 // Check for updated parameters
181 float curValue;
182
183 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
184 {
185 if (fPortControls[i] == nullptr)
186 continue;
187
188 curValue = *fPortControls[i];
189
190 if (fPlugin.isParameterInput(i) && d_isNotEqual(fLastControlValues[i], curValue))
191 {
192 fLastControlValues[i] = curValue;
193 fPlugin.setParameterValue(i, curValue);
194 }
195 }
196
197 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
198 // Get MIDI Events
199 uint32_t midiEventCount = 0;
200 MidiEvent midiEvents[eventCount];
201
202 for (uint32_t i=0, j; i < eventCount; ++i)
203 {
204 const snd_seq_event_t& seqEvent(events[i]);
205
206 // FIXME
207 if (seqEvent.data.note.channel > 0xF || seqEvent.data.control.channel > 0xF)
208 continue;
209
210 switch (seqEvent.type)
211 {
212 case SND_SEQ_EVENT_NOTEOFF:
213 j = midiEventCount++;
214 midiEvents[j].frame = seqEvent.time.tick;
215 midiEvents[j].size = 3;
216 midiEvents[j].data[0] = 0x80 + seqEvent.data.note.channel;
217 midiEvents[j].data[1] = seqEvent.data.note.note;
218 midiEvents[j].data[2] = 0;
219 midiEvents[j].data[3] = 0;
220 break;
221 case SND_SEQ_EVENT_NOTEON:
222 j = midiEventCount++;
223 midiEvents[j].frame = seqEvent.time.tick;
224 midiEvents[j].size = 3;
225 midiEvents[j].data[0] = 0x90 + seqEvent.data.note.channel;
226 midiEvents[j].data[1] = seqEvent.data.note.note;
227 midiEvents[j].data[2] = seqEvent.data.note.velocity;
228 midiEvents[j].data[3] = 0;
229 break;
230 case SND_SEQ_EVENT_KEYPRESS:
231 j = midiEventCount++;
232 midiEvents[j].frame = seqEvent.time.tick;
233 midiEvents[j].size = 3;
234 midiEvents[j].data[0] = 0xA0 + seqEvent.data.note.channel;
235 midiEvents[j].data[1] = seqEvent.data.note.note;
236 midiEvents[j].data[2] = seqEvent.data.note.velocity;
237 midiEvents[j].data[3] = 0;
238 break;
239 case SND_SEQ_EVENT_CONTROLLER:
240 j = midiEventCount++;
241 midiEvents[j].frame = seqEvent.time.tick;
242 midiEvents[j].size = 3;
243 midiEvents[j].data[0] = 0xB0 + seqEvent.data.control.channel;
244 midiEvents[j].data[1] = seqEvent.data.control.param;
245 midiEvents[j].data[2] = seqEvent.data.control.value;
246 midiEvents[j].data[3] = 0;
247 break;
248 case SND_SEQ_EVENT_CHANPRESS:
249 j = midiEventCount++;
250 midiEvents[j].frame = seqEvent.time.tick;
251 midiEvents[j].size = 2;
252 midiEvents[j].data[0] = 0xD0 + seqEvent.data.control.channel;
253 midiEvents[j].data[1] = seqEvent.data.control.value;
254 midiEvents[j].data[2] = 0;
255 midiEvents[j].data[3] = 0;
256 break;
257 case SND_SEQ_EVENT_PITCHBEND:
258 j = midiEventCount++;
259 midiEvents[j].frame = seqEvent.time.tick;
260 midiEvents[j].size = 3;
261 midiEvents[j].data[0] = 0xE0 + seqEvent.data.control.channel;
262 uint16_t tempvalue = seqEvent.data.control.value + 8192;
263 midiEvents[j].data[1] = tempvalue & 0x7F;
264 midiEvents[j].data[2] = tempvalue >> 7;
265 midiEvents[j].data[3] = 0;
266 break;
267 }
268 }
269
270 fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, midiEvents, midiEventCount);
271 #else
272 fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount);
273 #endif
274
275 updateParameterOutputsAndTriggers();
276
277 #if defined(DISTRHO_PLUGIN_TARGET_DSSI) && ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
278 return; // unused
279 (void)events; (void)eventCount;
280 #endif
281 }
282
283 // -------------------------------------------------------------------
284
285 #ifdef DISTRHO_PLUGIN_TARGET_DSSI
286 # if DISTRHO_PLUGIN_WANT_STATE
dssi_configure(const char * const key,const char * const value)287 char* dssi_configure(const char* const key, const char* const value)
288 {
289 if (std::strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, std::strlen(DSSI_RESERVED_CONFIGURE_PREFIX) == 0))
290 return nullptr;
291 if (std::strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX, std::strlen(DSSI_GLOBAL_CONFIGURE_PREFIX) == 0))
292 return nullptr;
293
294 fPlugin.setState(key, value);
295 return nullptr;
296 }
297 # endif
298
299 # if DISTRHO_PLUGIN_WANT_PROGRAMS
dssi_get_program(const ulong index)300 const DSSI_Program_Descriptor* dssi_get_program(const ulong index)
301 {
302 if (index >= fPlugin.getProgramCount())
303 return nullptr;
304
305 static DSSI_Program_Descriptor desc;
306
307 desc.Bank = index / 128;
308 desc.Program = index % 128;
309 desc.Name = fPlugin.getProgramName(index);
310
311 return &desc;
312 }
313
dssi_select_program(const ulong bank,const ulong program)314 void dssi_select_program(const ulong bank, const ulong program)
315 {
316 const ulong realProgram(bank * 128 + program);
317
318 DISTRHO_SAFE_ASSERT_RETURN(realProgram < fPlugin.getProgramCount(),);
319
320 fPlugin.loadProgram(realProgram);
321
322 // Update control inputs
323 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
324 {
325 if (fPlugin.isParameterOutput(i))
326 continue;
327
328 fLastControlValues[i] = fPlugin.getParameterValue(i);
329
330 if (fPortControls[i] != nullptr)
331 *fPortControls[i] = fLastControlValues[i];
332 }
333 }
334 # endif
335
dssi_get_midi_controller_for_port(const ulong port)336 int dssi_get_midi_controller_for_port(const ulong port) noexcept
337 {
338 const uint32_t parameterOffset = fPlugin.getParameterOffset();
339
340 if (port > parameterOffset)
341 return DSSI_NONE;
342
343 const uint8_t midiCC = fPlugin.getParameterMidiCC(port-parameterOffset);
344
345 if (midiCC == 0 || midiCC == 32 || midiCC >= 0x78)
346 return DSSI_NONE;
347
348 return DSSI_CC(midiCC);
349 }
350 #endif
351
352 // -------------------------------------------------------------------
353
354 private:
355 PluginExporter fPlugin;
356
357 // LADSPA ports
358 #if DISTRHO_PLUGIN_NUM_INPUTS > 0
359 const LADSPA_Data* fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS];
360 #else
361 const LADSPA_Data** fPortAudioIns;
362 #endif
363 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
364 LADSPA_Data* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS];
365 #else
366 LADSPA_Data** fPortAudioOuts;
367 #endif
368 LADSPA_Data** fPortControls;
369 #if DISTRHO_PLUGIN_WANT_LATENCY
370 LADSPA_Data* fPortLatency;
371 #endif
372
373 // Temporary data
374 LADSPA_Data* fLastControlValues;
375
376 // -------------------------------------------------------------------
377
updateParameterOutputsAndTriggers()378 void updateParameterOutputsAndTriggers()
379 {
380 float value;
381
382 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
383 {
384 if (fPlugin.isParameterOutput(i))
385 {
386 value = fLastControlValues[i] = fPlugin.getParameterValue(i);
387
388 if (fPortControls[i] != nullptr)
389 *fPortControls[i] = value;
390 }
391 else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger)
392 {
393 // NOTE: no trigger support in LADSPA control ports, simulate it here
394 value = fPlugin.getParameterRanges(i).def;
395
396 if (d_isEqual(value, fPlugin.getParameterValue(i)))
397 continue;
398
399 fLastControlValues[i] = value;
400 fPlugin.setParameterValue(i, value);
401
402 if (fPortControls[i] != nullptr)
403 *fPortControls[i] = value;
404 }
405 }
406
407 #if DISTRHO_PLUGIN_WANT_LATENCY
408 if (fPortLatency != nullptr)
409 *fPortLatency = fPlugin.getLatency();
410 #endif
411 }
412 };
413
414 // -----------------------------------------------------------------------
415
ladspa_instantiate(const LADSPA_Descriptor *,ulong sampleRate)416 static LADSPA_Handle ladspa_instantiate(const LADSPA_Descriptor*, ulong sampleRate)
417 {
418 if (d_lastBufferSize == 0)
419 d_lastBufferSize = 2048;
420 d_lastSampleRate = sampleRate;
421
422 return new PluginLadspaDssi();
423 }
424
425 #define instancePtr ((PluginLadspaDssi*)instance)
426
ladspa_connect_port(LADSPA_Handle instance,ulong port,LADSPA_Data * dataLocation)427 static void ladspa_connect_port(LADSPA_Handle instance, ulong port, LADSPA_Data* dataLocation)
428 {
429 instancePtr->ladspa_connect_port(port, dataLocation);
430 }
431
ladspa_activate(LADSPA_Handle instance)432 static void ladspa_activate(LADSPA_Handle instance)
433 {
434 instancePtr->ladspa_activate();
435 }
436
ladspa_run(LADSPA_Handle instance,ulong sampleCount)437 static void ladspa_run(LADSPA_Handle instance, ulong sampleCount)
438 {
439 instancePtr->ladspa_run(sampleCount);
440 }
441
ladspa_deactivate(LADSPA_Handle instance)442 static void ladspa_deactivate(LADSPA_Handle instance)
443 {
444 instancePtr->ladspa_deactivate();
445 }
446
ladspa_cleanup(LADSPA_Handle instance)447 static void ladspa_cleanup(LADSPA_Handle instance)
448 {
449 delete instancePtr;
450 }
451
452 #ifdef DISTRHO_PLUGIN_TARGET_DSSI
453 # if DISTRHO_PLUGIN_WANT_STATE
dssi_configure(LADSPA_Handle instance,const char * key,const char * value)454 static char* dssi_configure(LADSPA_Handle instance, const char* key, const char* value)
455 {
456 return instancePtr->dssi_configure(key, value);
457 }
458 # endif
459
460 # if DISTRHO_PLUGIN_WANT_PROGRAMS
dssi_get_program(LADSPA_Handle instance,ulong index)461 static const DSSI_Program_Descriptor* dssi_get_program(LADSPA_Handle instance, ulong index)
462 {
463 return instancePtr->dssi_get_program(index);
464 }
465
dssi_select_program(LADSPA_Handle instance,ulong bank,ulong program)466 static void dssi_select_program(LADSPA_Handle instance, ulong bank, ulong program)
467 {
468 instancePtr->dssi_select_program(bank, program);
469 }
470 # endif
471
dssi_get_midi_controller_for_port(LADSPA_Handle instance,ulong port)472 static int dssi_get_midi_controller_for_port(LADSPA_Handle instance, ulong port)
473 {
474 return instancePtr->dssi_get_midi_controller_for_port(port);
475 }
476
477 # if DISTRHO_PLUGIN_WANT_MIDI_INPUT
dssi_run_synth(LADSPA_Handle instance,ulong sampleCount,snd_seq_event_t * events,ulong eventCount)478 static void dssi_run_synth(LADSPA_Handle instance, ulong sampleCount, snd_seq_event_t* events, ulong eventCount)
479 {
480 instancePtr->dssi_run_synth(sampleCount, events, eventCount);
481 }
482 # endif
483 #endif
484
485 #undef instancePtr
486
487 // -----------------------------------------------------------------------
488
489 static LADSPA_Descriptor sLadspaDescriptor = {
490 /* UniqueID */ 0,
491 /* Label */ nullptr,
492 #if DISTRHO_PLUGIN_IS_RT_SAFE
493 /* Properties */ LADSPA_PROPERTY_HARD_RT_CAPABLE,
494 #else
495 /* Properties */ 0x0,
496 #endif
497 /* Name */ nullptr,
498 /* Maker */ nullptr,
499 /* Copyright */ nullptr,
500 /* PortCount */ 0,
501 /* PortDescriptors */ nullptr,
502 /* PortNames */ nullptr,
503 /* PortRangeHints */ nullptr,
504 /* ImplementationData */ nullptr,
505 ladspa_instantiate,
506 ladspa_connect_port,
507 ladspa_activate,
508 ladspa_run,
509 /* run_adding */ nullptr,
510 /* set_run_adding_gain */ nullptr,
511 ladspa_deactivate,
512 ladspa_cleanup
513 };
514
515 #ifdef DISTRHO_PLUGIN_TARGET_DSSI
516 static DSSI_Descriptor sDssiDescriptor = {
517 1,
518 &sLadspaDescriptor,
519 # if DISTRHO_PLUGIN_WANT_STATE
520 dssi_configure,
521 # else
522 /* configure */ nullptr,
523 # endif
524 # if DISTRHO_PLUGIN_WANT_PROGRAMS
525 dssi_get_program,
526 dssi_select_program,
527 # else
528 /* get_program */ nullptr,
529 /* select_program */ nullptr,
530 # endif
531 dssi_get_midi_controller_for_port,
532 # if DISTRHO_PLUGIN_WANT_MIDI_INPUT
533 dssi_run_synth,
534 # else
535 /* run_synth */ nullptr,
536 # endif
537 /* run_synth_adding */ nullptr,
538 /* run_multiple_synths */ nullptr,
539 /* run_multiple_synths_adding */ nullptr,
540 nullptr, nullptr
541 };
542 #endif
543
544 // -----------------------------------------------------------------------
545
546 class DescriptorInitializer
547 {
548 public:
DescriptorInitializer()549 DescriptorInitializer()
550 {
551 // Create dummy plugin to get data from
552 d_lastBufferSize = 512;
553 d_lastSampleRate = 44100.0;
554 PluginExporter plugin(nullptr, nullptr);
555 d_lastBufferSize = 0;
556 d_lastSampleRate = 0.0;
557
558 // Get port count, init
559 ulong port = 0;
560 ulong portCount = DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS + plugin.getParameterCount();
561 #if DISTRHO_PLUGIN_WANT_LATENCY
562 portCount += 1;
563 #endif
564 const char** const portNames = new const char*[portCount];
565 LADSPA_PortDescriptor* portDescriptors = new LADSPA_PortDescriptor[portCount];
566 LADSPA_PortRangeHint* portRangeHints = new LADSPA_PortRangeHint [portCount];
567
568 // Set ports
569 #if DISTRHO_PLUGIN_NUM_INPUTS > 0
570 for (ulong i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++port)
571 {
572 const AudioPort& aport(plugin.getAudioPort(true, i));
573
574 portNames[port] = strdup(aport.name);
575 portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT;
576
577 portRangeHints[port].HintDescriptor = 0x0;
578 portRangeHints[port].LowerBound = 0.0f;
579 portRangeHints[port].UpperBound = 1.0f;
580 }
581 #endif
582
583 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
584 for (ulong i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++port)
585 {
586 const AudioPort& aport(plugin.getAudioPort(false, i));
587
588 portNames[port] = strdup(aport.name);
589 portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT;
590
591 portRangeHints[port].HintDescriptor = 0x0;
592 portRangeHints[port].LowerBound = 0.0f;
593 portRangeHints[port].UpperBound = 1.0f;
594 }
595 #endif
596
597 #if DISTRHO_PLUGIN_WANT_LATENCY
598 // Set latency port
599 portNames[port] = strdup("_latency");
600 portDescriptors[port] = LADSPA_PORT_CONTROL | LADSPA_PORT_OUTPUT;
601 portRangeHints[port].HintDescriptor = LADSPA_HINT_SAMPLE_RATE|LADSPA_HINT_INTEGER;
602 portRangeHints[port].LowerBound = 0.0f;
603 portRangeHints[port].UpperBound = 1.0f;
604 ++port;
605 #endif
606
607 for (ulong i=0, count=plugin.getParameterCount(); i < count; ++i, ++port)
608 {
609 portNames[port] = strdup((const char*)plugin.getParameterName(i));
610 portDescriptors[port] = LADSPA_PORT_CONTROL;
611
612 if (plugin.isParameterOutput(i))
613 portDescriptors[port] |= LADSPA_PORT_OUTPUT;
614 else
615 portDescriptors[port] |= LADSPA_PORT_INPUT;
616
617 {
618 const ParameterRanges& ranges(plugin.getParameterRanges(i));
619 const float defValue(ranges.def);
620
621 portRangeHints[port].HintDescriptor = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
622 portRangeHints[port].LowerBound = ranges.min;
623 portRangeHints[port].UpperBound = ranges.max;
624
625 if (defValue == 0.0f)
626 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_0;
627 else if (defValue == 1.0f)
628 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_1;
629 else if (defValue == 100.0f)
630 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_100;
631 else if (defValue == 440.0f)
632 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_440;
633 else if (ranges.min == defValue)
634 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MINIMUM;
635 else if (ranges.max == defValue)
636 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MAXIMUM;
637 else
638 {
639 const float middleValue = ranges.min/2.0f + ranges.max/2.0f;
640 const float middleLow = (ranges.min/2.0f + middleValue/2.0f)/2.0f + middleValue/2.0f;
641 const float middleHigh = (ranges.max/2.0f + middleValue/2.0f)/2.0f + middleValue/2.0f;
642
643 if (defValue < middleLow)
644 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_LOW;
645 else if (defValue > middleHigh)
646 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_HIGH;
647 else
648 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MIDDLE;
649 }
650 }
651
652 {
653 const uint32_t hints(plugin.getParameterHints(i));
654
655 if (hints & kParameterIsBoolean)
656 {
657 portRangeHints[port].HintDescriptor |= LADSPA_HINT_TOGGLED;
658 }
659 else
660 {
661 if (hints & kParameterIsInteger)
662 portRangeHints[port].HintDescriptor |= LADSPA_HINT_INTEGER;
663 if (hints & kParameterIsLogarithmic)
664 portRangeHints[port].HintDescriptor |= LADSPA_HINT_LOGARITHMIC;
665 }
666 }
667 }
668
669 // Set data
670 sLadspaDescriptor.UniqueID = plugin.getUniqueId();
671 sLadspaDescriptor.Label = strdup(plugin.getLabel());
672 sLadspaDescriptor.Name = strdup(plugin.getName());
673 sLadspaDescriptor.Maker = strdup(plugin.getMaker());
674 sLadspaDescriptor.Copyright = strdup(plugin.getLicense());
675 sLadspaDescriptor.PortCount = portCount;
676 sLadspaDescriptor.PortNames = portNames;
677 sLadspaDescriptor.PortDescriptors = portDescriptors;
678 sLadspaDescriptor.PortRangeHints = portRangeHints;
679 }
680
~DescriptorInitializer()681 ~DescriptorInitializer()
682 {
683 if (sLadspaDescriptor.Label != nullptr)
684 {
685 std::free((void*)sLadspaDescriptor.Label);
686 sLadspaDescriptor.Label = nullptr;
687 }
688
689 if (sLadspaDescriptor.Name != nullptr)
690 {
691 std::free((void*)sLadspaDescriptor.Name);
692 sLadspaDescriptor.Name = nullptr;
693 }
694
695 if (sLadspaDescriptor.Maker != nullptr)
696 {
697 std::free((void*)sLadspaDescriptor.Maker);
698 sLadspaDescriptor.Maker = nullptr;
699 }
700
701 if (sLadspaDescriptor.Copyright != nullptr)
702 {
703 std::free((void*)sLadspaDescriptor.Copyright);
704 sLadspaDescriptor.Copyright = nullptr;
705 }
706
707 if (sLadspaDescriptor.PortDescriptors != nullptr)
708 {
709 delete[] sLadspaDescriptor.PortDescriptors;
710 sLadspaDescriptor.PortDescriptors = nullptr;
711 }
712
713 if (sLadspaDescriptor.PortRangeHints != nullptr)
714 {
715 delete[] sLadspaDescriptor.PortRangeHints;
716 sLadspaDescriptor.PortRangeHints = nullptr;
717 }
718
719 if (sLadspaDescriptor.PortNames != nullptr)
720 {
721 for (ulong i=0; i < sLadspaDescriptor.PortCount; ++i)
722 {
723 if (sLadspaDescriptor.PortNames[i] != nullptr)
724 std::free((void*)sLadspaDescriptor.PortNames[i]);
725 }
726
727 delete[] sLadspaDescriptor.PortNames;
728 sLadspaDescriptor.PortNames = nullptr;
729 }
730 }
731 };
732
733 static DescriptorInitializer sDescInit;
734
735 // -----------------------------------------------------------------------
736
737 END_NAMESPACE_DISTRHO
738
739 DISTRHO_PLUGIN_EXPORT
ladspa_descriptor(ulong index)740 const LADSPA_Descriptor* ladspa_descriptor(ulong index)
741 {
742 USE_NAMESPACE_DISTRHO
743 return (index == 0) ? &sLadspaDescriptor : nullptr;
744 }
745
746 #ifdef DISTRHO_PLUGIN_TARGET_DSSI
747 DISTRHO_PLUGIN_EXPORT
dssi_descriptor(ulong index)748 const DSSI_Descriptor* dssi_descriptor(ulong index)
749 {
750 USE_NAMESPACE_DISTRHO
751 return (index == 0) ? &sDssiDescriptor : nullptr;
752 }
753 #endif
754
755 // -----------------------------------------------------------------------
756