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