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