DPF

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

DistrhoPluginInternal.hpp (32620B)


      1 /*
      2  * DISTRHO Plugin Framework (DPF)
      3  * Copyright (C) 2012-2024 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 #ifndef DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
     18 #define DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
     19 
     20 #include "../DistrhoPlugin.hpp"
     21 
     22 #ifdef DISTRHO_PLUGIN_TARGET_VST3
     23 # include "DistrhoPluginVST.hpp"
     24 #endif
     25 
     26 #include <set>
     27 
     28 START_NAMESPACE_DISTRHO
     29 
     30 // -----------------------------------------------------------------------
     31 // Maxmimum values
     32 
     33 static const uint32_t kMaxMidiEvents = 512;
     34 
     35 // -----------------------------------------------------------------------
     36 // Static data, see DistrhoPlugin.cpp
     37 
     38 extern uint32_t    d_nextBufferSize;
     39 extern double      d_nextSampleRate;
     40 extern const char* d_nextBundlePath;
     41 extern bool        d_nextPluginIsDummy;
     42 extern bool        d_nextPluginIsSelfTest;
     43 extern bool        d_nextCanRequestParameterValueChanges;
     44 
     45 // -----------------------------------------------------------------------
     46 // DSP callbacks
     47 
     48 typedef bool (*writeMidiFunc) (void* ptr, const MidiEvent& midiEvent);
     49 typedef bool (*requestParameterValueChangeFunc) (void* ptr, uint32_t index, float value);
     50 typedef bool (*updateStateValueFunc) (void* ptr, const char* key, const char* value);
     51 
     52 // -----------------------------------------------------------------------
     53 // Helpers
     54 
     55 struct AudioPortWithBusId : AudioPort {
     56     uint32_t busId;
     57 
     58     AudioPortWithBusId()
     59         : AudioPort(),
     60           busId(0) {}
     61 };
     62 
     63 struct PortGroupWithId : PortGroup {
     64     uint32_t groupId;
     65 
     66     PortGroupWithId()
     67         : PortGroup(),
     68           groupId(kPortGroupNone) {}
     69 };
     70 
     71 static inline
     72 void fillInPredefinedPortGroupData(const uint32_t groupId, PortGroup& portGroup)
     73 {
     74     switch (groupId)
     75     {
     76     case kPortGroupNone:
     77         portGroup.name.clear();
     78         portGroup.symbol.clear();
     79         break;
     80     case kPortGroupMono:
     81         portGroup.name = "Mono";
     82         portGroup.symbol = "dpf_mono";
     83         break;
     84     case kPortGroupStereo:
     85         portGroup.name = "Stereo";
     86         portGroup.symbol = "dpf_stereo";
     87         break;
     88     }
     89 }
     90 
     91 static inline
     92 void d_strncpy(char* const dst, const char* const src, const size_t length)
     93 {
     94     DISTRHO_SAFE_ASSERT_RETURN(length > 0,);
     95 
     96     if (const size_t len = std::min(std::strlen(src), length-1U))
     97     {
     98         std::memcpy(dst, src, len);
     99         dst[len] = '\0';
    100     }
    101     else
    102     {
    103         dst[0] = '\0';
    104     }
    105 }
    106 
    107 template<typename T>
    108 static inline
    109 void snprintf_t(char* const dst, const T value, const char* const format, const size_t size)
    110 {
    111     DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
    112     std::snprintf(dst, size-1, format, value);
    113     dst[size-1] = '\0';
    114 }
    115 
    116 static inline
    117 void snprintf_f32(char* const dst, const float value, const size_t size)
    118 {
    119     return snprintf_t<float>(dst, value, "%f", size);
    120 }
    121 
    122 static inline
    123 void snprintf_f32(char* const dst, const double value, const size_t size)
    124 {
    125     return snprintf_t<double>(dst, value, "%f", size);
    126 }
    127 
    128 static inline
    129 void snprintf_i32(char* const dst, const int32_t value, const size_t size)
    130 {
    131     return snprintf_t<int32_t>(dst, value, "%d", size);
    132 }
    133 
    134 static inline
    135 void snprintf_u32(char* const dst, const uint32_t value, const size_t size)
    136 {
    137     return snprintf_t<uint32_t>(dst, value, "%u", size);
    138 }
    139 
    140 // -----------------------------------------------------------------------
    141 // Plugin private data
    142 
    143 struct Plugin::PrivateData {
    144     const bool canRequestParameterValueChanges;
    145     const bool isDummy;
    146     const bool isSelfTest;
    147     bool isProcessing;
    148 
    149 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
    150     AudioPortWithBusId* audioPorts;
    151 #endif
    152 
    153     uint32_t   parameterCount;
    154     uint32_t   parameterOffset;
    155     Parameter* parameters;
    156 
    157     uint32_t         portGroupCount;
    158     PortGroupWithId* portGroups;
    159 
    160 #if DISTRHO_PLUGIN_WANT_PROGRAMS
    161     uint32_t programCount;
    162     String*  programNames;
    163 #endif
    164 
    165 #if DISTRHO_PLUGIN_WANT_STATE
    166     uint32_t stateCount;
    167     State*   states;
    168 #endif
    169 
    170 #if DISTRHO_PLUGIN_WANT_LATENCY
    171     uint32_t latency;
    172 #endif
    173 
    174 #if DISTRHO_PLUGIN_WANT_TIMEPOS
    175     TimePosition timePosition;
    176 #endif
    177 
    178     // Callbacks
    179     void*         callbacksPtr;
    180     writeMidiFunc writeMidiCallbackFunc;
    181     requestParameterValueChangeFunc requestParameterValueChangeCallbackFunc;
    182     updateStateValueFunc updateStateValueCallbackFunc;
    183 
    184     uint32_t bufferSize;
    185     double   sampleRate;
    186     char*    bundlePath;
    187 
    188     PrivateData() noexcept
    189         : canRequestParameterValueChanges(d_nextCanRequestParameterValueChanges),
    190           isDummy(d_nextPluginIsDummy),
    191           isSelfTest(d_nextPluginIsSelfTest),
    192           isProcessing(false),
    193 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
    194           audioPorts(nullptr),
    195 #endif
    196           parameterCount(0),
    197           parameterOffset(0),
    198           parameters(nullptr),
    199           portGroupCount(0),
    200           portGroups(nullptr),
    201 #if DISTRHO_PLUGIN_WANT_PROGRAMS
    202           programCount(0),
    203           programNames(nullptr),
    204 #endif
    205 #if DISTRHO_PLUGIN_WANT_STATE
    206           stateCount(0),
    207           states(nullptr),
    208 #endif
    209 #if DISTRHO_PLUGIN_WANT_LATENCY
    210           latency(0),
    211 #endif
    212           callbacksPtr(nullptr),
    213           writeMidiCallbackFunc(nullptr),
    214           requestParameterValueChangeCallbackFunc(nullptr),
    215           updateStateValueCallbackFunc(nullptr),
    216           bufferSize(d_nextBufferSize),
    217           sampleRate(d_nextSampleRate),
    218           bundlePath(d_nextBundlePath != nullptr ? strdup(d_nextBundlePath) : nullptr)
    219     {
    220         DISTRHO_SAFE_ASSERT(bufferSize != 0);
    221         DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate));
    222 
    223 #if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2)
    224         parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
    225 # if DISTRHO_PLUGIN_WANT_LATENCY
    226         parameterOffset += 1;
    227 # endif
    228 #endif
    229 
    230 #ifdef DISTRHO_PLUGIN_TARGET_LV2
    231 # if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_STATE || DISTRHO_PLUGIN_WANT_TIMEPOS)
    232         parameterOffset += 1;
    233 # endif
    234 # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE)
    235         parameterOffset += 1;
    236 # endif
    237 #endif
    238 
    239 #ifdef DISTRHO_PLUGIN_TARGET_VST3
    240         parameterOffset += kVst3InternalParameterCount;
    241 #endif
    242     }
    243 
    244     ~PrivateData() noexcept
    245     {
    246 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
    247         if (audioPorts != nullptr)
    248         {
    249             delete[] audioPorts;
    250             audioPorts = nullptr;
    251         }
    252 #endif
    253 
    254         if (parameters != nullptr)
    255         {
    256             delete[] parameters;
    257             parameters = nullptr;
    258         }
    259 
    260         if (portGroups != nullptr)
    261         {
    262             delete[] portGroups;
    263             portGroups = nullptr;
    264         }
    265 
    266 #if DISTRHO_PLUGIN_WANT_PROGRAMS
    267         if (programNames != nullptr)
    268         {
    269             delete[] programNames;
    270             programNames = nullptr;
    271         }
    272 #endif
    273 
    274 #if DISTRHO_PLUGIN_WANT_STATE
    275         if (states != nullptr)
    276         {
    277             delete[] states;
    278             states = nullptr;
    279         }
    280 #endif
    281 
    282         if (bundlePath != nullptr)
    283         {
    284             std::free(bundlePath);
    285             bundlePath = nullptr;
    286         }
    287     }
    288 
    289 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
    290     bool writeMidiCallback(const MidiEvent& midiEvent)
    291     {
    292         if (writeMidiCallbackFunc != nullptr)
    293             return writeMidiCallbackFunc(callbacksPtr, midiEvent);
    294 
    295         return false;
    296     }
    297 #endif
    298 
    299 #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
    300     bool requestParameterValueChangeCallback(const uint32_t index, const float value)
    301     {
    302         if (requestParameterValueChangeCallbackFunc != nullptr)
    303             return requestParameterValueChangeCallbackFunc(callbacksPtr, index, value);
    304 
    305         return false;
    306     }
    307 #endif
    308 
    309 #if DISTRHO_PLUGIN_WANT_STATE
    310     bool updateStateValueCallback(const char* const key, const char* const value)
    311     {
    312         d_stdout("updateStateValueCallback %p", updateStateValueCallbackFunc);
    313         if (updateStateValueCallbackFunc != nullptr)
    314             return updateStateValueCallbackFunc(callbacksPtr, key, value);
    315 
    316         return false;
    317     }
    318 #endif
    319 };
    320 
    321 // -----------------------------------------------------------------------
    322 // Plugin exporter class
    323 
    324 class PluginExporter
    325 {
    326 public:
    327     PluginExporter(void* const callbacksPtr,
    328                    const writeMidiFunc writeMidiCall,
    329                    const requestParameterValueChangeFunc requestParameterValueChangeCall,
    330                    const updateStateValueFunc updateStateValueCall)
    331         : fPlugin(createPlugin()),
    332           fData((fPlugin != nullptr) ? fPlugin->pData : nullptr),
    333           fIsActive(false)
    334     {
    335         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
    336         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
    337 
    338 #if defined(DPF_RUNTIME_TESTING) && defined(__GNUC__) && !defined(__clang__)
    339         /* Run-time testing build.
    340          * Verify that virtual functions are overriden if parameters, programs or states are in use.
    341          * This does not work on all compilers, but we use it purely as informational check anyway. */
    342         if (fData->parameterCount != 0)
    343         {
    344             if ((void*)(fPlugin->*(&Plugin::initParameter)) == (void*)&Plugin::initParameter)
    345             {
    346                 d_stderr2("DPF warning: Plugins with parameters must implement `initParameter`");
    347                 abort();
    348             }
    349             if ((void*)(fPlugin->*(&Plugin::getParameterValue)) == (void*)&Plugin::getParameterValue)
    350             {
    351                 d_stderr2("DPF warning: Plugins with parameters must implement `getParameterValue`");
    352                 abort();
    353             }
    354             if ((void*)(fPlugin->*(&Plugin::setParameterValue)) == (void*)&Plugin::setParameterValue)
    355             {
    356                 d_stderr2("DPF warning: Plugins with parameters must implement `setParameterValue`");
    357                 abort();
    358             }
    359         }
    360 
    361 # if DISTRHO_PLUGIN_WANT_PROGRAMS
    362         if (fData->programCount != 0)
    363         {
    364             if ((void*)(fPlugin->*(&Plugin::initProgramName)) == (void*)&Plugin::initProgramName)
    365             {
    366                 d_stderr2("DPF warning: Plugins with programs must implement `initProgramName`");
    367                 abort();
    368             }
    369             if ((void*)(fPlugin->*(&Plugin::loadProgram)) == (void*)&Plugin::loadProgram)
    370             {
    371                 d_stderr2("DPF warning: Plugins with programs must implement `loadProgram`");
    372                 abort();
    373             }
    374         }
    375 # endif
    376 
    377 # if DISTRHO_PLUGIN_WANT_STATE
    378         if (fData->stateCount != 0)
    379         {
    380             if ((void*)(fPlugin->*(static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState))) ==
    381                 (void*)static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState))
    382             {
    383                 d_stderr2("DPF warning: Plugins with state must implement `initState`");
    384                 abort();
    385             }
    386 
    387             if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState)
    388             {
    389                 d_stderr2("DPF warning: Plugins with state must implement `setState`");
    390                 abort();
    391             }
    392         }
    393 # endif
    394 
    395 # if DISTRHO_PLUGIN_WANT_FULL_STATE
    396         if (fData->stateCount != 0)
    397         {
    398             if ((void*)(fPlugin->*(&Plugin::getState)) == (void*)&Plugin::getState)
    399             {
    400                 d_stderr2("DPF warning: Plugins with full state must implement `getState`");
    401                 abort();
    402             }
    403         }
    404         else
    405         {
    406             d_stderr2("DPF warning: Plugins with full state must have at least 1 state");
    407             abort();
    408         }
    409 # endif
    410 #endif
    411 
    412 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
    413         {
    414             uint32_t j=0;
    415 # if DISTRHO_PLUGIN_NUM_INPUTS > 0
    416             for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j)
    417                 fPlugin->initAudioPort(true, i, fData->audioPorts[j]);
    418 # endif
    419 # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
    420             for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j)
    421                 fPlugin->initAudioPort(false, i, fData->audioPorts[j]);
    422 # endif
    423         }
    424 #endif // DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
    425 
    426         for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
    427             fPlugin->initParameter(i, fData->parameters[i]);
    428 
    429         {
    430             std::set<uint32_t> portGroupIndices;
    431 
    432 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
    433             for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
    434                 portGroupIndices.insert(fData->audioPorts[i].groupId);
    435 #endif
    436             for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
    437                 portGroupIndices.insert(fData->parameters[i].groupId);
    438 
    439             portGroupIndices.erase(kPortGroupNone);
    440 
    441             if (const uint32_t portGroupSize = static_cast<uint32_t>(portGroupIndices.size()))
    442             {
    443                 fData->portGroups = new PortGroupWithId[portGroupSize];
    444                 fData->portGroupCount = portGroupSize;
    445 
    446                 uint32_t index = 0;
    447                 for (std::set<uint32_t>::iterator it = portGroupIndices.begin(); it != portGroupIndices.end(); ++it, ++index)
    448                 {
    449                     PortGroupWithId& portGroup(fData->portGroups[index]);
    450                     portGroup.groupId = *it;
    451 
    452                     if (portGroup.groupId < portGroupSize)
    453                         fPlugin->initPortGroup(portGroup.groupId, portGroup);
    454                     else
    455                         fillInPredefinedPortGroupData(portGroup.groupId, portGroup);
    456                 }
    457             }
    458         }
    459 
    460 #if DISTRHO_PLUGIN_WANT_PROGRAMS
    461         for (uint32_t i=0, count=fData->programCount; i < count; ++i)
    462             fPlugin->initProgramName(i, fData->programNames[i]);
    463 #endif
    464 
    465 #if DISTRHO_PLUGIN_WANT_STATE
    466         for (uint32_t i=0, count=fData->stateCount; i < count; ++i)
    467             fPlugin->initState(i, fData->states[i]);
    468 #endif
    469 
    470         fData->callbacksPtr = callbacksPtr;
    471         fData->writeMidiCallbackFunc = writeMidiCall;
    472         fData->requestParameterValueChangeCallbackFunc = requestParameterValueChangeCall;
    473         fData->updateStateValueCallbackFunc = updateStateValueCall;
    474     }
    475 
    476     ~PluginExporter()
    477     {
    478         delete fPlugin;
    479     }
    480 
    481     // -------------------------------------------------------------------
    482 
    483     const char* getName() const noexcept
    484     {
    485         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
    486 
    487         return fPlugin->getName();
    488     }
    489 
    490     const char* getLabel() const noexcept
    491     {
    492         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
    493 
    494         return fPlugin->getLabel();
    495     }
    496 
    497     const char* getDescription() const noexcept
    498     {
    499         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
    500 
    501         return fPlugin->getDescription();
    502     }
    503 
    504     const char* getMaker() const noexcept
    505     {
    506         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
    507 
    508         return fPlugin->getMaker();
    509     }
    510 
    511     const char* getHomePage() const noexcept
    512     {
    513         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
    514 
    515         return fPlugin->getHomePage();
    516     }
    517 
    518     const char* getLicense() const noexcept
    519     {
    520         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
    521 
    522         return fPlugin->getLicense();
    523     }
    524 
    525     uint32_t getVersion() const noexcept
    526     {
    527         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0);
    528 
    529         return fPlugin->getVersion();
    530     }
    531 
    532     long getUniqueId() const noexcept
    533     {
    534         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0);
    535 
    536         return fPlugin->getUniqueId();
    537     }
    538 
    539     void* getInstancePointer() const noexcept
    540     {
    541         return fPlugin;
    542     }
    543 
    544     // -------------------------------------------------------------------
    545 
    546 #if DISTRHO_PLUGIN_WANT_LATENCY
    547     uint32_t getLatency() const noexcept
    548     {
    549         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
    550 
    551         return fData->latency;
    552     }
    553 #endif
    554 
    555 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
    556     AudioPortWithBusId& getAudioPort(const bool input, const uint32_t index) const noexcept
    557     {
    558         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort);
    559 
    560         if (input)
    561         {
    562 # if DISTRHO_PLUGIN_NUM_INPUTS > 0
    563             DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_INPUTS,  sFallbackAudioPort);
    564 # endif
    565         }
    566         else
    567         {
    568 # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
    569             DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_OUTPUTS, sFallbackAudioPort);
    570 # endif
    571         }
    572 
    573         return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)];
    574     }
    575 
    576     uint32_t getAudioPortHints(const bool input, const uint32_t index) const noexcept
    577     {
    578         return getAudioPort(input, index).hints;
    579     }
    580     
    581     uint32_t getAudioPortCountWithGroupId(const bool input, const uint32_t groupId) const noexcept
    582     {
    583         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
    584 
    585         uint32_t numPorts = 0;
    586 
    587         if (input)
    588         {
    589            #if DISTRHO_PLUGIN_NUM_INPUTS > 0
    590             for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
    591             {
    592                 if (fData->audioPorts[i].groupId == groupId)
    593                     ++numPorts;
    594             }
    595            #endif
    596         }
    597         else
    598         {
    599            #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
    600             for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
    601             {
    602                 if (fData->audioPorts[i + DISTRHO_PLUGIN_NUM_INPUTS].groupId == groupId)
    603                     ++numPorts;
    604             }
    605            #endif
    606         }
    607 
    608         return numPorts;
    609     }
    610 #endif
    611 
    612     uint32_t getParameterCount() const noexcept
    613     {
    614         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
    615 
    616         return fData->parameterCount;
    617     }
    618 
    619     uint32_t getParameterOffset() const noexcept
    620     {
    621         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
    622 
    623         return fData->parameterOffset;
    624     }
    625 
    626     uint32_t getParameterHints(const uint32_t index) const noexcept
    627     {
    628         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0x0);
    629 
    630         return fData->parameters[index].hints;
    631     }
    632 
    633     ParameterDesignation getParameterDesignation(const uint32_t index) const noexcept
    634     {
    635         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kParameterDesignationNull);
    636 
    637         return fData->parameters[index].designation;
    638     }
    639 
    640     bool isParameterInput(const uint32_t index) const noexcept
    641     {
    642         return (getParameterHints(index) & kParameterIsOutput) == 0x0;
    643     }
    644 
    645     bool isParameterOutput(const uint32_t index) const noexcept
    646     {
    647         return (getParameterHints(index) & kParameterIsOutput) != 0x0;
    648     }
    649 
    650     bool isParameterInteger(const uint32_t index) const noexcept
    651     {
    652         return (getParameterHints(index) & kParameterIsInteger) != 0x0;
    653     }
    654 
    655     bool isParameterTrigger(const uint32_t index) const noexcept
    656     {
    657         return (getParameterHints(index) & kParameterIsTrigger) == kParameterIsTrigger;
    658     }
    659 
    660     bool isParameterOutputOrTrigger(const uint32_t index) const noexcept
    661     {
    662         const uint32_t hints = getParameterHints(index);
    663 
    664         if (hints & kParameterIsOutput)
    665             return true;
    666         if ((hints & kParameterIsTrigger) == kParameterIsTrigger)
    667             return true;
    668 
    669         return false;
    670     }
    671 
    672     const String& getParameterName(const uint32_t index) const noexcept
    673     {
    674         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
    675 
    676         return fData->parameters[index].name;
    677     }
    678 
    679     const String& getParameterShortName(const uint32_t index) const noexcept
    680     {
    681         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
    682 
    683         return fData->parameters[index].shortName;
    684     }
    685 
    686     const String& getParameterSymbol(const uint32_t index) const noexcept
    687     {
    688         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
    689 
    690         return fData->parameters[index].symbol;
    691     }
    692 
    693     const String& getParameterUnit(const uint32_t index) const noexcept
    694     {
    695         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
    696 
    697         return fData->parameters[index].unit;
    698     }
    699 
    700     const String& getParameterDescription(const uint32_t index) const noexcept
    701     {
    702         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
    703 
    704         return fData->parameters[index].description;
    705     }
    706 
    707     const ParameterEnumerationValues& getParameterEnumValues(const uint32_t index) const noexcept
    708     {
    709         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackEnumValues);
    710 
    711         return fData->parameters[index].enumValues;
    712     }
    713 
    714     const ParameterRanges& getParameterRanges(const uint32_t index) const noexcept
    715     {
    716         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackRanges);
    717 
    718         return fData->parameters[index].ranges;
    719     }
    720 
    721     uint8_t getParameterMidiCC(const uint32_t index) const noexcept
    722     {
    723         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0);
    724 
    725         return fData->parameters[index].midiCC;
    726     }
    727 
    728     uint32_t getParameterGroupId(const uint32_t index) const noexcept
    729     {
    730         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kPortGroupNone);
    731 
    732         return fData->parameters[index].groupId;
    733     }
    734 
    735     float getParameterDefault(const uint32_t index) const
    736     {
    737         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
    738         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f);
    739 
    740         return fData->parameters[index].ranges.def;
    741     }
    742 
    743     float getParameterValue(const uint32_t index) const
    744     {
    745         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
    746         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f);
    747 
    748         return fPlugin->getParameterValue(index);
    749     }
    750 
    751     void setParameterValue(const uint32_t index, const float value)
    752     {
    753         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
    754         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount,);
    755 
    756         fPlugin->setParameterValue(index, value);
    757     }
    758 
    759     /*
    760     bool getParameterIndexForSymbol(const char* const symbol, uint32_t& index)
    761     {
    762         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false);
    763 
    764         for (uint32_t i=0; i < fData->parameterCount; ++i)
    765         {
    766             if (fData->parameters[i].symbol == symbol)
    767             {
    768                 index = i;
    769                 return true;
    770             }
    771         }
    772 
    773         return false;
    774     }
    775     */
    776 
    777     uint32_t getPortGroupCount() const noexcept
    778     {
    779         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
    780 
    781         return fData->portGroupCount;
    782     }
    783 
    784     const PortGroupWithId& getPortGroupById(const uint32_t groupId) const noexcept
    785     {
    786         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && fData->portGroupCount != 0, sFallbackPortGroup);
    787 
    788         for (uint32_t i=0; i < fData->portGroupCount; ++i)
    789         {
    790             const PortGroupWithId& portGroup(fData->portGroups[i]);
    791 
    792             if (portGroup.groupId == groupId)
    793                 return portGroup;
    794         }
    795 
    796         return sFallbackPortGroup;
    797     }
    798 
    799     const PortGroupWithId& getPortGroupByIndex(const uint32_t index) const noexcept
    800     {
    801         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->portGroupCount, sFallbackPortGroup);
    802 
    803         return fData->portGroups[index];
    804     }
    805 
    806     const String& getPortGroupSymbolForId(const uint32_t groupId) const noexcept
    807     {
    808         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString);
    809 
    810         return getPortGroupById(groupId).symbol;
    811     }
    812 
    813 #if DISTRHO_PLUGIN_WANT_PROGRAMS
    814     uint32_t getProgramCount() const noexcept
    815     {
    816         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
    817 
    818         return fData->programCount;
    819     }
    820 
    821     const String& getProgramName(const uint32_t index) const noexcept
    822     {
    823         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount, sFallbackString);
    824 
    825         return fData->programNames[index];
    826     }
    827 
    828     void loadProgram(const uint32_t index)
    829     {
    830         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
    831         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount,);
    832 
    833         fPlugin->loadProgram(index);
    834     }
    835 #endif
    836 
    837 #if DISTRHO_PLUGIN_WANT_STATE
    838     uint32_t getStateCount() const noexcept
    839     {
    840         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
    841 
    842         return fData->stateCount;
    843     }
    844 
    845     uint32_t getStateHints(const uint32_t index) const noexcept
    846     {
    847         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, 0x0);
    848 
    849         return fData->states[index].hints;
    850     }
    851 
    852     const String& getStateKey(const uint32_t index) const noexcept
    853     {
    854         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
    855 
    856         return fData->states[index].key;
    857     }
    858 
    859     const String& getStateDefaultValue(const uint32_t index) const noexcept
    860     {
    861         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
    862 
    863         return fData->states[index].defaultValue;
    864     }
    865 
    866     const String& getStateLabel(const uint32_t index) const noexcept
    867     {
    868         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
    869 
    870         return fData->states[index].label;
    871     }
    872 
    873     const String& getStateDescription(const uint32_t index) const noexcept
    874     {
    875         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
    876 
    877         return fData->states[index].description;
    878     }
    879 
    880    #ifdef __MOD_DEVICES__
    881     const String& getStateFileTypes(const uint32_t index) const noexcept
    882     {
    883         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
    884 
    885         return fData->states[index].fileTypes;
    886     }
    887    #endif
    888 
    889    #if DISTRHO_PLUGIN_WANT_FULL_STATE
    890     String getStateValue(const char* const key) const
    891     {
    892         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString);
    893         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', sFallbackString);
    894 
    895         return fPlugin->getState(key);
    896     }
    897    #endif
    898 
    899     void setState(const char* const key, const char* const value)
    900     {
    901         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
    902         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
    903         DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
    904 
    905         fPlugin->setState(key, value);
    906     }
    907 
    908     bool wantStateKey(const char* const key) const noexcept
    909     {
    910         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false);
    911         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false);
    912 
    913         for (uint32_t i=0; i < fData->stateCount; ++i)
    914         {
    915             if (fData->states[i].key == key)
    916                 return true;
    917         }
    918 
    919         return false;
    920     }
    921 #endif
    922 
    923 #if DISTRHO_PLUGIN_WANT_TIMEPOS
    924     void setTimePosition(const TimePosition& timePosition) noexcept
    925     {
    926         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
    927 
    928         std::memcpy(&fData->timePosition, &timePosition, sizeof(TimePosition));
    929     }
    930 #endif
    931 
    932     // -------------------------------------------------------------------
    933 
    934     bool isActive() const noexcept
    935     {
    936         return fIsActive;
    937     }
    938 
    939     void activate()
    940     {
    941         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
    942         DISTRHO_SAFE_ASSERT_RETURN(! fIsActive,);
    943 
    944         fIsActive = true;
    945         fPlugin->activate();
    946     }
    947 
    948     void deactivate()
    949     {
    950         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
    951         DISTRHO_SAFE_ASSERT_RETURN(fIsActive,);
    952 
    953         fIsActive = false;
    954         fPlugin->deactivate();
    955     }
    956 
    957     void deactivateIfNeeded()
    958     {
    959         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
    960 
    961         if (fIsActive)
    962         {
    963             fIsActive = false;
    964             fPlugin->deactivate();
    965         }
    966     }
    967 
    968    #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
    969     void run(const float** const inputs, float** const outputs, const uint32_t frames,
    970              const MidiEvent* const midiEvents, const uint32_t midiEventCount)
    971     {
    972         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
    973         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
    974 
    975         if (! fIsActive)
    976         {
    977             fIsActive = true;
    978             fPlugin->activate();
    979         }
    980 
    981         fData->isProcessing = true;
    982         fPlugin->run(inputs, outputs, frames, midiEvents, midiEventCount);
    983         fData->isProcessing = false;
    984     }
    985    #else
    986     void run(const float** const inputs, float** const outputs, const uint32_t frames)
    987     {
    988         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
    989         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
    990 
    991         if (! fIsActive)
    992         {
    993             fIsActive = true;
    994             fPlugin->activate();
    995         }
    996 
    997         fData->isProcessing = true;
    998         fPlugin->run(inputs, outputs, frames);
    999         fData->isProcessing = false;
   1000     }
   1001    #endif
   1002 
   1003     // -------------------------------------------------------------------
   1004 
   1005    #ifdef DISTRHO_PLUGIN_TARGET_AU
   1006     void setAudioPortIO(const uint16_t numInputs, const uint16_t numOutputs)
   1007     {
   1008         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
   1009         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
   1010 
   1011         if (fIsActive) fPlugin->deactivate();
   1012         fPlugin->ioChanged(numInputs, numOutputs);
   1013         if (fIsActive) fPlugin->activate();
   1014     }
   1015    #endif
   1016 
   1017     // -------------------------------------------------------------------
   1018 
   1019     uint32_t getBufferSize() const noexcept
   1020     {
   1021         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
   1022         return fData->bufferSize;
   1023     }
   1024 
   1025     double getSampleRate() const noexcept
   1026     {
   1027         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0.0);
   1028         return fData->sampleRate;
   1029     }
   1030 
   1031     bool setBufferSize(const uint32_t bufferSize, const bool doCallback = false)
   1032     {
   1033         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false);
   1034         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, false);
   1035         DISTRHO_SAFE_ASSERT(bufferSize >= 2);
   1036 
   1037         if (fData->bufferSize == bufferSize)
   1038             return false;
   1039 
   1040         fData->bufferSize = bufferSize;
   1041 
   1042         if (doCallback)
   1043         {
   1044             if (fIsActive) fPlugin->deactivate();
   1045             fPlugin->bufferSizeChanged(bufferSize);
   1046             if (fIsActive) fPlugin->activate();
   1047         }
   1048 
   1049         return true;
   1050     }
   1051 
   1052     void setSampleRate(const double sampleRate, const bool doCallback = false)
   1053     {
   1054         DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
   1055         DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
   1056         DISTRHO_SAFE_ASSERT(sampleRate > 0.0);
   1057 
   1058         if (d_isEqual(fData->sampleRate, sampleRate))
   1059             return;
   1060 
   1061         fData->sampleRate = sampleRate;
   1062 
   1063         if (doCallback)
   1064         {
   1065             if (fIsActive) fPlugin->deactivate();
   1066             fPlugin->sampleRateChanged(sampleRate);
   1067             if (fIsActive) fPlugin->activate();
   1068         }
   1069     }
   1070 
   1071 private:
   1072     // -------------------------------------------------------------------
   1073     // Plugin and DistrhoPlugin data
   1074 
   1075     Plugin* const fPlugin;
   1076     Plugin::PrivateData* const fData;
   1077     bool fIsActive;
   1078 
   1079     // -------------------------------------------------------------------
   1080     // Static fallback data, see DistrhoPlugin.cpp
   1081 
   1082     static const String                     sFallbackString;
   1083     static /* */ AudioPortWithBusId         sFallbackAudioPort;
   1084     static const ParameterRanges            sFallbackRanges;
   1085     static const ParameterEnumerationValues sFallbackEnumValues;
   1086     static const PortGroupWithId            sFallbackPortGroup;
   1087 
   1088     DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter)
   1089 };
   1090 
   1091 // -----------------------------------------------------------------------
   1092 
   1093 END_NAMESPACE_DISTRHO
   1094 
   1095 #endif // DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED