1 /*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2021 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 #include "lv2/atom.h"
20 #include "lv2/atom-util.h"
21 #include "lv2/buf-size.h"
22 #include "lv2/data-access.h"
23 #include "lv2/instance-access.h"
24 #include "lv2/midi.h"
25 #include "lv2/options.h"
26 #include "lv2/parameters.h"
27 #include "lv2/patch.h"
28 #include "lv2/state.h"
29 #include "lv2/time.h"
30 #include "lv2/urid.h"
31 #include "lv2/worker.h"
32 #include "lv2/lv2_kxstudio_properties.h"
33 #include "lv2/lv2_programs.h"
34 #include "lv2/control-input-port-change-request.h"
35
36 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
37 # include "libmodla.h"
38 #endif
39
40 #ifdef noexcept
41 # undef noexcept
42 #endif
43
44 #include <map>
45
46 #ifndef DISTRHO_PLUGIN_URI
47 # error DISTRHO_PLUGIN_URI undefined!
48 #endif
49
50 #ifndef DISTRHO_PLUGIN_LV2_STATE_PREFIX
51 # define DISTRHO_PLUGIN_LV2_STATE_PREFIX "urn:distrho:"
52 #endif
53
54 #define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) || DISTRHO_PLUGIN_WANT_STATEFILES)
55 #define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI))
56
57 START_NAMESPACE_DISTRHO
58
59 typedef std::map<const String, String> StringToStringMap;
60 typedef std::map<const LV2_URID, String> UridToStringMap;
61
62 #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
63 static const writeMidiFunc writeMidiCallback = nullptr;
64 #endif
65 #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
66 static const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr;
67 #endif
68
69 // -----------------------------------------------------------------------
70
71 class PluginLv2
72 {
73 public:
PluginLv2(const double sampleRate,const LV2_URID_Map * const uridMap,const LV2_Worker_Schedule * const worker,const LV2_ControlInputPort_Change_Request * const ctrlInPortChangeReq,const bool usingNominal)74 PluginLv2(const double sampleRate,
75 const LV2_URID_Map* const uridMap,
76 const LV2_Worker_Schedule* const worker,
77 const LV2_ControlInputPort_Change_Request* const ctrlInPortChangeReq,
78 const bool usingNominal)
79 : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback),
80 fUsingNominal(usingNominal),
81 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
82 fRunCount(0),
83 #endif
84 fPortControls(nullptr),
85 fLastControlValues(nullptr),
86 fSampleRate(sampleRate),
87 fURIDs(uridMap),
88 #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
89 fCtrlInPortChangeReq(ctrlInPortChangeReq),
90 #endif
91 fUridMap(uridMap),
92 fWorker(worker)
93 {
94 #if DISTRHO_PLUGIN_NUM_INPUTS > 0
95 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
96 fPortAudioIns[i] = nullptr;
97 #else
98 fPortAudioIns = nullptr;
99 #endif
100
101 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
102 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
103 fPortAudioOuts[i] = nullptr;
104 #else
105 fPortAudioOuts = nullptr;
106 #endif
107
108 if (const uint32_t count = fPlugin.getParameterCount())
109 {
110 fPortControls = new float*[count];
111 fLastControlValues = new float[count];
112
113 for (uint32_t i=0; i < count; ++i)
114 {
115 fPortControls[i] = nullptr;
116 fLastControlValues[i] = fPlugin.getParameterValue(i);
117 }
118 }
119 else
120 {
121 fPortControls = nullptr;
122 fLastControlValues = nullptr;
123 }
124
125 #if DISTRHO_LV2_USE_EVENTS_IN
126 fPortEventsIn = nullptr;
127 #endif
128 #if DISTRHO_PLUGIN_WANT_LATENCY
129 fPortLatency = nullptr;
130 #endif
131
132 #if DISTRHO_PLUGIN_WANT_STATE
133 if (const uint32_t count = fPlugin.getStateCount())
134 {
135 fNeededUiSends = new bool[count];
136
137 for (uint32_t i=0; i < count; ++i)
138 {
139 fNeededUiSends[i] = false;
140
141 const String& dkey(fPlugin.getStateKey(i));
142 fStateMap[dkey] = fPlugin.getStateDefaultValue(i);
143
144 # if DISTRHO_PLUGIN_WANT_STATEFILES
145 if (fPlugin.isStateFile(i))
146 {
147 const String dpf_lv2_key(DISTRHO_PLUGIN_URI "#" + dkey);
148 const LV2_URID urid = uridMap->map(uridMap->handle, dpf_lv2_key.buffer());
149 fUridStateFileMap[urid] = dkey;
150 }
151 # endif
152 }
153 }
154 else
155 {
156 fNeededUiSends = nullptr;
157 }
158 #else
159 // unused
160 (void)fWorker;
161 #endif
162
163 #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
164 // unused
165 (void)ctrlInPortChangeReq;
166 #endif
167 }
168
~PluginLv2()169 ~PluginLv2()
170 {
171 if (fPortControls != nullptr)
172 {
173 delete[] fPortControls;
174 fPortControls = nullptr;
175 }
176
177 if (fLastControlValues)
178 {
179 delete[] fLastControlValues;
180 fLastControlValues = nullptr;
181 }
182
183 #if DISTRHO_PLUGIN_WANT_STATE
184 if (fNeededUiSends != nullptr)
185 {
186 delete[] fNeededUiSends;
187 fNeededUiSends = nullptr;
188 }
189
190 fStateMap.clear();
191 #endif
192 }
193
194 // -------------------------------------------------------------------
195
getPortControlValue(uint32_t index,float & value) const196 bool getPortControlValue(uint32_t index, float& value) const
197 {
198 if (const float* control = fPortControls[index])
199 {
200 switch (fPlugin.getParameterDesignation(index))
201 {
202 default:
203 value = *control;
204 break;
205 case kParameterDesignationBypass:
206 value = 1.0f - *control;
207 break;
208 }
209
210 return true;
211 }
212
213 return false;
214 }
215
setPortControlValue(uint32_t index,float value)216 void setPortControlValue(uint32_t index, float value)
217 {
218 if (float* control = fPortControls[index])
219 {
220 switch (fPlugin.getParameterDesignation(index))
221 {
222 default:
223 *control = value;
224 break;
225 case kParameterDesignationBypass:
226 *control = 1.0f - value;
227 break;
228 }
229 }
230 }
231
232 // -------------------------------------------------------------------
233
lv2_activate()234 void lv2_activate()
235 {
236 #if DISTRHO_PLUGIN_WANT_TIMEPOS
237 fTimePosition.clear();
238
239 // hosts may not send all values, resulting on some invalid data, let's reset everything
240 fTimePosition.bbt.bar = 1;
241 fTimePosition.bbt.beat = 1;
242 fTimePosition.bbt.tick = 0.0;
243 fTimePosition.bbt.barStartTick = 0;
244 fTimePosition.bbt.beatsPerBar = 4;
245 fTimePosition.bbt.beatType = 4;
246 fTimePosition.bbt.ticksPerBeat = 1920.0;
247 fTimePosition.bbt.beatsPerMinute = 120.0;
248 #endif
249 fPlugin.activate();
250 }
251
lv2_deactivate()252 void lv2_deactivate()
253 {
254 fPlugin.deactivate();
255 }
256
257 // -------------------------------------------------------------------
258
lv2_connect_port(const uint32_t port,void * const dataLocation)259 void lv2_connect_port(const uint32_t port, void* const dataLocation)
260 {
261 uint32_t index = 0;
262
263 #if DISTRHO_PLUGIN_NUM_INPUTS > 0
264 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
265 {
266 if (port == index++)
267 {
268 fPortAudioIns[i] = (const float*)dataLocation;
269 return;
270 }
271 }
272 #endif
273
274 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
275 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
276 {
277 if (port == index++)
278 {
279 fPortAudioOuts[i] = (float*)dataLocation;
280 return;
281 }
282 }
283 #endif
284
285 #if DISTRHO_LV2_USE_EVENTS_IN
286 if (port == index++)
287 {
288 fPortEventsIn = (LV2_Atom_Sequence*)dataLocation;
289 return;
290 }
291 #endif
292
293 #if DISTRHO_LV2_USE_EVENTS_OUT
294 if (port == index++)
295 {
296 fEventsOutData.port = (LV2_Atom_Sequence*)dataLocation;
297 return;
298 }
299 #endif
300
301 #if DISTRHO_PLUGIN_WANT_LATENCY
302 if (port == index++)
303 {
304 fPortLatency = (float*)dataLocation;
305 return;
306 }
307 #endif
308
309 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
310 {
311 if (port == index++)
312 {
313 fPortControls[i] = (float*)dataLocation;
314 return;
315 }
316 }
317 }
318
319 // -------------------------------------------------------------------
320
lv2_run(const uint32_t sampleCount)321 void lv2_run(const uint32_t sampleCount)
322 {
323 // cache midi input and time position first
324 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
325 uint32_t midiEventCount = 0;
326 #endif
327
328 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS
329 LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event)
330 {
331 if (event == nullptr)
332 break;
333
334 # if DISTRHO_PLUGIN_WANT_MIDI_INPUT
335 if (event->body.type == fURIDs.midiEvent)
336 {
337 if (midiEventCount >= kMaxMidiEvents)
338 continue;
339
340 const uint8_t* const data((const uint8_t*)(event + 1));
341
342 MidiEvent& midiEvent(fMidiEvents[midiEventCount++]);
343
344 midiEvent.frame = event->time.frames;
345 midiEvent.size = event->body.size;
346
347 if (midiEvent.size > MidiEvent::kDataSize)
348 {
349 midiEvent.dataExt = data;
350 std::memset(midiEvent.data, 0, MidiEvent::kDataSize);
351 }
352 else
353 {
354 midiEvent.dataExt = nullptr;
355 std::memcpy(midiEvent.data, data, midiEvent.size);
356 }
357
358 continue;
359 }
360 # endif
361 # if DISTRHO_PLUGIN_WANT_TIMEPOS
362 if (event->body.type == fURIDs.atomBlank || event->body.type == fURIDs.atomObject)
363 {
364 const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body);
365
366 if (obj->body.otype != fURIDs.timePosition)
367 continue;
368
369 LV2_Atom* bar = nullptr;
370 LV2_Atom* barBeat = nullptr;
371 LV2_Atom* beatUnit = nullptr;
372 LV2_Atom* beatsPerBar = nullptr;
373 LV2_Atom* beatsPerMinute = nullptr;
374 LV2_Atom* frame = nullptr;
375 LV2_Atom* speed = nullptr;
376 LV2_Atom* ticksPerBeat = nullptr;
377
378 lv2_atom_object_get(obj,
379 fURIDs.timeBar, &bar,
380 fURIDs.timeBarBeat, &barBeat,
381 fURIDs.timeBeatUnit, &beatUnit,
382 fURIDs.timeBeatsPerBar, &beatsPerBar,
383 fURIDs.timeBeatsPerMinute, &beatsPerMinute,
384 fURIDs.timeFrame, &frame,
385 fURIDs.timeSpeed, &speed,
386 fURIDs.timeTicksPerBeat, &ticksPerBeat,
387 0);
388
389 // need to handle this first as other values depend on it
390 if (ticksPerBeat != nullptr)
391 {
392 /**/ if (ticksPerBeat->type == fURIDs.atomDouble)
393 fLastPositionData.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body;
394 else if (ticksPerBeat->type == fURIDs.atomFloat)
395 fLastPositionData.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body;
396 else if (ticksPerBeat->type == fURIDs.atomInt)
397 fLastPositionData.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body;
398 else if (ticksPerBeat->type == fURIDs.atomLong)
399 fLastPositionData.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body;
400 else
401 d_stderr("Unknown lv2 ticksPerBeat value type");
402
403 if (fLastPositionData.ticksPerBeat > 0.0)
404 fTimePosition.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat;
405 }
406
407 // same
408 if (speed != nullptr)
409 {
410 /**/ if (speed->type == fURIDs.atomDouble)
411 fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body;
412 else if (speed->type == fURIDs.atomFloat)
413 fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body;
414 else if (speed->type == fURIDs.atomInt)
415 fLastPositionData.speed = ((LV2_Atom_Int*)speed)->body;
416 else if (speed->type == fURIDs.atomLong)
417 fLastPositionData.speed = ((LV2_Atom_Long*)speed)->body;
418 else
419 d_stderr("Unknown lv2 speed value type");
420
421 fTimePosition.playing = d_isNotZero(fLastPositionData.speed);
422 }
423
424 if (bar != nullptr)
425 {
426 /**/ if (bar->type == fURIDs.atomDouble)
427 fLastPositionData.bar = ((LV2_Atom_Double*)bar)->body;
428 else if (bar->type == fURIDs.atomFloat)
429 fLastPositionData.bar = ((LV2_Atom_Float*)bar)->body;
430 else if (bar->type == fURIDs.atomInt)
431 fLastPositionData.bar = ((LV2_Atom_Int*)bar)->body;
432 else if (bar->type == fURIDs.atomLong)
433 fLastPositionData.bar = ((LV2_Atom_Long*)bar)->body;
434 else
435 d_stderr("Unknown lv2 bar value type");
436
437 if (fLastPositionData.bar >= 0)
438 fTimePosition.bbt.bar = fLastPositionData.bar + 1;
439 }
440
441 if (barBeat != nullptr)
442 {
443 /**/ if (barBeat->type == fURIDs.atomDouble)
444 fLastPositionData.barBeat = ((LV2_Atom_Double*)barBeat)->body;
445 else if (barBeat->type == fURIDs.atomFloat)
446 fLastPositionData.barBeat = ((LV2_Atom_Float*)barBeat)->body;
447 else if (barBeat->type == fURIDs.atomInt)
448 fLastPositionData.barBeat = ((LV2_Atom_Int*)barBeat)->body;
449 else if (barBeat->type == fURIDs.atomLong)
450 fLastPositionData.barBeat = ((LV2_Atom_Long*)barBeat)->body;
451 else
452 d_stderr("Unknown lv2 barBeat value type");
453
454 if (fLastPositionData.barBeat >= 0.0f)
455 {
456 const double rest = std::fmod(fLastPositionData.barBeat, 1.0f);
457 fTimePosition.bbt.beat = std::round(fLastPositionData.barBeat - rest + 1.0);
458 fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat;
459 }
460 }
461
462 if (beatUnit != nullptr)
463 {
464 /**/ if (beatUnit->type == fURIDs.atomDouble)
465 fLastPositionData.beatUnit = ((LV2_Atom_Double*)beatUnit)->body;
466 else if (beatUnit->type == fURIDs.atomFloat)
467 fLastPositionData.beatUnit = ((LV2_Atom_Float*)beatUnit)->body;
468 else if (beatUnit->type == fURIDs.atomInt)
469 fLastPositionData.beatUnit = ((LV2_Atom_Int*)beatUnit)->body;
470 else if (beatUnit->type == fURIDs.atomLong)
471 fLastPositionData.beatUnit = ((LV2_Atom_Long*)beatUnit)->body;
472 else
473 d_stderr("Unknown lv2 beatUnit value type");
474
475 if (fLastPositionData.beatUnit > 0)
476 fTimePosition.bbt.beatType = fLastPositionData.beatUnit;
477 }
478
479 if (beatsPerBar != nullptr)
480 {
481 /**/ if (beatsPerBar->type == fURIDs.atomDouble)
482 fLastPositionData.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body;
483 else if (beatsPerBar->type == fURIDs.atomFloat)
484 fLastPositionData.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body;
485 else if (beatsPerBar->type == fURIDs.atomInt)
486 fLastPositionData.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body;
487 else if (beatsPerBar->type == fURIDs.atomLong)
488 fLastPositionData.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body;
489 else
490 d_stderr("Unknown lv2 beatsPerBar value type");
491
492 if (fLastPositionData.beatsPerBar > 0.0f)
493 fTimePosition.bbt.beatsPerBar = fLastPositionData.beatsPerBar;
494 }
495
496 if (beatsPerMinute != nullptr)
497 {
498 /**/ if (beatsPerMinute->type == fURIDs.atomDouble)
499 fLastPositionData.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body;
500 else if (beatsPerMinute->type == fURIDs.atomFloat)
501 fLastPositionData.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body;
502 else if (beatsPerMinute->type == fURIDs.atomInt)
503 fLastPositionData.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body;
504 else if (beatsPerMinute->type == fURIDs.atomLong)
505 fLastPositionData.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body;
506 else
507 d_stderr("Unknown lv2 beatsPerMinute value type");
508
509 if (fLastPositionData.beatsPerMinute > 0.0f)
510 {
511 fTimePosition.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute;
512
513 if (d_isNotZero(fLastPositionData.speed))
514 fTimePosition.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed);
515 }
516 }
517
518 if (frame != nullptr)
519 {
520 /**/ if (frame->type == fURIDs.atomDouble)
521 fLastPositionData.frame = ((LV2_Atom_Double*)frame)->body;
522 else if (frame->type == fURIDs.atomFloat)
523 fLastPositionData.frame = ((LV2_Atom_Float*)frame)->body;
524 else if (frame->type == fURIDs.atomInt)
525 fLastPositionData.frame = ((LV2_Atom_Int*)frame)->body;
526 else if (frame->type == fURIDs.atomLong)
527 fLastPositionData.frame = ((LV2_Atom_Long*)frame)->body;
528 else
529 d_stderr("Unknown lv2 frame value type");
530
531 if (fLastPositionData.frame >= 0)
532 fTimePosition.frame = fLastPositionData.frame;
533 }
534
535 fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*
536 fTimePosition.bbt.beatsPerBar*
537 (fTimePosition.bbt.bar-1);
538
539 fTimePosition.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 &&
540 fLastPositionData.beatUnit > 0 &&
541 fLastPositionData.beatsPerBar > 0.0f);
542
543 fPlugin.setTimePosition(fTimePosition);
544
545 continue;
546 }
547 # endif
548 }
549 #endif
550
551 // check for messages from UI or files
552 #if DISTRHO_PLUGIN_WANT_STATE && (DISTRHO_PLUGIN_HAS_UI || DISTRHO_PLUGIN_WANT_STATEFILES)
553 LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event)
554 {
555 if (event == nullptr)
556 break;
557
558 if (event->body.type == fURIDs.dpfKeyValue)
559 {
560 const void* const data = (const void*)(event + 1);
561
562 // check if this is our special message
563 if (std::strcmp((const char*)data, "__dpf_ui_data__") == 0)
564 {
565 for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
566 fNeededUiSends[i] = true;
567 }
568 // no, send to DSP as usual
569 else if (fWorker != nullptr)
570 {
571 fWorker->schedule_work(fWorker->handle, sizeof(LV2_Atom)+event->body.size, &event->body);
572 }
573 }
574 # if DISTRHO_PLUGIN_WANT_STATEFILES
575 else if (event->body.type == fURIDs.atomObject && fWorker != nullptr)
576 {
577 const LV2_Atom_Object* const object = (const LV2_Atom_Object*)&event->body;
578
579 const LV2_Atom* property = nullptr;
580 const LV2_Atom* value = nullptr;
581 lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr);
582
583 if (property != nullptr && property->type == fURIDs.atomURID &&
584 value != nullptr && value->type == fURIDs.atomPath)
585 {
586 fWorker->schedule_work(fWorker->handle, sizeof(LV2_Atom)+event->body.size, &event->body);
587 }
588 }
589 # endif
590 }
591 #endif
592
593 // Check for updated parameters
594 float curValue;
595
596 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
597 {
598 if (!getPortControlValue(i, curValue))
599 continue;
600
601 if (fPlugin.isParameterInput(i) && d_isNotEqual(fLastControlValues[i], curValue))
602 {
603 fLastControlValues[i] = curValue;
604
605 fPlugin.setParameterValue(i, curValue);
606 }
607 }
608
609 // Run plugin
610 if (sampleCount != 0)
611 {
612 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
613 fRunCount = mod_license_run_begin(fRunCount, sampleCount);
614 #endif
615
616 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
617 fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, fMidiEvents, midiEventCount);
618 #else
619 fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount);
620 #endif
621
622 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
623 for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
624 mod_license_run_silence(fRunCount, fPortAudioOuts[i], sampleCount, i);
625 #endif
626
627 #if DISTRHO_PLUGIN_WANT_TIMEPOS
628 // update timePos for next callback
629 if (d_isNotZero(fLastPositionData.speed))
630 {
631 if (fLastPositionData.speed > 0.0)
632 {
633 // playing forwards
634 fLastPositionData.frame += sampleCount;
635 }
636 else
637 {
638 // playing backwards
639 fLastPositionData.frame -= sampleCount;
640
641 if (fLastPositionData.frame < 0)
642 fLastPositionData.frame = 0;
643 }
644
645 fTimePosition.frame = fLastPositionData.frame;
646
647 if (fTimePosition.bbt.valid)
648 {
649 const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed;
650 const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute;
651 const double addedBarBeats = double(sampleCount) / framesPerBeat;
652
653 if (fLastPositionData.barBeat >= 0.0f)
654 {
655 fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+addedBarBeats,
656 (double)fLastPositionData.beatsPerBar);
657
658 const double rest = std::fmod(fLastPositionData.barBeat, 1.0f);
659 fTimePosition.bbt.beat = std::round(fLastPositionData.barBeat - rest + 1.0);
660 fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat;
661
662 if (fLastPositionData.bar >= 0)
663 {
664 fLastPositionData.bar += std::floor((fLastPositionData.barBeat+addedBarBeats)/
665 fLastPositionData.beatsPerBar);
666
667 if (fLastPositionData.bar < 0)
668 fLastPositionData.bar = 0;
669
670 fTimePosition.bbt.bar = fLastPositionData.bar + 1;
671
672 fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*
673 fTimePosition.bbt.beatsPerBar*
674 (fTimePosition.bbt.bar-1);
675 }
676 }
677
678 fTimePosition.bbt.beatsPerMinute = std::abs(beatsPerMinute);
679 }
680
681 fPlugin.setTimePosition(fTimePosition);
682 }
683 #endif
684 }
685
686 updateParameterOutputsAndTriggers();
687
688 #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI
689 fEventsOutData.initIfNeeded(fURIDs.atomSequence);
690
691 LV2_Atom_Event* aev;
692 const uint32_t capacity = fEventsOutData.capacity;
693
694 for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
695 {
696 if (! fNeededUiSends[i])
697 continue;
698
699 const String& curKey(fPlugin.getStateKey(i));
700
701 for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
702 {
703 const String& key(cit->first);
704
705 if (curKey != key)
706 continue;
707
708 const String& value(cit->second);
709
710 // set msg size (key + value + separator + 2x null terminator)
711 const size_t msgSize = key.length()+value.length()+3;
712
713 if (sizeof(LV2_Atom_Event) + msgSize > capacity - fEventsOutData.offset)
714 {
715 d_stdout("Sending key '%s' to UI failed, out of space", key.buffer());
716 break;
717 }
718
719 // put data
720 aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + fEventsOutData.offset);
721 aev->time.frames = 0;
722 aev->body.type = fURIDs.dpfKeyValue;
723 aev->body.size = msgSize;
724
725 uint8_t* const msgBuf = LV2_ATOM_BODY(&aev->body);
726 std::memset(msgBuf, 0, msgSize);
727
728 // write key and value in atom buffer
729 std::memcpy(msgBuf, key.buffer(), key.length()+1);
730 std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()+1);
731
732 fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize));
733
734 fNeededUiSends[i] = false;
735 break;
736 }
737 }
738 #endif
739
740 #if DISTRHO_LV2_USE_EVENTS_OUT
741 fEventsOutData.endRun();
742 #endif
743 }
744
745 // -------------------------------------------------------------------
746
lv2_get_options(LV2_Options_Option * const)747 uint32_t lv2_get_options(LV2_Options_Option* const /*options*/)
748 {
749 // currently unused
750 return LV2_OPTIONS_ERR_UNKNOWN;
751 }
752
lv2_set_options(const LV2_Options_Option * const options)753 uint32_t lv2_set_options(const LV2_Options_Option* const options)
754 {
755 for (int i=0; options[i].key != 0; ++i)
756 {
757 if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__nominalBlockLength))
758 {
759 if (options[i].type == fURIDs.atomInt)
760 {
761 const int32_t bufferSize(*(const int32_t*)options[i].value);
762 fPlugin.setBufferSize(bufferSize);
763 }
764 else
765 {
766 d_stderr("Host changed nominalBlockLength but with wrong value type");
767 }
768 }
769 else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__maxBlockLength) && ! fUsingNominal)
770 {
771 if (options[i].type == fURIDs.atomInt)
772 {
773 const int32_t bufferSize(*(const int32_t*)options[i].value);
774 fPlugin.setBufferSize(bufferSize);
775 }
776 else
777 {
778 d_stderr("Host changed maxBlockLength but with wrong value type");
779 }
780 }
781 else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_PARAMETERS__sampleRate))
782 {
783 if (options[i].type == fURIDs.atomFloat)
784 {
785 const float sampleRate(*(const float*)options[i].value);
786 fSampleRate = sampleRate;
787 fPlugin.setSampleRate(sampleRate);
788 }
789 else
790 {
791 d_stderr("Host changed sampleRate but with wrong value type");
792 }
793 }
794 }
795
796 return LV2_OPTIONS_SUCCESS;
797 }
798
799 // -------------------------------------------------------------------
800
801 #if DISTRHO_PLUGIN_WANT_PROGRAMS
lv2_get_program(const uint32_t index)802 const LV2_Program_Descriptor* lv2_get_program(const uint32_t index)
803 {
804 if (index >= fPlugin.getProgramCount())
805 return nullptr;
806
807 static LV2_Program_Descriptor desc;
808
809 desc.bank = index / 128;
810 desc.program = index % 128;
811 desc.name = fPlugin.getProgramName(index);
812
813 return &desc;
814 }
815
lv2_select_program(const uint32_t bank,const uint32_t program)816 void lv2_select_program(const uint32_t bank, const uint32_t program)
817 {
818 const uint32_t realProgram(bank * 128 + program);
819
820 if (realProgram >= fPlugin.getProgramCount())
821 return;
822
823 fPlugin.loadProgram(realProgram);
824
825 // Update control inputs
826 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
827 {
828 if (fPlugin.isParameterOutput(i))
829 continue;
830
831 fLastControlValues[i] = fPlugin.getParameterValue(i);
832
833 setPortControlValue(i, fLastControlValues[i]);
834 }
835
836 # if DISTRHO_PLUGIN_WANT_FULL_STATE
837 // Update state
838 for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
839 {
840 const String& key = cit->first;
841 fStateMap[key] = fPlugin.getState(key);
842 }
843 # endif
844 }
845 #endif
846
847 // -------------------------------------------------------------------
848
849 #if DISTRHO_PLUGIN_WANT_STATE
lv2_save(const LV2_State_Store_Function store,const LV2_State_Handle handle)850 LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle)
851 {
852 # if DISTRHO_PLUGIN_WANT_FULL_STATE
853 // Update current state
854 for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
855 {
856 const String& key = cit->first;
857 fStateMap[key] = fPlugin.getState(key);
858 }
859 # endif
860
861 String dpf_lv2_key;
862 LV2_URID urid;
863
864 for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
865 {
866 const String& curKey(fPlugin.getStateKey(i));
867
868 for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
869 {
870 const String& key(cit->first);
871
872 if (curKey != key)
873 continue;
874
875 const String& value(cit->second);
876
877 # if DISTRHO_PLUGIN_WANT_STATEFILES
878 if (fPlugin.isStateFile(i))
879 {
880 dpf_lv2_key = DISTRHO_PLUGIN_URI "#";
881 urid = fURIDs.atomPath;
882 }
883 else
884 # endif
885 {
886 dpf_lv2_key = DISTRHO_PLUGIN_LV2_STATE_PREFIX;
887 urid = fURIDs.atomString;
888 }
889
890 dpf_lv2_key += key;
891
892 // some hosts need +1 for the null terminator, even though the type is string
893 store(handle,
894 fUridMap->map(fUridMap->handle, dpf_lv2_key.buffer()),
895 value.buffer(),
896 value.length()+1,
897 urid,
898 LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE);
899 }
900 }
901
902 return LV2_STATE_SUCCESS;
903 }
904
lv2_restore(const LV2_State_Retrieve_Function retrieve,const LV2_State_Handle handle)905 LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve, const LV2_State_Handle handle)
906 {
907 size_t size;
908 uint32_t type, flags;
909
910 String dpf_lv2_key;
911 LV2_URID urid;
912
913 for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
914 {
915 const String& key(fPlugin.getStateKey(i));
916
917 # if DISTRHO_PLUGIN_WANT_STATEFILES
918 if (fPlugin.isStateFile(i))
919 {
920 dpf_lv2_key = DISTRHO_PLUGIN_URI "#";
921 urid = fURIDs.atomPath;
922 }
923 else
924 # endif
925 {
926 dpf_lv2_key = DISTRHO_PLUGIN_LV2_STATE_PREFIX;
927 urid = fURIDs.atomString;
928 }
929
930 dpf_lv2_key += key;
931
932 size = 0;
933 type = 0;
934 flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE;
935 const void* data = retrieve(handle,
936 fUridMap->map(fUridMap->handle, dpf_lv2_key.buffer()),
937 &size, &type, &flags);
938
939 if (data == nullptr || size == 0)
940 continue;
941
942 DISTRHO_SAFE_ASSERT_CONTINUE(type == urid);
943
944 const char* const value = (const char*)data;
945 const std::size_t length = std::strlen(value);
946 DISTRHO_SAFE_ASSERT_CONTINUE(length == size || length+1 == size);
947
948 setState(key, value);
949
950 #if DISTRHO_LV2_USE_EVENTS_OUT
951 // signal msg needed for UI
952 fNeededUiSends[i] = true;
953 #endif
954 }
955
956 return LV2_STATE_SUCCESS;
957 }
958
959 // -------------------------------------------------------------------
960
lv2_work(const void * const data)961 LV2_Worker_Status lv2_work(const void* const data)
962 {
963 const LV2_Atom* const eventBody = (const LV2_Atom*)data;
964
965 if (eventBody->type == fURIDs.dpfKeyValue)
966 {
967 const char* const key = (const char*)(eventBody + 1);
968 const char* const value = key + (std::strlen(key) + 1U);
969
970 setState(key, value);
971 return LV2_WORKER_SUCCESS;
972 }
973
974 # if DISTRHO_PLUGIN_WANT_STATEFILES
975 if (eventBody->type == fURIDs.atomObject)
976 {
977 const LV2_Atom_Object* const object = (const LV2_Atom_Object*)eventBody;
978
979 const LV2_Atom* property = nullptr;
980 const LV2_Atom* value = nullptr;
981 lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr);
982 DISTRHO_SAFE_ASSERT_RETURN(property != nullptr, LV2_WORKER_ERR_UNKNOWN);
983 DISTRHO_SAFE_ASSERT_RETURN(property->type == fURIDs.atomURID, LV2_WORKER_ERR_UNKNOWN);
984 DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, LV2_WORKER_ERR_UNKNOWN);
985 DISTRHO_SAFE_ASSERT_RETURN(value->type == fURIDs.atomPath, LV2_WORKER_ERR_UNKNOWN);
986
987 const LV2_URID urid = ((const LV2_Atom_URID*)property)->body;
988 const char* const filename = (const char*)(value + 1);
989
990 String key;
991
992 try {
993 key = fUridStateFileMap[urid];
994 } DISTRHO_SAFE_EXCEPTION_RETURN("lv2_work fUridStateFileMap[urid]", LV2_WORKER_ERR_UNKNOWN);
995
996 setState(key, filename);
997
998 for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
999 {
1000 if (fPlugin.getStateKey(i) == key)
1001 {
1002 fNeededUiSends[i] = true;
1003 break;
1004 }
1005 }
1006
1007 return LV2_WORKER_SUCCESS;
1008 }
1009 # endif
1010
1011 return LV2_WORKER_ERR_UNKNOWN;
1012 }
1013
lv2_work_response(uint32_t,const void *)1014 LV2_Worker_Status lv2_work_response(uint32_t, const void*)
1015 {
1016 return LV2_WORKER_SUCCESS;
1017 }
1018 #endif
1019
1020 // -------------------------------------------------------------------
1021
1022 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
lv2_get_instance_pointer()1023 void* lv2_get_instance_pointer()
1024 {
1025 return fPlugin.getInstancePointer();
1026 }
1027 #endif
1028
1029 // -------------------------------------------------------------------
1030
1031 private:
1032 PluginExporter fPlugin;
1033 const bool fUsingNominal; // if false use maxBlockLength
1034
1035 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
1036 uint32_t fRunCount;
1037 #endif
1038
1039 // LV2 ports
1040 #if DISTRHO_PLUGIN_NUM_INPUTS > 0
1041 const float* fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS];
1042 #else
1043 const float** fPortAudioIns;
1044 #endif
1045 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
1046 float* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS];
1047 #else
1048 float** fPortAudioOuts;
1049 #endif
1050 float** fPortControls;
1051 #if DISTRHO_LV2_USE_EVENTS_IN
1052 LV2_Atom_Sequence* fPortEventsIn;
1053 #endif
1054 #if DISTRHO_PLUGIN_WANT_LATENCY
1055 float* fPortLatency;
1056 #endif
1057
1058 // Temporary data
1059 float* fLastControlValues;
1060 double fSampleRate;
1061 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
1062 MidiEvent fMidiEvents[kMaxMidiEvents];
1063 #endif
1064 #if DISTRHO_PLUGIN_WANT_TIMEPOS
1065 TimePosition fTimePosition;
1066
1067 struct Lv2PositionData {
1068 int64_t bar;
1069 float barBeat;
1070 uint32_t beatUnit;
1071 float beatsPerBar;
1072 float beatsPerMinute;
1073 int64_t frame;
1074 double speed;
1075 double ticksPerBeat;
1076
Lv2PositionDataPluginLv2::Lv2PositionData1077 Lv2PositionData()
1078 : bar(-1),
1079 barBeat(-1.0f),
1080 beatUnit(0),
1081 beatsPerBar(0.0f),
1082 beatsPerMinute(0.0f),
1083 frame(-1),
1084 speed(0.0),
1085 ticksPerBeat(-1.0) {}
1086
1087 } fLastPositionData;
1088 #endif
1089
1090 #if DISTRHO_LV2_USE_EVENTS_OUT
1091 struct Lv2EventsOutData {
1092 uint32_t capacity, offset;
1093 LV2_Atom_Sequence* port;
1094
Lv2EventsOutDataPluginLv2::Lv2EventsOutData1095 Lv2EventsOutData()
1096 : capacity(0),
1097 offset(0),
1098 port(nullptr) {}
1099
initIfNeededPluginLv2::Lv2EventsOutData1100 void initIfNeeded(const LV2_URID uridAtomSequence)
1101 {
1102 if (capacity != 0)
1103 return;
1104
1105 capacity = port->atom.size;
1106
1107 port->atom.size = sizeof(LV2_Atom_Sequence_Body);
1108 port->atom.type = uridAtomSequence;
1109 port->body.unit = 0;
1110 port->body.pad = 0;
1111 }
1112
growByPluginLv2::Lv2EventsOutData1113 void growBy(const uint32_t size)
1114 {
1115 offset += size;
1116 port->atom.size += size;
1117 }
1118
endRunPluginLv2::Lv2EventsOutData1119 void endRun()
1120 {
1121 capacity = 0;
1122 offset = 0;
1123 }
1124
1125 } fEventsOutData;
1126 #endif
1127
1128 // LV2 URIDs
1129 struct URIDs {
1130 const LV2_URID_Map* _uridMap;
1131 LV2_URID atomBlank;
1132 LV2_URID atomObject;
1133 LV2_URID atomDouble;
1134 LV2_URID atomFloat;
1135 LV2_URID atomInt;
1136 LV2_URID atomLong;
1137 LV2_URID atomPath;
1138 LV2_URID atomSequence;
1139 LV2_URID atomString;
1140 LV2_URID atomURID;
1141 LV2_URID dpfKeyValue;
1142 LV2_URID midiEvent;
1143 LV2_URID patchProperty;
1144 LV2_URID patchValue;
1145 LV2_URID timePosition;
1146 LV2_URID timeBar;
1147 LV2_URID timeBarBeat;
1148 LV2_URID timeBeatUnit;
1149 LV2_URID timeBeatsPerBar;
1150 LV2_URID timeBeatsPerMinute;
1151 LV2_URID timeTicksPerBeat;
1152 LV2_URID timeFrame;
1153 LV2_URID timeSpeed;
1154
URIDsPluginLv2::URIDs1155 URIDs(const LV2_URID_Map* const uridMap)
1156 : _uridMap(uridMap),
1157 atomBlank(map(LV2_ATOM__Blank)),
1158 atomObject(map(LV2_ATOM__Object)),
1159 atomDouble(map(LV2_ATOM__Double)),
1160 atomFloat(map(LV2_ATOM__Float)),
1161 atomInt(map(LV2_ATOM__Int)),
1162 atomLong(map(LV2_ATOM__Long)),
1163 atomPath(map(LV2_ATOM__Path)),
1164 atomSequence(map(LV2_ATOM__Sequence)),
1165 atomString(map(LV2_ATOM__String)),
1166 atomURID(map(LV2_ATOM__URID)),
1167 dpfKeyValue(map(DISTRHO_PLUGIN_LV2_STATE_PREFIX "KeyValueState")),
1168 midiEvent(map(LV2_MIDI__MidiEvent)),
1169 patchProperty(map(LV2_PATCH__property)),
1170 patchValue(map(LV2_PATCH__value)),
1171 timePosition(map(LV2_TIME__Position)),
1172 timeBar(map(LV2_TIME__bar)),
1173 timeBarBeat(map(LV2_TIME__barBeat)),
1174 timeBeatUnit(map(LV2_TIME__beatUnit)),
1175 timeBeatsPerBar(map(LV2_TIME__beatsPerBar)),
1176 timeBeatsPerMinute(map(LV2_TIME__beatsPerMinute)),
1177 timeTicksPerBeat(map(LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat)),
1178 timeFrame(map(LV2_TIME__frame)),
1179 timeSpeed(map(LV2_TIME__speed)) {}
1180
mapPluginLv2::URIDs1181 inline LV2_URID map(const char* const uri) const
1182 {
1183 return _uridMap->map(_uridMap->handle, uri);
1184 }
1185 } fURIDs;
1186
1187 // LV2 features
1188 #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
1189 const LV2_ControlInputPort_Change_Request* const fCtrlInPortChangeReq;
1190 #endif
1191 const LV2_URID_Map* const fUridMap;
1192 const LV2_Worker_Schedule* const fWorker;
1193
1194 #if DISTRHO_PLUGIN_WANT_STATE
1195 StringToStringMap fStateMap;
1196 bool* fNeededUiSends;
1197
setState(const char * const key,const char * const newValue)1198 void setState(const char* const key, const char* const newValue)
1199 {
1200 fPlugin.setState(key, newValue);
1201
1202 // check if we want to save this key
1203 if (! fPlugin.wantStateKey(key))
1204 return;
1205
1206 // check if key already exists
1207 for (StringToStringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it)
1208 {
1209 const String& dkey(it->first);
1210
1211 if (dkey == key)
1212 {
1213 it->second = newValue;
1214 return;
1215 }
1216 }
1217
1218 d_stderr("Failed to find plugin state with key \"%s\"", key);
1219 }
1220
1221 # if DISTRHO_PLUGIN_WANT_STATEFILES
1222 UridToStringMap fUridStateFileMap;
1223 # endif
1224 #endif
1225
updateParameterOutputsAndTriggers()1226 void updateParameterOutputsAndTriggers()
1227 {
1228 float curValue;
1229
1230 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
1231 {
1232 if (fPlugin.isParameterOutput(i))
1233 {
1234 curValue = fLastControlValues[i] = fPlugin.getParameterValue(i);
1235
1236 setPortControlValue(i, curValue);
1237 }
1238 else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger)
1239 {
1240 // NOTE: host is responsible for auto-updating control port buffers
1241 }
1242 }
1243
1244 #if DISTRHO_PLUGIN_WANT_LATENCY
1245 if (fPortLatency != nullptr)
1246 *fPortLatency = fPlugin.getLatency();
1247 #endif
1248 }
1249
1250 #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
requestParameterValueChange(const uint32_t index,const float value)1251 bool requestParameterValueChange(const uint32_t index, const float value)
1252 {
1253 if (fCtrlInPortChangeReq == nullptr)
1254 return false;
1255 return fCtrlInPortChangeReq->request_change(fCtrlInPortChangeReq->handle, index, value);
1256 }
1257
requestParameterValueChangeCallback(void * const ptr,const uint32_t index,const float value)1258 static bool requestParameterValueChangeCallback(void* const ptr, const uint32_t index, const float value)
1259 {
1260 return (((PluginLv2*)ptr)->requestParameterValueChange(index, value) == 0);
1261 }
1262 #endif
1263
1264 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
writeMidi(const MidiEvent & midiEvent)1265 bool writeMidi(const MidiEvent& midiEvent)
1266 {
1267 DISTRHO_SAFE_ASSERT_RETURN(fEventsOutData.port != nullptr, false);
1268
1269 fEventsOutData.initIfNeeded(fURIDs.atomSequence);
1270
1271 const uint32_t capacity = fEventsOutData.capacity;
1272 const uint32_t offset = fEventsOutData.offset;
1273
1274 if (sizeof(LV2_Atom_Event) + midiEvent.size > capacity - offset)
1275 return false;
1276
1277 LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + offset);
1278 aev->time.frames = midiEvent.frame;
1279 aev->body.type = fURIDs.midiEvent;
1280 aev->body.size = midiEvent.size;
1281 std::memcpy(LV2_ATOM_BODY(&aev->body),
1282 midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data,
1283 midiEvent.size);
1284
1285 fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + midiEvent.size));
1286
1287 return true;
1288 }
1289
writeMidiCallback(void * ptr,const MidiEvent & midiEvent)1290 static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent)
1291 {
1292 return ((PluginLv2*)ptr)->writeMidi(midiEvent);
1293 }
1294 #endif
1295 };
1296
1297 // -----------------------------------------------------------------------
1298
lv2_instantiate(const LV2_Descriptor *,double sampleRate,const char *,const LV2_Feature * const * features)1299 static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char*, const LV2_Feature* const* features)
1300 {
1301 const LV2_Options_Option* options = nullptr;
1302 const LV2_URID_Map* uridMap = nullptr;
1303 const LV2_Worker_Schedule* worker = nullptr;
1304 const LV2_ControlInputPort_Change_Request* ctrlInPortChangeReq = nullptr;
1305
1306 for (int i=0; features[i] != nullptr; ++i)
1307 {
1308 if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
1309 options = (const LV2_Options_Option*)features[i]->data;
1310 else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
1311 uridMap = (const LV2_URID_Map*)features[i]->data;
1312 else if (std::strcmp(features[i]->URI, LV2_WORKER__schedule) == 0)
1313 worker = (const LV2_Worker_Schedule*)features[i]->data;
1314 else if (std::strcmp(features[i]->URI, LV2_CONTROL_INPUT_PORT_CHANGE_REQUEST_URI) == 0)
1315 ctrlInPortChangeReq = (const LV2_ControlInputPort_Change_Request*)features[i]->data;
1316 }
1317
1318 if (options == nullptr)
1319 {
1320 d_stderr("Options feature missing, cannot continue!");
1321 return nullptr;
1322 }
1323
1324 if (uridMap == nullptr)
1325 {
1326 d_stderr("URID Map feature missing, cannot continue!");
1327 return nullptr;
1328 }
1329
1330 #if DISTRHO_PLUGIN_WANT_STATE
1331 if (worker == nullptr)
1332 {
1333 d_stderr("Worker feature missing, cannot continue!");
1334 return nullptr;
1335 }
1336 #endif
1337
1338 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
1339 mod_license_check(features, DISTRHO_PLUGIN_URI);
1340 #endif
1341
1342 d_lastBufferSize = 0;
1343 bool usingNominal = false;
1344
1345 for (int i=0; options[i].key != 0; ++i)
1346 {
1347 if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__nominalBlockLength))
1348 {
1349 if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
1350 {
1351 d_lastBufferSize = *(const int*)options[i].value;
1352 usingNominal = true;
1353 }
1354 else
1355 {
1356 d_stderr("Host provides nominalBlockLength but has wrong value type");
1357 }
1358 break;
1359 }
1360
1361 if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength))
1362 {
1363 if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
1364 d_lastBufferSize = *(const int*)options[i].value;
1365 else
1366 d_stderr("Host provides maxBlockLength but has wrong value type");
1367
1368 // no break, continue in case host supports nominalBlockLength
1369 }
1370 }
1371
1372 if (d_lastBufferSize == 0)
1373 {
1374 d_stderr("Host does not provide nominalBlockLength or maxBlockLength options");
1375 d_lastBufferSize = 2048;
1376 }
1377
1378 d_lastSampleRate = sampleRate;
1379 d_lastCanRequestParameterValueChanges = ctrlInPortChangeReq != nullptr;
1380
1381 return new PluginLv2(sampleRate, uridMap, worker, ctrlInPortChangeReq, usingNominal);
1382 }
1383
1384 #define instancePtr ((PluginLv2*)instance)
1385
lv2_connect_port(LV2_Handle instance,uint32_t port,void * dataLocation)1386 static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
1387 {
1388 instancePtr->lv2_connect_port(port, dataLocation);
1389 }
1390
lv2_activate(LV2_Handle instance)1391 static void lv2_activate(LV2_Handle instance)
1392 {
1393 instancePtr->lv2_activate();
1394 }
1395
lv2_run(LV2_Handle instance,uint32_t sampleCount)1396 static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
1397 {
1398 instancePtr->lv2_run(sampleCount);
1399 }
1400
lv2_deactivate(LV2_Handle instance)1401 static void lv2_deactivate(LV2_Handle instance)
1402 {
1403 instancePtr->lv2_deactivate();
1404 }
1405
lv2_cleanup(LV2_Handle instance)1406 static void lv2_cleanup(LV2_Handle instance)
1407 {
1408 delete instancePtr;
1409 }
1410
1411 // -----------------------------------------------------------------------
1412
lv2_get_options(LV2_Handle instance,LV2_Options_Option * options)1413 static uint32_t lv2_get_options(LV2_Handle instance, LV2_Options_Option* options)
1414 {
1415 return instancePtr->lv2_get_options(options);
1416 }
1417
lv2_set_options(LV2_Handle instance,const LV2_Options_Option * options)1418 static uint32_t lv2_set_options(LV2_Handle instance, const LV2_Options_Option* options)
1419 {
1420 return instancePtr->lv2_set_options(options);
1421 }
1422
1423 // -----------------------------------------------------------------------
1424
1425 #if DISTRHO_PLUGIN_WANT_PROGRAMS
lv2_get_program(LV2_Handle instance,uint32_t index)1426 static const LV2_Program_Descriptor* lv2_get_program(LV2_Handle instance, uint32_t index)
1427 {
1428 return instancePtr->lv2_get_program(index);
1429 }
1430
lv2_select_program(LV2_Handle instance,uint32_t bank,uint32_t program)1431 static void lv2_select_program(LV2_Handle instance, uint32_t bank, uint32_t program)
1432 {
1433 instancePtr->lv2_select_program(bank, program);
1434 }
1435 #endif
1436
1437 // -----------------------------------------------------------------------
1438
1439 #if DISTRHO_PLUGIN_WANT_STATE
lv2_save(LV2_Handle instance,LV2_State_Store_Function store,LV2_State_Handle handle,uint32_t,const LV2_Feature * const *)1440 static LV2_State_Status lv2_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t, const LV2_Feature* const*)
1441 {
1442 return instancePtr->lv2_save(store, handle);
1443 }
1444
lv2_restore(LV2_Handle instance,LV2_State_Retrieve_Function retrieve,LV2_State_Handle handle,uint32_t,const LV2_Feature * const *)1445 static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t, const LV2_Feature* const*)
1446 {
1447 return instancePtr->lv2_restore(retrieve, handle);
1448 }
1449
lv2_work(LV2_Handle instance,LV2_Worker_Respond_Function,LV2_Worker_Respond_Handle,uint32_t,const void * data)1450 LV2_Worker_Status lv2_work(LV2_Handle instance, LV2_Worker_Respond_Function, LV2_Worker_Respond_Handle, uint32_t, const void* data)
1451 {
1452 return instancePtr->lv2_work(data);
1453 }
1454
lv2_work_response(LV2_Handle instance,uint32_t size,const void * body)1455 LV2_Worker_Status lv2_work_response(LV2_Handle instance, uint32_t size, const void* body)
1456 {
1457 return instancePtr->lv2_work_response(size, body);
1458 }
1459 #endif
1460
1461 // -----------------------------------------------------------------------
1462
1463 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
lv2_get_instance_pointer(LV2_Handle instance)1464 static void* lv2_get_instance_pointer(LV2_Handle instance)
1465 {
1466 return instancePtr->lv2_get_instance_pointer();
1467 }
1468 #endif
1469
1470 // -----------------------------------------------------------------------
1471
lv2_extension_data(const char * uri)1472 static const void* lv2_extension_data(const char* uri)
1473 {
1474 static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options };
1475
1476 if (std::strcmp(uri, LV2_OPTIONS__interface) == 0)
1477 return &options;
1478
1479 #if DISTRHO_PLUGIN_WANT_PROGRAMS
1480 static const LV2_Programs_Interface programs = { lv2_get_program, lv2_select_program };
1481
1482 if (std::strcmp(uri, LV2_PROGRAMS__Interface) == 0)
1483 return &programs;
1484 #endif
1485
1486 #if DISTRHO_PLUGIN_WANT_STATE
1487 static const LV2_State_Interface state = { lv2_save, lv2_restore };
1488 static const LV2_Worker_Interface worker = { lv2_work, lv2_work_response, nullptr };
1489
1490 if (std::strcmp(uri, LV2_STATE__interface) == 0)
1491 return &state;
1492 if (std::strcmp(uri, LV2_WORKER__interface) == 0)
1493 return &worker;
1494 #endif
1495
1496 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
1497 struct LV2_DirectAccess_Interface {
1498 void* (*get_instance_pointer)(LV2_Handle handle);
1499 };
1500
1501 static const LV2_DirectAccess_Interface directaccess = { lv2_get_instance_pointer };
1502
1503 if (std::strcmp(uri, DISTRHO_PLUGIN_LV2_STATE_PREFIX "direct-access") == 0)
1504 return &directaccess;
1505 #endif
1506
1507 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
1508 return mod_license_interface(uri);
1509 #else
1510 return nullptr;
1511 #endif
1512 }
1513
1514 #undef instancePtr
1515
1516 // -----------------------------------------------------------------------
1517
1518 static const LV2_Descriptor sLv2Descriptor = {
1519 DISTRHO_PLUGIN_URI,
1520 lv2_instantiate,
1521 lv2_connect_port,
1522 lv2_activate,
1523 lv2_run,
1524 lv2_deactivate,
1525 lv2_cleanup,
1526 lv2_extension_data
1527 };
1528
1529 // -----------------------------------------------------------------------
1530
1531 END_NAMESPACE_DISTRHO
1532
1533 DISTRHO_PLUGIN_EXPORT
lv2_descriptor(uint32_t index)1534 const LV2_Descriptor* lv2_descriptor(uint32_t index)
1535 {
1536 USE_NAMESPACE_DISTRHO
1537 return (index == 0) ? &sLv2Descriptor : nullptr;
1538 }
1539
1540 // -----------------------------------------------------------------------
1541