diff DPF-Prymula-audioplugins/dpf/distrho/src/DistrhoPluginLADSPA+DSSI.cpp @ 3:84e66ea83026

DPF-Prymula-audioplugins-0.231015-2
author prymula <prymula76@outlook.com>
date Mon, 16 Oct 2023 21:53:34 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DPF-Prymula-audioplugins/dpf/distrho/src/DistrhoPluginLADSPA+DSSI.cpp	Mon Oct 16 21:53:34 2023 +0200
@@ -0,0 +1,761 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with
+ * or without fee is hereby granted, provided that the above copyright notice and this
+ * permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "DistrhoPluginInternal.hpp"
+
+#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
+# error Cannot use parameter value change request with LADSPA or DSSI
+#endif
+#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
+# error Cannot use MIDI Output with LADSPA or DSSI
+#endif
+#if DISTRHO_PLUGIN_WANT_FULL_STATE && !defined(DISTRHO_PLUGIN_WANT_FULL_STATE_WITH_LADSPA)
+# error Cannot use full state with LADSPA or DSSI
+#endif
+
+#if DISTRHO_PLUGIN_WANT_TIMEPOS && !defined(DISTRHO_NO_WARNINGS)
+# warning LADSPA/DSSI does not support TimePos
+#endif
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+# include "dssi/dssi.h"
+#else
+# include "ladspa/ladspa.h"
+# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
+#  error Cannot use MIDI with LADSPA
+# endif
+# if DISTRHO_PLUGIN_WANT_STATE && !defined(DISTRHO_NO_WARNINGS)
+#  warning LADSPA cannot handle states
+# endif
+#endif
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+
+class PluginLadspaDssi
+{
+public:
+    PluginLadspaDssi()
+        : fPlugin(nullptr, nullptr, nullptr, nullptr),
+          fPortControls(nullptr),
+          fLastControlValues(nullptr)
+    {
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+        for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
+            fPortAudioIns[i] = nullptr;
+#else
+        fPortAudioIns = nullptr;
+#endif
+
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+        for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
+            fPortAudioOuts[i] = nullptr;
+#else
+        fPortAudioOuts = nullptr;
+#endif
+
+        if (const uint32_t count = fPlugin.getParameterCount())
+        {
+            fPortControls      = new LADSPA_Data*[count];
+            fLastControlValues = new LADSPA_Data[count];
+
+            for (uint32_t i=0; i < count; ++i)
+            {
+                fPortControls[i] = nullptr;
+                fLastControlValues[i] = fPlugin.getParameterValue(i);
+            }
+        }
+        else
+        {
+            fPortControls = nullptr;
+            fLastControlValues = nullptr;
+        }
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+        fPortLatency = nullptr;
+#endif
+    }
+
+    ~PluginLadspaDssi() noexcept
+    {
+        if (fPortControls != nullptr)
+        {
+            delete[] fPortControls;
+            fPortControls = nullptr;
+        }
+
+        if (fLastControlValues != nullptr)
+        {
+            delete[] fLastControlValues;
+            fLastControlValues = nullptr;
+        }
+    }
+
+    // -------------------------------------------------------------------
+
+    void ladspa_activate()
+    {
+        fPlugin.activate();
+    }
+
+    void ladspa_deactivate()
+    {
+        fPlugin.deactivate();
+    }
+
+    // -------------------------------------------------------------------
+
+    void ladspa_connect_port(const ulong port, LADSPA_Data* const dataLocation) noexcept
+    {
+        ulong index = 0;
+
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+        for (ulong i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i)
+        {
+            if (port == index++)
+            {
+                fPortAudioIns[i] = dataLocation;
+                return;
+            }
+        }
+#endif
+
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+        for (ulong i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
+        {
+            if (port == index++)
+            {
+                fPortAudioOuts[i] = dataLocation;
+                return;
+            }
+        }
+#endif
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+        if (port == index++)
+        {
+            fPortLatency = dataLocation;
+            return;
+        }
+#endif
+
+        for (ulong i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+        {
+            if (port == index++)
+            {
+                fPortControls[i] = dataLocation;
+                return;
+            }
+        }
+    }
+
+    // -------------------------------------------------------------------
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+    void ladspa_run(const ulong sampleCount)
+    {
+        dssi_run_synth(sampleCount, nullptr, 0);
+    }
+
+    void dssi_run_synth(const ulong sampleCount, snd_seq_event_t* const events, const ulong eventCount)
+#else
+    void ladspa_run(const ulong sampleCount)
+#endif
+    {
+        // pre-roll
+        if (sampleCount == 0)
+            return updateParameterOutputsAndTriggers();
+
+        // Check for updated parameters
+        float curValue;
+
+        for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+        {
+            if (fPortControls[i] == nullptr)
+                continue;
+
+            curValue = *fPortControls[i];
+
+            if (fPlugin.isParameterInput(i) && d_isNotEqual(fLastControlValues[i], curValue))
+            {
+                fLastControlValues[i] = curValue;
+                fPlugin.setParameterValue(i, curValue);
+            }
+        }
+
+#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
+        // Get MIDI Events
+        uint32_t  midiEventCount = 0;
+        MidiEvent midiEvents[eventCount];
+
+        for (uint32_t i=0, j; i < eventCount; ++i)
+        {
+            const snd_seq_event_t& seqEvent(events[i]);
+
+            // FIXME
+            if (seqEvent.data.note.channel > 0xF || seqEvent.data.control.channel > 0xF)
+                continue;
+
+            switch (seqEvent.type)
+            {
+            case SND_SEQ_EVENT_NOTEOFF:
+                j = midiEventCount++;
+                midiEvents[j].frame   = seqEvent.time.tick;
+                midiEvents[j].size    = 3;
+                midiEvents[j].data[0] = 0x80 + seqEvent.data.note.channel;
+                midiEvents[j].data[1] = seqEvent.data.note.note;
+                midiEvents[j].data[2] = 0;
+                midiEvents[j].data[3] = 0;
+                break;
+            case SND_SEQ_EVENT_NOTEON:
+                j = midiEventCount++;
+                midiEvents[j].frame   = seqEvent.time.tick;
+                midiEvents[j].size    = 3;
+                midiEvents[j].data[0] = 0x90 + seqEvent.data.note.channel;
+                midiEvents[j].data[1] = seqEvent.data.note.note;
+                midiEvents[j].data[2] = seqEvent.data.note.velocity;
+                midiEvents[j].data[3] = 0;
+                break;
+            case SND_SEQ_EVENT_KEYPRESS:
+                j = midiEventCount++;
+                midiEvents[j].frame   = seqEvent.time.tick;
+                midiEvents[j].size    = 3;
+                midiEvents[j].data[0] = 0xA0 + seqEvent.data.note.channel;
+                midiEvents[j].data[1] = seqEvent.data.note.note;
+                midiEvents[j].data[2] = seqEvent.data.note.velocity;
+                midiEvents[j].data[3] = 0;
+                break;
+            case SND_SEQ_EVENT_CONTROLLER:
+                j = midiEventCount++;
+                midiEvents[j].frame   = seqEvent.time.tick;
+                midiEvents[j].size    = 3;
+                midiEvents[j].data[0] = 0xB0 + seqEvent.data.control.channel;
+                midiEvents[j].data[1] = seqEvent.data.control.param;
+                midiEvents[j].data[2] = seqEvent.data.control.value;
+                midiEvents[j].data[3] = 0;
+                break;
+            case SND_SEQ_EVENT_CHANPRESS:
+                j = midiEventCount++;
+                midiEvents[j].frame   = seqEvent.time.tick;
+                midiEvents[j].size    = 2;
+                midiEvents[j].data[0] = 0xD0 + seqEvent.data.control.channel;
+                midiEvents[j].data[1] = seqEvent.data.control.value;
+                midiEvents[j].data[2] = 0;
+                midiEvents[j].data[3] = 0;
+                break;
+            case SND_SEQ_EVENT_PITCHBEND:
+                j = midiEventCount++;
+                midiEvents[j].frame   = seqEvent.time.tick;
+                midiEvents[j].size    = 3;
+                midiEvents[j].data[0] = 0xE0 + seqEvent.data.control.channel;
+                uint16_t tempvalue = seqEvent.data.control.value + 8192;
+                midiEvents[j].data[1] = tempvalue & 0x7F;
+                midiEvents[j].data[2] = tempvalue >> 7;
+                midiEvents[j].data[3] = 0;
+                break;
+            }
+        }
+
+        fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, midiEvents, midiEventCount);
+#else
+        fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount);
+#endif
+
+        updateParameterOutputsAndTriggers();
+
+#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
+        return; // unused
+        (void)events; (void)eventCount;
+#endif
+    }
+
+    // -------------------------------------------------------------------
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+# if DISTRHO_PLUGIN_WANT_STATE
+    char* dssi_configure(const char* const key, const char* const value)
+    {
+        if (std::strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, std::strlen(DSSI_RESERVED_CONFIGURE_PREFIX)) == 0)
+            return nullptr;
+        if (std::strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX, std::strlen(DSSI_GLOBAL_CONFIGURE_PREFIX)) == 0)
+            return nullptr;
+
+        fPlugin.setState(key, value);
+        return nullptr;
+    }
+# endif
+
+# if DISTRHO_PLUGIN_WANT_PROGRAMS
+    const DSSI_Program_Descriptor* dssi_get_program(const ulong index)
+    {
+        if (index >= fPlugin.getProgramCount())
+            return nullptr;
+
+        static DSSI_Program_Descriptor desc;
+
+        desc.Bank    = index / 128;
+        desc.Program = index % 128;
+        desc.Name    = fPlugin.getProgramName(index);
+
+        return &desc;
+    }
+
+    void dssi_select_program(const ulong bank, const ulong program)
+    {
+        const ulong realProgram(bank * 128 + program);
+
+        DISTRHO_SAFE_ASSERT_RETURN(realProgram < fPlugin.getProgramCount(),);
+
+        fPlugin.loadProgram(realProgram);
+
+        // Update control inputs
+        for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+        {
+            if (fPlugin.isParameterOutput(i))
+                continue;
+
+            fLastControlValues[i] = fPlugin.getParameterValue(i);
+
+            if (fPortControls[i] != nullptr)
+                *fPortControls[i] = fLastControlValues[i];
+        }
+    }
+# endif
+
+    int dssi_get_midi_controller_for_port(const ulong port) noexcept
+    {
+        const uint32_t parameterOffset = fPlugin.getParameterOffset();
+
+        if (port > parameterOffset)
+            return DSSI_NONE;
+
+        const uint8_t midiCC = fPlugin.getParameterMidiCC(port-parameterOffset);
+
+        if (midiCC == 0 || midiCC == 32 || midiCC >= 0x78)
+            return DSSI_NONE;
+
+        return DSSI_CC(midiCC);
+    }
+#endif
+
+    // -------------------------------------------------------------------
+
+private:
+    PluginExporter fPlugin;
+
+    // LADSPA ports
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+    const LADSPA_Data*  fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS];
+#else
+    const LADSPA_Data** fPortAudioIns;
+#endif
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+    LADSPA_Data*  fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS];
+#else
+    LADSPA_Data** fPortAudioOuts;
+#endif
+    LADSPA_Data** fPortControls;
+#if DISTRHO_PLUGIN_WANT_LATENCY
+    LADSPA_Data*  fPortLatency;
+#endif
+
+    // Temporary data
+    LADSPA_Data* fLastControlValues;
+
+    // -------------------------------------------------------------------
+
+    void updateParameterOutputsAndTriggers()
+    {
+        float value;
+
+        for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
+        {
+            if (fPlugin.isParameterOutput(i))
+            {
+                value = fLastControlValues[i] = fPlugin.getParameterValue(i);
+
+                if (fPortControls[i] != nullptr)
+                    *fPortControls[i] = value;
+            }
+            else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger)
+            {
+                // NOTE: no trigger support in LADSPA control ports, simulate it here
+                value = fPlugin.getParameterRanges(i).def;
+
+                if (d_isEqual(value, fPlugin.getParameterValue(i)))
+                    continue;
+
+                fLastControlValues[i] = value;
+                fPlugin.setParameterValue(i, value);
+
+                if (fPortControls[i] != nullptr)
+                    *fPortControls[i] = value;
+            }
+        }
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+        if (fPortLatency != nullptr)
+            *fPortLatency = fPlugin.getLatency();
+#endif
+    }
+};
+
+// -----------------------------------------------------------------------
+
+static LADSPA_Handle ladspa_instantiate(const LADSPA_Descriptor*, ulong sampleRate)
+{
+    if (d_nextBufferSize == 0)
+        d_nextBufferSize = 2048;
+    d_nextSampleRate = sampleRate;
+
+    return new PluginLadspaDssi();
+}
+
+#define instancePtr ((PluginLadspaDssi*)instance)
+
+static void ladspa_connect_port(LADSPA_Handle instance, ulong port, LADSPA_Data* dataLocation)
+{
+    instancePtr->ladspa_connect_port(port, dataLocation);
+}
+
+static void ladspa_activate(LADSPA_Handle instance)
+{
+    instancePtr->ladspa_activate();
+}
+
+static void ladspa_run(LADSPA_Handle instance, ulong sampleCount)
+{
+    instancePtr->ladspa_run(sampleCount);
+}
+
+static void ladspa_deactivate(LADSPA_Handle instance)
+{
+    instancePtr->ladspa_deactivate();
+}
+
+static void ladspa_cleanup(LADSPA_Handle instance)
+{
+    delete instancePtr;
+}
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+# if DISTRHO_PLUGIN_WANT_STATE
+static char* dssi_configure(LADSPA_Handle instance, const char* key, const char* value)
+{
+    return instancePtr->dssi_configure(key, value);
+}
+# endif
+
+# if DISTRHO_PLUGIN_WANT_PROGRAMS
+static const DSSI_Program_Descriptor* dssi_get_program(LADSPA_Handle instance, ulong index)
+{
+    return instancePtr->dssi_get_program(index);
+}
+
+static void dssi_select_program(LADSPA_Handle instance, ulong bank, ulong program)
+{
+    instancePtr->dssi_select_program(bank, program);
+}
+# endif
+
+static int dssi_get_midi_controller_for_port(LADSPA_Handle instance, ulong port)
+{
+    return instancePtr->dssi_get_midi_controller_for_port(port);
+}
+
+# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
+static void dssi_run_synth(LADSPA_Handle instance, ulong sampleCount, snd_seq_event_t* events, ulong eventCount)
+{
+    instancePtr->dssi_run_synth(sampleCount, events, eventCount);
+}
+# endif
+#endif
+
+#undef instancePtr
+
+// -----------------------------------------------------------------------
+
+static LADSPA_Descriptor sLadspaDescriptor = {
+    /* UniqueID   */ 0,
+    /* Label      */ nullptr,
+#if DISTRHO_PLUGIN_IS_RT_SAFE
+    /* Properties */ LADSPA_PROPERTY_HARD_RT_CAPABLE,
+#else
+    /* Properties */ 0x0,
+#endif
+    /* Name       */ nullptr,
+    /* Maker      */ nullptr,
+    /* Copyright  */ nullptr,
+    /* PortCount  */ 0,
+    /* PortDescriptors    */ nullptr,
+    /* PortNames          */ nullptr,
+    /* PortRangeHints     */ nullptr,
+    /* ImplementationData */ nullptr,
+    ladspa_instantiate,
+    ladspa_connect_port,
+    ladspa_activate,
+    ladspa_run,
+    /* run_adding */          nullptr,
+    /* set_run_adding_gain */ nullptr,
+    ladspa_deactivate,
+    ladspa_cleanup
+};
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+static DSSI_Descriptor sDssiDescriptor = {
+    1,
+    &sLadspaDescriptor,
+# if DISTRHO_PLUGIN_WANT_STATE
+    dssi_configure,
+# else
+    /* configure                    */ nullptr,
+# endif
+# if DISTRHO_PLUGIN_WANT_PROGRAMS
+    dssi_get_program,
+    dssi_select_program,
+# else
+    /* get_program                  */ nullptr,
+    /* select_program               */ nullptr,
+# endif
+    dssi_get_midi_controller_for_port,
+# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
+    dssi_run_synth,
+# else
+    /* run_synth                    */ nullptr,
+# endif
+    /* run_synth_adding             */ nullptr,
+    /* run_multiple_synths          */ nullptr,
+    /* run_multiple_synths_adding   */ nullptr,
+    nullptr, nullptr
+};
+#endif
+
+// -----------------------------------------------------------------------
+
+static const struct DescriptorInitializer
+{
+    DescriptorInitializer()
+    {
+        // Create dummy plugin to get data from
+        d_nextBufferSize = 512;
+        d_nextSampleRate = 44100.0;
+        d_nextPluginIsDummy = true;
+        const PluginExporter plugin(nullptr, nullptr, nullptr, nullptr);
+        d_nextBufferSize = 0;
+        d_nextSampleRate = 0.0;
+        d_nextPluginIsDummy = false;
+
+        // Get port count, init
+        ulong port = 0;
+        ulong portCount = DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS + plugin.getParameterCount();
+#if DISTRHO_PLUGIN_WANT_LATENCY
+        portCount += 1;
+#endif
+        const char** const     portNames       = new const char*[portCount];
+        LADSPA_PortDescriptor* portDescriptors = new LADSPA_PortDescriptor[portCount];
+        LADSPA_PortRangeHint*  portRangeHints  = new LADSPA_PortRangeHint [portCount];
+
+        // Set ports
+#if DISTRHO_PLUGIN_NUM_INPUTS > 0
+        for (ulong i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++port)
+        {
+            const AudioPort& aport(plugin.getAudioPort(true, i));
+
+            portNames[port]       = strdup(aport.name);
+            portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT;
+
+            portRangeHints[port].HintDescriptor = 0x0;
+            portRangeHints[port].LowerBound = 0.0f;
+            portRangeHints[port].UpperBound = 1.0f;
+        }
+#endif
+
+#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+        for (ulong i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++port)
+        {
+            const AudioPort& aport(plugin.getAudioPort(false, i));
+
+            portNames[port]       = strdup(aport.name);
+            portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT;
+
+            portRangeHints[port].HintDescriptor = 0x0;
+            portRangeHints[port].LowerBound = 0.0f;
+            portRangeHints[port].UpperBound = 1.0f;
+        }
+#endif
+
+#if DISTRHO_PLUGIN_WANT_LATENCY
+        // Set latency port
+        portNames[port]       = strdup("_latency");
+        portDescriptors[port] = LADSPA_PORT_CONTROL | LADSPA_PORT_OUTPUT;
+        portRangeHints[port].HintDescriptor = LADSPA_HINT_SAMPLE_RATE|LADSPA_HINT_INTEGER;
+        portRangeHints[port].LowerBound     = 0.0f;
+        portRangeHints[port].UpperBound     = 1.0f;
+        ++port;
+#endif
+
+        for (ulong i=0, count=plugin.getParameterCount(); i < count; ++i, ++port)
+        {
+            portNames[port]       = strdup((const char*)plugin.getParameterName(i));
+            portDescriptors[port] = LADSPA_PORT_CONTROL;
+
+            if (plugin.isParameterOutput(i))
+                portDescriptors[port] |= LADSPA_PORT_OUTPUT;
+            else
+                portDescriptors[port] |= LADSPA_PORT_INPUT;
+
+            const uint32_t hints = plugin.getParameterHints(i);
+
+            {
+                const ParameterRanges& ranges(plugin.getParameterRanges(i));
+                const float defValue = ranges.def;
+
+                // LADSPA doesn't allow bounded hints on toggles
+                portRangeHints[port].HintDescriptor = hints & kParameterIsBoolean
+                                                    ? 0
+                                                    : LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
+
+                portRangeHints[port].LowerBound = ranges.min;
+                portRangeHints[port].UpperBound = ranges.max;
+
+                /**/ if (d_isZero(defValue))
+                    portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_0;
+                else if (d_isEqual(defValue, 1.0f))
+                    portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_1;
+                else if (d_isEqual(defValue, 100.0f))
+                    portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_100;
+                else if (d_isEqual(defValue, 440.0f))
+                    portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_440;
+                else if (d_isEqual(ranges.min, defValue))
+                    portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MINIMUM;
+                else if (d_isEqual(ranges.max, defValue))
+                    portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MAXIMUM;
+                else
+                {
+                    const float middleValue =  ranges.min/2.0f + ranges.max/2.0f;
+                    const float middleLow   = (ranges.min/2.0f + middleValue/2.0f)/2.0f + middleValue/2.0f;
+                    const float middleHigh  = (ranges.max/2.0f + middleValue/2.0f)/2.0f + middleValue/2.0f;
+
+                    /**/ if (defValue < middleLow)
+                        portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_LOW;
+                    else if (defValue > middleHigh)
+                        portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_HIGH;
+                    else
+                        portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MIDDLE;
+                }
+            }
+
+            {
+                if (hints & kParameterIsBoolean)
+                {
+                    portRangeHints[port].HintDescriptor |= LADSPA_HINT_TOGGLED;
+                }
+                else
+                {
+                    if (hints & kParameterIsInteger)
+                        portRangeHints[port].HintDescriptor |= LADSPA_HINT_INTEGER;
+                    if (hints & kParameterIsLogarithmic)
+                        portRangeHints[port].HintDescriptor |= LADSPA_HINT_LOGARITHMIC;
+                }
+            }
+        }
+
+        // Set data
+        sLadspaDescriptor.UniqueID  = plugin.getUniqueId();
+        sLadspaDescriptor.Label     = strdup(plugin.getLabel());
+        sLadspaDescriptor.Name      = strdup(plugin.getName());
+        sLadspaDescriptor.Maker     = strdup(plugin.getMaker());
+        sLadspaDescriptor.Copyright = strdup(plugin.getLicense());
+        sLadspaDescriptor.PortCount = portCount;
+        sLadspaDescriptor.PortNames = portNames;
+        sLadspaDescriptor.PortDescriptors = portDescriptors;
+        sLadspaDescriptor.PortRangeHints  = portRangeHints;
+    }
+
+    ~DescriptorInitializer()
+    {
+        if (sLadspaDescriptor.Label != nullptr)
+        {
+            std::free((void*)sLadspaDescriptor.Label);
+            sLadspaDescriptor.Label = nullptr;
+        }
+
+        if (sLadspaDescriptor.Name != nullptr)
+        {
+            std::free((void*)sLadspaDescriptor.Name);
+            sLadspaDescriptor.Name = nullptr;
+        }
+
+        if (sLadspaDescriptor.Maker != nullptr)
+        {
+            std::free((void*)sLadspaDescriptor.Maker);
+            sLadspaDescriptor.Maker = nullptr;
+        }
+
+        if (sLadspaDescriptor.Copyright != nullptr)
+        {
+            std::free((void*)sLadspaDescriptor.Copyright);
+            sLadspaDescriptor.Copyright = nullptr;
+        }
+
+        if (sLadspaDescriptor.PortDescriptors != nullptr)
+        {
+            delete[] sLadspaDescriptor.PortDescriptors;
+            sLadspaDescriptor.PortDescriptors = nullptr;
+        }
+
+        if (sLadspaDescriptor.PortRangeHints != nullptr)
+        {
+            delete[] sLadspaDescriptor.PortRangeHints;
+            sLadspaDescriptor.PortRangeHints = nullptr;
+        }
+
+        if (sLadspaDescriptor.PortNames != nullptr)
+        {
+            for (ulong i=0; i < sLadspaDescriptor.PortCount; ++i)
+            {
+                if (sLadspaDescriptor.PortNames[i] != nullptr)
+                    std::free((void*)sLadspaDescriptor.PortNames[i]);
+            }
+
+            delete[] sLadspaDescriptor.PortNames;
+            sLadspaDescriptor.PortNames = nullptr;
+        }
+    }
+} sDescInit;
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+DISTRHO_PLUGIN_EXPORT
+const LADSPA_Descriptor* ladspa_descriptor(ulong index)
+{
+    USE_NAMESPACE_DISTRHO
+    return (index == 0) ? &sLadspaDescriptor : nullptr;
+}
+
+#ifdef DISTRHO_PLUGIN_TARGET_DSSI
+DISTRHO_PLUGIN_EXPORT
+const DSSI_Descriptor* dssi_descriptor(ulong index)
+{
+    USE_NAMESPACE_DISTRHO
+    return (index == 0) ? &sDssiDescriptor : nullptr;
+}
+#endif
+
+// -----------------------------------------------------------------------