DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

DistrhoPluginLV2.cpp (59583B)


      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.0);
    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,
    913                               const LV2_State_Handle handle,
    914                               const LV2_Feature* const* const features)
    915     {
    916        #if DISTRHO_PLUGIN_WANT_FULL_STATE
    917         // Update current state
    918         for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
    919         {
    920             const String& key = cit->first;
    921             fStateMap[key] = fPlugin.getStateValue(key);
    922         }
    923        #endif
    924 
    925         String lv2key;
    926         LV2_URID urid;
    927 
    928         for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
    929         {
    930             const String& curKey(fPlugin.getStateKey(i));
    931 
    932             for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
    933             {
    934                 const String& key(cit->first);
    935 
    936                 if (curKey != key)
    937                     continue;
    938 
    939                 const uint32_t hints = fPlugin.getStateHints(i);
    940 
    941                #if ! DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
    942                 // do not save UI-only messages if there is no UI available
    943                 if (hints & kStateIsOnlyForUI)
    944                     break;
    945                #endif
    946 
    947                 if (hints & kStateIsHostReadable)
    948                 {
    949                     lv2key = DISTRHO_PLUGIN_URI "#";
    950                     urid = (hints & kStateIsFilenamePath) == kStateIsFilenamePath
    951                          ? fURIDs.atomPath
    952                          : fURIDs.atomString;
    953                 }
    954                 else
    955                 {
    956                     lv2key = DISTRHO_PLUGIN_LV2_STATE_PREFIX;
    957                     urid = fURIDs.atomString;
    958                 }
    959 
    960                 lv2key += key;
    961 
    962                 const String& value(cit->second);
    963 
    964                 if (urid == fURIDs.atomPath)
    965                 {
    966                     const LV2_State_Map_Path* mapPath = nullptr;
    967                     const LV2_State_Free_Path* freePath = nullptr;
    968                     for (int i=0; features[i] != nullptr; ++i)
    969                     {
    970                         if (std::strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
    971                             mapPath = (const LV2_State_Map_Path*)features[i]->data;
    972                         else if (std::strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
    973                             freePath = (const LV2_State_Free_Path*)features[i]->data;
    974                     }
    975 
    976                     if (char* const abstractPath = mapPath != nullptr
    977                                                  ? mapPath->abstract_path(mapPath->handle, value.buffer())
    978                                                  : nullptr)
    979                     {
    980                         // some hosts need +1 for the null terminator, even though the type is string/path
    981                         store(handle,
    982                               fUridMap->map(fUridMap->handle, lv2key.buffer()),
    983                               abstractPath,
    984                               std::strlen(abstractPath)+1,
    985                               urid,
    986                               LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE);
    987 
    988                         if (freePath != nullptr)
    989                             freePath->free_path(freePath->handle, abstractPath);
    990                        #ifndef DISTRHO_OS_WINDOWS
    991                         else
    992                             std::free(abstractPath);
    993                        #endif
    994 
    995                         break;
    996                     }
    997                 }
    998 
    999                 // some hosts need +1 for the null terminator, even though the type is string
   1000                 store(handle,
   1001                       fUridMap->map(fUridMap->handle, lv2key.buffer()),
   1002                       value.buffer(),
   1003                       value.length()+1,
   1004                       urid,
   1005                       LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE);
   1006 
   1007                 break;
   1008             }
   1009         }
   1010 
   1011         return LV2_STATE_SUCCESS;
   1012     }
   1013 
   1014     LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve,
   1015                                  const LV2_State_Handle handle,
   1016                                  const LV2_Feature* const* const features)
   1017     {
   1018         size_t size;
   1019         uint32_t type, flags;
   1020 
   1021         String lv2key;
   1022         LV2_URID urid;
   1023 
   1024         for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
   1025         {
   1026             const String& key(fPlugin.getStateKey(i));
   1027 
   1028             const uint32_t hints = fPlugin.getStateHints(i);
   1029 
   1030             if (hints & kStateIsHostReadable)
   1031             {
   1032                 lv2key = DISTRHO_PLUGIN_URI "#";
   1033                 urid = (hints & kStateIsFilenamePath) == kStateIsFilenamePath
   1034                      ? fURIDs.atomPath
   1035                      : fURIDs.atomString;
   1036             }
   1037             else
   1038             {
   1039                 lv2key = DISTRHO_PLUGIN_LV2_STATE_PREFIX;
   1040                 urid = fURIDs.atomString;
   1041             }
   1042 
   1043             lv2key += key;
   1044 
   1045             size  = 0;
   1046             type  = 0;
   1047             flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE;
   1048             const void* data = retrieve(handle,
   1049                                         fUridMap->map(fUridMap->handle, lv2key.buffer()),
   1050                                         &size, &type, &flags);
   1051 
   1052             if (data == nullptr || size == 0)
   1053                 continue;
   1054 
   1055             DISTRHO_SAFE_ASSERT_CONTINUE(type == urid);
   1056 
   1057             const char* const value  = (const char*)data;
   1058             const std::size_t length = std::strlen(value);
   1059             DISTRHO_SAFE_ASSERT_CONTINUE(length == size || length+1 == size);
   1060 
   1061             if (urid == fURIDs.atomPath)
   1062             {
   1063                 const LV2_State_Map_Path* mapPath = nullptr;
   1064                 const LV2_State_Free_Path* freePath = nullptr;
   1065                 for (int i=0; features[i] != nullptr; ++i)
   1066                 {
   1067                     if (std::strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
   1068                         mapPath = (const LV2_State_Map_Path*)features[i]->data;
   1069                     else if (std::strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
   1070                         freePath = (const LV2_State_Free_Path*)features[i]->data;
   1071                 }
   1072 
   1073                 if (char* const absolutePath = mapPath != nullptr
   1074                                              ? mapPath->absolute_path(mapPath->handle, value)
   1075                                              : nullptr)
   1076                 {
   1077                     setState(key, absolutePath);
   1078 
   1079                     if (freePath != nullptr)
   1080                         freePath->free_path(freePath->handle, absolutePath);
   1081                    #ifndef DISTRHO_OS_WINDOWS
   1082                     else
   1083                         std::free(absolutePath);
   1084                    #endif
   1085 
   1086                     // signal msg needed for UI
   1087                     fNeededUiSends[i] = true;
   1088                     continue;
   1089                 }
   1090             }
   1091 
   1092             setState(key, value);
   1093 
   1094            #if DISTRHO_PLUGIN_WANT_STATE
   1095             // signal msg needed for UI
   1096             if ((hints & kStateIsOnlyForDSP) == 0x0)
   1097                 fNeededUiSends[i] = true;
   1098            #endif
   1099         }
   1100 
   1101         return LV2_STATE_SUCCESS;
   1102     }
   1103 
   1104     // -------------------------------------------------------------------
   1105 
   1106     LV2_Worker_Status lv2_work(const void* const data)
   1107     {
   1108         const LV2_Atom* const eventBody = (const LV2_Atom*)data;
   1109 
   1110         if (eventBody->type == fURIDs.dpfKeyValue)
   1111         {
   1112             const char* const key   = (const char*)(eventBody + 1);
   1113             const char* const value = key + (std::strlen(key) + 1U);
   1114 
   1115             setState(key, value);
   1116             return LV2_WORKER_SUCCESS;
   1117         }
   1118 
   1119         if (eventBody->type == fURIDs.atomObject)
   1120         {
   1121             const LV2_Atom_Object* const object = (const LV2_Atom_Object*)eventBody;
   1122 
   1123             const LV2_Atom* property = nullptr;
   1124             const LV2_Atom* value    = nullptr;
   1125             lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr);
   1126             DISTRHO_SAFE_ASSERT_RETURN(property != nullptr, LV2_WORKER_ERR_UNKNOWN);
   1127             DISTRHO_SAFE_ASSERT_RETURN(property->type == fURIDs.atomURID, LV2_WORKER_ERR_UNKNOWN);
   1128             DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, LV2_WORKER_ERR_UNKNOWN);
   1129             DISTRHO_SAFE_ASSERT_RETURN(value->type == fURIDs.atomPath ||
   1130                                        value->type == fURIDs.atomString, LV2_WORKER_ERR_UNKNOWN);
   1131 
   1132             const LV2_URID urid        = ((const LV2_Atom_URID*)property)->body;
   1133             const char* const filename = (const char*)(value + 1);
   1134 
   1135             String key;
   1136 
   1137             try {
   1138                 key = fUridStateMap[urid];
   1139             } DISTRHO_SAFE_EXCEPTION_RETURN("lv2_work fUridStateMap[urid]", LV2_WORKER_ERR_UNKNOWN);
   1140 
   1141             setState(key, filename);
   1142 
   1143             /* FIXME host should be responsible for updating UI side, not us
   1144             for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
   1145             {
   1146                 if (fPlugin.getStateKey(i) == key)
   1147                 {
   1148                     if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0)
   1149                         fNeededUiSends[i] = true;
   1150                     break;
   1151                 }
   1152             }
   1153             */
   1154 
   1155             return LV2_WORKER_SUCCESS;
   1156         }
   1157 
   1158         return LV2_WORKER_ERR_UNKNOWN;
   1159     }
   1160 
   1161     LV2_Worker_Status lv2_work_response(uint32_t, const void*)
   1162     {
   1163         return LV2_WORKER_SUCCESS;
   1164     }
   1165    #endif
   1166 
   1167     // -------------------------------------------------------------------
   1168 
   1169    #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
   1170     void* lv2_get_instance_pointer()
   1171     {
   1172         return fPlugin.getInstancePointer();
   1173     }
   1174    #endif
   1175 
   1176     // -------------------------------------------------------------------
   1177 
   1178 private:
   1179     PluginExporter fPlugin;
   1180     const bool fUsingNominal; // if false use maxBlockLength
   1181 
   1182    #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
   1183     uint32_t fRunCount;
   1184    #endif
   1185 
   1186     // LV2 ports
   1187    #if DISTRHO_PLUGIN_NUM_INPUTS > 0
   1188     const float*  fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS];
   1189    #else
   1190     const float** fPortAudioIns;
   1191    #endif
   1192    #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
   1193     float*  fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS];
   1194    #else
   1195     float** fPortAudioOuts;
   1196    #endif
   1197     float** fPortControls;
   1198    #if DISTRHO_LV2_USE_EVENTS_IN
   1199     LV2_Atom_Sequence* fPortEventsIn;
   1200    #endif
   1201    #if DISTRHO_PLUGIN_WANT_LATENCY
   1202     float* fPortLatency;
   1203    #endif
   1204 
   1205     // Temporary data
   1206     float* fLastControlValues;
   1207     double fSampleRate;
   1208    #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
   1209     MidiEvent fMidiEvents[kMaxMidiEvents];
   1210    #endif
   1211    #if DISTRHO_PLUGIN_WANT_TIMEPOS
   1212     TimePosition fTimePosition;
   1213 
   1214     struct Lv2PositionData {
   1215         int64_t  bar;
   1216         float    barBeat;
   1217         uint32_t beatUnit;
   1218         float    beatsPerBar;
   1219         float    beatsPerMinute;
   1220         int64_t  frame;
   1221         double   speed;
   1222         double   ticksPerBeat;
   1223 
   1224         Lv2PositionData()
   1225             : bar(-1),
   1226               barBeat(-1.0f),
   1227               beatUnit(0),
   1228               beatsPerBar(0.0f),
   1229               beatsPerMinute(0.0f),
   1230               frame(-1),
   1231               speed(0.0),
   1232               ticksPerBeat(-1.0) {}
   1233 
   1234     } fLastPositionData;
   1235    #endif
   1236 
   1237    #if DISTRHO_LV2_USE_EVENTS_OUT
   1238     struct Lv2EventsOutData {
   1239         uint32_t capacity, offset;
   1240         LV2_Atom_Sequence* port;
   1241 
   1242         Lv2EventsOutData()
   1243             : capacity(0),
   1244               offset(0),
   1245               port(nullptr) {}
   1246 
   1247         void initIfNeeded(const LV2_URID uridAtomSequence)
   1248         {
   1249             if (capacity != 0)
   1250                 return;
   1251 
   1252             capacity = port->atom.size;
   1253 
   1254             port->atom.size = sizeof(LV2_Atom_Sequence_Body);
   1255             port->atom.type = uridAtomSequence;
   1256             port->body.unit = 0;
   1257             port->body.pad  = 0;
   1258         }
   1259 
   1260         void growBy(const uint32_t size)
   1261         {
   1262             offset += size;
   1263             port->atom.size += size;
   1264         }
   1265 
   1266         void endRun()
   1267         {
   1268             capacity = 0;
   1269             offset = 0;
   1270         }
   1271 
   1272     } fEventsOutData;
   1273    #endif
   1274 
   1275     // LV2 URIDs
   1276     struct URIDs {
   1277         const LV2_URID_Map* _uridMap;
   1278         LV2_URID atomBlank;
   1279         LV2_URID atomObject;
   1280         LV2_URID atomDouble;
   1281         LV2_URID atomFloat;
   1282         LV2_URID atomInt;
   1283         LV2_URID atomLong;
   1284         LV2_URID atomPath;
   1285         LV2_URID atomSequence;
   1286         LV2_URID atomString;
   1287         LV2_URID atomURID;
   1288         LV2_URID dpfKeyValue;
   1289         LV2_URID midiEvent;
   1290         LV2_URID patchSet;
   1291         LV2_URID patchProperty;
   1292         LV2_URID patchValue;
   1293         LV2_URID timePosition;
   1294         LV2_URID timeBar;
   1295         LV2_URID timeBarBeat;
   1296         LV2_URID timeBeatUnit;
   1297         LV2_URID timeBeatsPerBar;
   1298         LV2_URID timeBeatsPerMinute;
   1299         LV2_URID timeTicksPerBeat;
   1300         LV2_URID timeFrame;
   1301         LV2_URID timeSpeed;
   1302 
   1303         URIDs(const LV2_URID_Map* const uridMap)
   1304             : _uridMap(uridMap),
   1305               atomBlank(map(LV2_ATOM__Blank)),
   1306               atomObject(map(LV2_ATOM__Object)),
   1307               atomDouble(map(LV2_ATOM__Double)),
   1308               atomFloat(map(LV2_ATOM__Float)),
   1309               atomInt(map(LV2_ATOM__Int)),
   1310               atomLong(map(LV2_ATOM__Long)),
   1311               atomPath(map(LV2_ATOM__Path)),
   1312               atomSequence(map(LV2_ATOM__Sequence)),
   1313               atomString(map(LV2_ATOM__String)),
   1314               atomURID(map(LV2_ATOM__URID)),
   1315               dpfKeyValue(map(DISTRHO_PLUGIN_LV2_STATE_PREFIX "KeyValueState")),
   1316               midiEvent(map(LV2_MIDI__MidiEvent)),
   1317               patchSet(map(LV2_PATCH__Set)),
   1318               patchProperty(map(LV2_PATCH__property)),
   1319               patchValue(map(LV2_PATCH__value)),
   1320               timePosition(map(LV2_TIME__Position)),
   1321               timeBar(map(LV2_TIME__bar)),
   1322               timeBarBeat(map(LV2_TIME__barBeat)),
   1323               timeBeatUnit(map(LV2_TIME__beatUnit)),
   1324               timeBeatsPerBar(map(LV2_TIME__beatsPerBar)),
   1325               timeBeatsPerMinute(map(LV2_TIME__beatsPerMinute)),
   1326               timeTicksPerBeat(map(LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat)),
   1327               timeFrame(map(LV2_TIME__frame)),
   1328               timeSpeed(map(LV2_TIME__speed)) {}
   1329 
   1330         inline LV2_URID map(const char* const uri) const
   1331         {
   1332             return _uridMap->map(_uridMap->handle, uri);
   1333         }
   1334     } fURIDs;
   1335 
   1336     // LV2 features
   1337    #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
   1338     const LV2_ControlInputPort_Change_Request* const fCtrlInPortChangeReq;
   1339    #endif
   1340     const LV2_URID_Map* const fUridMap;
   1341     const LV2_Worker_Schedule* const fWorker;
   1342 
   1343    #if DISTRHO_PLUGIN_WANT_STATE
   1344     LV2_Atom_Forge fAtomForge;
   1345     StringToStringMap fStateMap;
   1346     UridToStringMap fUridStateMap;
   1347     LV2_URID* fUrids;
   1348     bool* fNeededUiSends;
   1349 
   1350     void setState(const char* const key, const char* const newValue)
   1351     {
   1352         fPlugin.setState(key, newValue);
   1353 
   1354         // save this key if necessary
   1355         if (fPlugin.wantStateKey(key))
   1356         {
   1357             const String dkey(key);
   1358             fStateMap[dkey] = newValue;
   1359         }
   1360     }
   1361 
   1362     bool updateState(const char* const key, const char* const newValue)
   1363     {
   1364         fPlugin.setState(key, newValue);
   1365 
   1366         // key must already exist
   1367         for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
   1368         {
   1369             if (fPlugin.getStateKey(i) == key)
   1370             {
   1371                 const String dkey(key);
   1372                 fStateMap[dkey] = newValue;
   1373 
   1374                 if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0)
   1375                     fNeededUiSends[i] = true;
   1376 
   1377                 return true;
   1378             }
   1379         }
   1380 
   1381         d_stderr("Failed to find plugin state with key \"%s\"", key);
   1382         return false;
   1383     }
   1384    #endif
   1385 
   1386     void updateParameterOutputsAndTriggers()
   1387     {
   1388         float curValue;
   1389 
   1390         for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
   1391         {
   1392             if (fPlugin.isParameterOutput(i))
   1393             {
   1394                 curValue = fLastControlValues[i] = fPlugin.getParameterValue(i);
   1395 
   1396                 setPortControlValue(i, curValue);
   1397             }
   1398             else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger)
   1399             {
   1400                 // NOTE: host is responsible for auto-updating control port buffers
   1401             }
   1402         }
   1403 
   1404        #if DISTRHO_PLUGIN_WANT_LATENCY
   1405         if (fPortLatency != nullptr)
   1406             *fPortLatency = fPlugin.getLatency();
   1407        #endif
   1408     }
   1409 
   1410    #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
   1411     bool requestParameterValueChange(const uint32_t index, const float value)
   1412     {
   1413         if (fCtrlInPortChangeReq == nullptr)
   1414             return false;
   1415         return fCtrlInPortChangeReq->request_change(fCtrlInPortChangeReq->handle,
   1416                                                     index + fPlugin.getParameterOffset(),
   1417                                                     value);
   1418     }
   1419 
   1420     static bool requestParameterValueChangeCallback(void* const ptr, const uint32_t index, const float value)
   1421     {
   1422         return (((PluginLv2*)ptr)->requestParameterValueChange(index, value) == 0);
   1423     }
   1424    #endif
   1425 
   1426    #if DISTRHO_PLUGIN_WANT_STATE
   1427     static bool updateStateValueCallback(void* const ptr, const char* const key, const char* const value)
   1428     {
   1429         return ((PluginLv2*)ptr)->updateState(key, value);
   1430     }
   1431    #endif
   1432 
   1433    #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
   1434     bool writeMidi(const MidiEvent& midiEvent)
   1435     {
   1436         DISTRHO_SAFE_ASSERT_RETURN(fEventsOutData.port != nullptr, false);
   1437 
   1438         fEventsOutData.initIfNeeded(fURIDs.atomSequence);
   1439 
   1440         const uint32_t capacity = fEventsOutData.capacity;
   1441         const uint32_t offset = fEventsOutData.offset;
   1442 
   1443         if (sizeof(LV2_Atom_Event) + midiEvent.size > capacity - offset)
   1444             return false;
   1445 
   1446         LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + offset);
   1447         aev->time.frames = midiEvent.frame;
   1448         aev->body.type   = fURIDs.midiEvent;
   1449         aev->body.size   = midiEvent.size;
   1450         std::memcpy(LV2_ATOM_BODY(&aev->body),
   1451                     midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data,
   1452                     midiEvent.size);
   1453 
   1454         fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + midiEvent.size));
   1455 
   1456         return true;
   1457     }
   1458 
   1459     static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent)
   1460     {
   1461         return ((PluginLv2*)ptr)->writeMidi(midiEvent);
   1462     }
   1463    #endif
   1464 };
   1465 
   1466 // -----------------------------------------------------------------------
   1467 
   1468 static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
   1469 {
   1470     const LV2_Options_Option* options = nullptr;
   1471     const LV2_URID_Map*       uridMap = nullptr;
   1472     const LV2_Worker_Schedule* worker = nullptr;
   1473     const LV2_ControlInputPort_Change_Request* ctrlInPortChangeReq = nullptr;
   1474 
   1475     for (int i=0; features[i] != nullptr; ++i)
   1476     {
   1477         if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
   1478             options = (const LV2_Options_Option*)features[i]->data;
   1479         else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
   1480             uridMap = (const LV2_URID_Map*)features[i]->data;
   1481         else if (std::strcmp(features[i]->URI, LV2_WORKER__schedule) == 0)
   1482             worker = (const LV2_Worker_Schedule*)features[i]->data;
   1483         else if (std::strcmp(features[i]->URI, LV2_CONTROL_INPUT_PORT_CHANGE_REQUEST_URI) == 0)
   1484             ctrlInPortChangeReq = (const LV2_ControlInputPort_Change_Request*)features[i]->data;
   1485     }
   1486 
   1487     if (options == nullptr)
   1488     {
   1489         d_stderr("Options feature missing, cannot continue!");
   1490         return nullptr;
   1491     }
   1492 
   1493     if (uridMap == nullptr)
   1494     {
   1495         d_stderr("URID Map feature missing, cannot continue!");
   1496         return nullptr;
   1497     }
   1498 
   1499 #if DISTRHO_PLUGIN_WANT_STATE
   1500     if (worker == nullptr)
   1501     {
   1502         d_stderr("Worker feature missing, cannot continue!");
   1503         return nullptr;
   1504     }
   1505 #endif
   1506 
   1507 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
   1508     mod_license_check(features, DISTRHO_PLUGIN_URI);
   1509 #endif
   1510 
   1511     d_nextBufferSize = 0;
   1512     bool usingNominal = false;
   1513 
   1514     for (int i=0; options[i].key != 0; ++i)
   1515     {
   1516         if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__nominalBlockLength))
   1517         {
   1518             if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
   1519             {
   1520                 d_nextBufferSize = *(const int*)options[i].value;
   1521                 usingNominal = true;
   1522             }
   1523             else
   1524             {
   1525                 d_stderr("Host provides nominalBlockLength but has wrong value type");
   1526             }
   1527             break;
   1528         }
   1529 
   1530         if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength))
   1531         {
   1532             if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
   1533                 d_nextBufferSize = *(const int*)options[i].value;
   1534             else
   1535                 d_stderr("Host provides maxBlockLength but has wrong value type");
   1536 
   1537             // no break, continue in case host supports nominalBlockLength
   1538         }
   1539     }
   1540 
   1541     if (d_nextBufferSize == 0)
   1542     {
   1543         d_stderr("Host does not provide nominalBlockLength or maxBlockLength options");
   1544         d_nextBufferSize = 2048;
   1545     }
   1546 
   1547     d_nextSampleRate = sampleRate;
   1548     d_nextBundlePath = bundlePath;
   1549     d_nextCanRequestParameterValueChanges = ctrlInPortChangeReq != nullptr;
   1550 
   1551     if (std::getenv("RUNNING_UNDER_LV2LINT") != nullptr)
   1552         d_nextPluginIsDummy = true;
   1553 
   1554     return new PluginLv2(sampleRate, uridMap, worker, ctrlInPortChangeReq, usingNominal);
   1555 }
   1556 
   1557 #define instancePtr ((PluginLv2*)instance)
   1558 
   1559 static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
   1560 {
   1561     instancePtr->lv2_connect_port(port, dataLocation);
   1562 }
   1563 
   1564 static void lv2_activate(LV2_Handle instance)
   1565 {
   1566     instancePtr->lv2_activate();
   1567 }
   1568 
   1569 static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
   1570 {
   1571     instancePtr->lv2_run(sampleCount);
   1572 }
   1573 
   1574 static void lv2_deactivate(LV2_Handle instance)
   1575 {
   1576     instancePtr->lv2_deactivate();
   1577 }
   1578 
   1579 static void lv2_cleanup(LV2_Handle instance)
   1580 {
   1581     delete instancePtr;
   1582 }
   1583 
   1584 // -----------------------------------------------------------------------
   1585 
   1586 static uint32_t lv2_get_options(LV2_Handle instance, LV2_Options_Option* options)
   1587 {
   1588     return instancePtr->lv2_get_options(options);
   1589 }
   1590 
   1591 static uint32_t lv2_set_options(LV2_Handle instance, const LV2_Options_Option* options)
   1592 {
   1593     return instancePtr->lv2_set_options(options);
   1594 }
   1595 
   1596 // -----------------------------------------------------------------------
   1597 
   1598 #if DISTRHO_PLUGIN_WANT_PROGRAMS
   1599 static const LV2_Program_Descriptor* lv2_get_program(LV2_Handle instance, uint32_t index)
   1600 {
   1601     return instancePtr->lv2_get_program(index);
   1602 }
   1603 
   1604 static void lv2_select_program(LV2_Handle instance, uint32_t bank, uint32_t program)
   1605 {
   1606     instancePtr->lv2_select_program(bank, program);
   1607 }
   1608 #endif
   1609 
   1610 // -----------------------------------------------------------------------
   1611 
   1612 #if DISTRHO_PLUGIN_WANT_STATE
   1613 static LV2_State_Status lv2_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t, const LV2_Feature* const* const features)
   1614 {
   1615     return instancePtr->lv2_save(store, handle, features);
   1616 }
   1617 
   1618 static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t, const LV2_Feature* const* const features)
   1619 {
   1620     return instancePtr->lv2_restore(retrieve, handle, features);
   1621 }
   1622 
   1623 LV2_Worker_Status lv2_work(LV2_Handle instance, LV2_Worker_Respond_Function, LV2_Worker_Respond_Handle, uint32_t, const void* data)
   1624 {
   1625     return instancePtr->lv2_work(data);
   1626 }
   1627 
   1628 LV2_Worker_Status lv2_work_response(LV2_Handle instance, uint32_t size, const void* body)
   1629 {
   1630     return instancePtr->lv2_work_response(size, body);
   1631 }
   1632 #endif
   1633 
   1634 // -----------------------------------------------------------------------
   1635 
   1636 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
   1637 static void* lv2_get_instance_pointer(LV2_Handle instance)
   1638 {
   1639     return instancePtr->lv2_get_instance_pointer();
   1640 }
   1641 #endif
   1642 
   1643 // -----------------------------------------------------------------------
   1644 
   1645 static const void* lv2_extension_data(const char* uri)
   1646 {
   1647     static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options };
   1648 
   1649     if (std::strcmp(uri, LV2_OPTIONS__interface) == 0)
   1650         return &options;
   1651 
   1652 #if DISTRHO_PLUGIN_WANT_PROGRAMS
   1653     static const LV2_Programs_Interface programs = { lv2_get_program, lv2_select_program };
   1654 
   1655     if (std::strcmp(uri, LV2_PROGRAMS__Interface) == 0)
   1656         return &programs;
   1657 #endif
   1658 
   1659 #if DISTRHO_PLUGIN_WANT_STATE
   1660     static const LV2_State_Interface state = { lv2_save, lv2_restore };
   1661     static const LV2_Worker_Interface worker = { lv2_work, lv2_work_response, nullptr };
   1662 
   1663     if (std::strcmp(uri, LV2_STATE__interface) == 0)
   1664         return &state;
   1665     if (std::strcmp(uri, LV2_WORKER__interface) == 0)
   1666         return &worker;
   1667 #endif
   1668 
   1669 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
   1670     struct LV2_DirectAccess_Interface {
   1671         void* (*get_instance_pointer)(LV2_Handle handle);
   1672     };
   1673 
   1674     static const LV2_DirectAccess_Interface directaccess = { lv2_get_instance_pointer };
   1675 
   1676     if (std::strcmp(uri, DISTRHO_PLUGIN_LV2_STATE_PREFIX "direct-access") == 0)
   1677         return &directaccess;
   1678 #endif
   1679 
   1680 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
   1681     return mod_license_interface(uri);
   1682 #else
   1683     return nullptr;
   1684 #endif
   1685 }
   1686 
   1687 #undef instancePtr
   1688 
   1689 // -----------------------------------------------------------------------
   1690 
   1691 static const LV2_Descriptor sLv2Descriptor = {
   1692     DISTRHO_PLUGIN_URI,
   1693     lv2_instantiate,
   1694     lv2_connect_port,
   1695     lv2_activate,
   1696     lv2_run,
   1697     lv2_deactivate,
   1698     lv2_cleanup,
   1699     lv2_extension_data
   1700 };
   1701 
   1702 // -----------------------------------------------------------------------
   1703 
   1704 END_NAMESPACE_DISTRHO
   1705 
   1706 DISTRHO_PLUGIN_EXPORT
   1707 const LV2_Descriptor* lv2_descriptor(uint32_t index)
   1708 {
   1709     USE_NAMESPACE_DISTRHO
   1710     return (index == 0) ? &sLv2Descriptor : nullptr;
   1711 }
   1712 
   1713 // -----------------------------------------------------------------------