comparison DPF-Prymula-audioplugins/dpf/distrho/src/DistrhoPluginLV2.cpp @ 3:84e66ea83026

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