DPF

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

DistrhoPluginCarla.cpp (15714B)


      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 #if DISTRHO_PLUGIN_HAS_UI
     20 # include "DistrhoUIInternal.hpp"
     21 #endif
     22 
     23 #include "CarlaNative.hpp"
     24 
     25 // TODO
     26 #undef DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
     27 #define DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 0
     28 
     29 // -----------------------------------------------------------------------
     30 
     31 START_NAMESPACE_DISTRHO
     32 
     33 #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
     34 static constexpr const writeMidiFunc writeMidiCallback = nullptr;
     35 #endif
     36 #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
     37 static constexpr const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr;
     38 #endif
     39 // TODO
     40 static constexpr const updateStateValueFunc updateStateValueCallback = nullptr;
     41 
     42 #if DISTRHO_PLUGIN_HAS_UI
     43 // -----------------------------------------------------------------------
     44 // Carla UI
     45 
     46 #if ! DISTRHO_PLUGIN_WANT_STATE
     47 static const setStateFunc setStateCallback = nullptr;
     48 #endif
     49 #if ! DISTRHO_PLUGIN_IS_SYNTH
     50 static const sendNoteFunc sendNoteCallback = nullptr;
     51 #endif
     52 
     53 class UICarla
     54 {
     55 public:
     56     UICarla(const NativeHostDescriptor* const host, PluginExporter* const plugin)
     57         : fHost(host),
     58           fUI(this, 0, plugin->getSampleRate(),
     59               editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback,
     60               nullptr, // window size
     61               nullptr, // TODO file request
     62               nullptr, // bundle path
     63               plugin->getInstancePointer())
     64     {
     65         fUI.setWindowTitle(host->uiName);
     66 
     67         if (host->uiParentId != 0)
     68             fUI.setWindowTransientWinId(host->uiParentId);
     69     }
     70 
     71     ~UICarla()
     72     {
     73         fUI.quit();
     74     }
     75 
     76     // ---------------------------------------------
     77 
     78     void carla_show(const bool yesNo)
     79     {
     80         fUI.setWindowVisible(yesNo);
     81     }
     82 
     83     bool carla_idle()
     84     {
     85         return fUI.plugin_idle();
     86     }
     87 
     88     void carla_setParameterValue(const uint32_t index, const float value)
     89     {
     90         fUI.parameterChanged(index, value);
     91     }
     92 
     93 #if DISTRHO_PLUGIN_WANT_PROGRAMS
     94     void carla_setMidiProgram(const uint32_t realProgram)
     95     {
     96         fUI.programLoaded(realProgram);
     97     }
     98 #endif
     99 
    100 #if DISTRHO_PLUGIN_WANT_STATE
    101     void carla_setCustomData(const char* const key, const char* const value)
    102     {
    103         fUI.stateChanged(key, value);
    104     }
    105 #endif
    106 
    107     void carla_setUiTitle(const char* const uiTitle)
    108     {
    109         fUI.setWindowTitle(uiTitle);
    110     }
    111 
    112     // ---------------------------------------------
    113 
    114 protected:
    115     void handleEditParameter(const uint32_t, const bool)
    116     {
    117         // TODO
    118     }
    119 
    120     void handleSetParameterValue(const uint32_t rindex, const float value)
    121     {
    122         fHost->ui_parameter_changed(fHost->handle, rindex, value);
    123     }
    124 
    125 #if DISTRHO_PLUGIN_WANT_STATE
    126     void handleSetState(const char* const key, const char* const value)
    127     {
    128         fHost->ui_custom_data_changed(fHost->handle, key, value);
    129     }
    130 #endif
    131 
    132 #if DISTRHO_PLUGIN_IS_SYNTH
    133     void handleSendNote(const uint8_t, const uint8_t, const uint8_t)
    134     {
    135         // TODO
    136     }
    137 #endif
    138 
    139     // ---------------------------------------------
    140 
    141 private:
    142     // Plugin stuff
    143     const NativeHostDescriptor* const fHost;
    144 
    145     // UI
    146     UIExporter fUI;
    147 
    148     // ---------------------------------------------
    149     // Callbacks
    150 
    151     #define handlePtr ((UICarla*)ptr)
    152 
    153     static void editParameterCallback(void* ptr, uint32_t index, bool started)
    154     {
    155         handlePtr->handleEditParameter(index, started);
    156     }
    157 
    158     static void setParameterCallback(void* ptr, uint32_t rindex, float value)
    159     {
    160         handlePtr->handleSetParameterValue(rindex, value);
    161     }
    162 
    163 #if DISTRHO_PLUGIN_WANT_STATE
    164     static void setStateCallback(void* ptr, const char* key, const char* value)
    165     {
    166         handlePtr->handleSetState(key, value);
    167     }
    168 #endif
    169 
    170 #if DISTRHO_PLUGIN_IS_SYNTH
    171     static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
    172     {
    173         handlePtr->handleSendNote(channel, note, velocity);
    174     }
    175 #endif
    176 
    177     #undef handlePtr
    178 
    179     CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UICarla)
    180 };
    181 #endif // DISTRHO_PLUGIN_HAS_UI
    182 
    183 // -----------------------------------------------------------------------
    184 // Carla Plugin
    185 
    186 class PluginCarla : public NativePluginClass
    187 {
    188 public:
    189     PluginCarla(const NativeHostDescriptor* const host)
    190         : NativePluginClass(host),
    191           fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, updateStateValueCallback),
    192           fScalePointsCache(nullptr)
    193     {
    194 #if DISTRHO_PLUGIN_HAS_UI
    195         fUiPtr = nullptr;
    196 #endif
    197     }
    198 
    199     ~PluginCarla() override
    200     {
    201 #if DISTRHO_PLUGIN_HAS_UI
    202         if (fUiPtr != nullptr)
    203         {
    204             delete fUiPtr;
    205             fUiPtr = nullptr;
    206         }
    207 #endif
    208 
    209         if (fScalePointsCache != nullptr)
    210         {
    211             delete[] fScalePointsCache;
    212             fScalePointsCache = nullptr;
    213         }
    214     }
    215 
    216 protected:
    217     // -------------------------------------------------------------------
    218     // Plugin parameter calls
    219 
    220     uint32_t getParameterCount() const override
    221     {
    222         return fPlugin.getParameterCount();
    223     }
    224 
    225     const NativeParameter* getParameterInfo(const uint32_t index) const override
    226     {
    227         CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(), nullptr);
    228 
    229         static NativeParameter param;
    230 
    231         param.scalePointCount = 0;
    232         param.scalePoints = nullptr;
    233 
    234         {
    235             int      nativeParamHints = ::NATIVE_PARAMETER_IS_ENABLED;
    236             const uint32_t paramHints = fPlugin.getParameterHints(index);
    237 
    238             if (paramHints & kParameterIsAutomatable)
    239                 nativeParamHints |= ::NATIVE_PARAMETER_IS_AUTOMABLE;
    240             if (paramHints & kParameterIsBoolean)
    241                 nativeParamHints |= ::NATIVE_PARAMETER_IS_BOOLEAN;
    242             if (paramHints & kParameterIsInteger)
    243                 nativeParamHints |= ::NATIVE_PARAMETER_IS_INTEGER;
    244             if (paramHints & kParameterIsLogarithmic)
    245                 nativeParamHints |= ::NATIVE_PARAMETER_IS_LOGARITHMIC;
    246             if (paramHints & kParameterIsOutput)
    247                 nativeParamHints |= ::NATIVE_PARAMETER_IS_OUTPUT;
    248 
    249             param.hints = static_cast<NativeParameterHints>(nativeParamHints);
    250         }
    251 
    252         param.name = fPlugin.getParameterName(index);
    253         param.unit = fPlugin.getParameterUnit(index);
    254 
    255         {
    256             const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
    257 
    258             param.ranges.def = ranges.def;
    259             param.ranges.min = ranges.min;
    260             param.ranges.max = ranges.max;
    261         }
    262 
    263         {
    264             const ParameterEnumerationValues& enumValues(fPlugin.getParameterEnumValues(index));
    265 
    266             if (const uint32_t scalePointCount = enumValues.count)
    267             {
    268                 NativeParameterScalePoint* const scalePoints = new NativeParameterScalePoint[scalePointCount];
    269 
    270                 for (uint32_t i=0; i<scalePointCount; ++i)
    271                 {
    272                     scalePoints[i].label = enumValues.values[i].label.buffer();
    273                     scalePoints[i].value = enumValues.values[i].value;
    274                 }
    275 
    276                 param.scalePoints     = scalePoints;
    277                 param.scalePointCount = scalePointCount;
    278 
    279                 if (enumValues.restrictedMode)
    280                     param.hints = static_cast<NativeParameterHints>(param.hints|::NATIVE_PARAMETER_USES_SCALEPOINTS);
    281             }
    282             else if (fScalePointsCache != nullptr)
    283             {
    284                 delete[] fScalePointsCache;
    285                 fScalePointsCache = nullptr;
    286             }
    287         }
    288 
    289         return &param;
    290     }
    291 
    292     float getParameterValue(const uint32_t index) const override
    293     {
    294         CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(), 0.0f);
    295 
    296         return fPlugin.getParameterValue(index);
    297     }
    298 
    299     // -------------------------------------------------------------------
    300     // Plugin midi-program calls
    301 
    302 #if DISTRHO_PLUGIN_WANT_PROGRAMS
    303     uint32_t getMidiProgramCount() const override
    304     {
    305         return fPlugin.getProgramCount();
    306     }
    307 
    308     const NativeMidiProgram* getMidiProgramInfo(const uint32_t index) const override
    309     {
    310         CARLA_SAFE_ASSERT_RETURN(index < getMidiProgramCount(), nullptr);
    311 
    312         static NativeMidiProgram midiProgram;
    313 
    314         midiProgram.bank    = index / 128;
    315         midiProgram.program = index % 128;
    316         midiProgram.name    = fPlugin.getProgramName(index);
    317 
    318         return &midiProgram;
    319     }
    320 #endif
    321 
    322     // -------------------------------------------------------------------
    323     // Plugin state calls
    324 
    325     void setParameterValue(const uint32_t index, const float value) override
    326     {
    327         CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
    328 
    329         fPlugin.setParameterValue(index, value);
    330     }
    331 
    332 #if DISTRHO_PLUGIN_WANT_PROGRAMS
    333     void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
    334     {
    335         const uint32_t realProgram(bank * 128 + program);
    336 
    337         CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),);
    338 
    339         fPlugin.loadProgram(realProgram);
    340     }
    341 #endif
    342 
    343 #if DISTRHO_PLUGIN_WANT_STATE
    344     void setCustomData(const char* const key, const char* const value) override
    345     {
    346         CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
    347         CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
    348 
    349         fPlugin.setState(key, value);
    350     }
    351 #endif
    352 
    353     // -------------------------------------------------------------------
    354     // Plugin process calls
    355 
    356     void activate() override
    357     {
    358         fPlugin.activate();
    359     }
    360 
    361     void deactivate() override
    362     {
    363         fPlugin.deactivate();
    364     }
    365 
    366 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
    367     void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames,
    368                  const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
    369     {
    370         MidiEvent realMidiEvents[midiEventCount];
    371 
    372         for (uint32_t i=0; i < midiEventCount; ++i)
    373         {
    374             const NativeMidiEvent& midiEvent(midiEvents[i]);
    375             MidiEvent& realMidiEvent(realMidiEvents[i]);
    376 
    377             realMidiEvent.frame = midiEvent.time;
    378             realMidiEvent.size  = midiEvent.size;
    379 
    380             uint8_t j=0;
    381             for (; j<midiEvent.size; ++j)
    382                 realMidiEvent.data[j] = midiEvent.data[j];
    383             for (; j<midiEvent.size; ++j)
    384                 realMidiEvent.data[j] = midiEvent.data[j];
    385 
    386             realMidiEvent.dataExt = nullptr;
    387         }
    388 
    389         fPlugin.run(const_cast<const float**>(inBuffer), outBuffer, frames, realMidiEvents, midiEventCount);
    390     }
    391 #else
    392     void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames,
    393                  const NativeMidiEvent* const, const uint32_t) override
    394     {
    395         fPlugin.run(const_cast<const float**>(inBuffer), outBuffer, frames);
    396     }
    397 #endif
    398 
    399     // -------------------------------------------------------------------
    400     // Plugin UI calls
    401 
    402 #if DISTRHO_PLUGIN_HAS_UI
    403     void uiShow(const bool show) override
    404     {
    405         if (show)
    406         {
    407             createUiIfNeeded();
    408             CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
    409 
    410             fUiPtr->carla_show(show);
    411         }
    412         else if (fUiPtr != nullptr)
    413         {
    414             delete fUiPtr;
    415             fUiPtr = nullptr;
    416         }
    417     }
    418 
    419     void uiIdle() override
    420     {
    421         CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
    422 
    423         if (! fUiPtr->carla_idle())
    424         {
    425             uiClosed();
    426 
    427             delete fUiPtr;
    428             fUiPtr = nullptr;
    429         }
    430     }
    431 
    432     void uiSetParameterValue(const uint32_t index, const float value) override
    433     {
    434         CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
    435         CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
    436 
    437         fUiPtr->carla_setParameterValue(index, value);
    438     }
    439 
    440 # if DISTRHO_PLUGIN_WANT_PROGRAMS
    441     void uiSetMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
    442     {
    443         CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
    444 
    445         const uint32_t realProgram(bank * 128 + program);
    446 
    447         CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),);
    448 
    449         fUiPtr->carla_setMidiProgram(realProgram);
    450     }
    451 # endif
    452 
    453 # if DISTRHO_PLUGIN_WANT_STATE
    454     void uiSetCustomData(const char* const key, const char* const value) override
    455     {
    456         CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
    457         CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
    458         CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
    459 
    460         fUiPtr->carla_setCustomData(key, value);
    461     }
    462 # endif
    463 #endif
    464 
    465     // -------------------------------------------------------------------
    466     // Plugin dispatcher calls
    467 
    468     void bufferSizeChanged(const uint32_t bufferSize) override
    469     {
    470         fPlugin.setBufferSize(bufferSize, true);
    471     }
    472 
    473     void sampleRateChanged(const double sampleRate) override
    474     {
    475         fPlugin.setSampleRate(sampleRate, true);
    476     }
    477 
    478 #if DISTRHO_PLUGIN_HAS_UI
    479     void uiNameChanged(const char* const uiName) override
    480     {
    481         CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
    482 
    483         fUiPtr->carla_setUiTitle(uiName);
    484     }
    485 #endif
    486 
    487     // -------------------------------------------------------------------
    488 
    489 private:
    490     PluginExporter fPlugin;
    491     mutable NativeParameterScalePoint* fScalePointsCache;
    492 
    493 #if DISTRHO_PLUGIN_HAS_UI
    494     // UI
    495     UICarla* fUiPtr;
    496 
    497     void createUiIfNeeded()
    498     {
    499         if (fUiPtr == nullptr)
    500             fUiPtr = new UICarla(getHostHandle(), &fPlugin);
    501     }
    502 #endif
    503 
    504 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
    505     static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent)
    506     {
    507         if (midiEvent.size > 4)
    508             return;
    509 
    510         const NativeMidiEvent event = {
    511             midiEvent.frame, 0, midiEvent.size, midiEvent.data
    512         };
    513 
    514         return ((PluginCarla*)ptr)->fPlugin.writeMidiEvent(midiEvent);
    515     }
    516 #endif
    517 
    518 #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
    519     bool requestParameterValueChange(const uint32_t index, const float value)
    520     {
    521         // TODO implementation
    522         return false;
    523     }
    524 
    525     static bool requestParameterValueChangeCallback(void* ptr, const uint32_t index, const float value)
    526     {
    527         return thisPtr->requestParameterValueChange(index, value);
    528     }
    529 #endif
    530 
    531     CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla)
    532 
    533     // -------------------------------------------------------------------
    534 
    535 public:
    536     static NativePluginHandle _instantiate(const NativeHostDescriptor* host)
    537     {
    538         d_nextBufferSize = host->get_buffer_size(host->handle);
    539         d_nextSampleRate = host->get_sample_rate(host->handle);
    540         return new PluginCarla(host);
    541     }
    542 
    543     static void _cleanup(NativePluginHandle handle)
    544     {
    545         delete (PluginCarla*)handle;
    546     }
    547 };
    548 
    549 END_NAMESPACE_DISTRHO
    550 
    551 // -----------------------------------------------------------------------