commit b29e345b8c94114f80ac3567e4bef11821189467
parent 7a8bb95434ab0f5e00bd631f8840f719c016ce3a
Author: falkTX <falktx@falktx.com>
Date: Mon, 27 Mar 2023 14:04:49 +0200
Move common code to DistrhoDetails.hpp; add constexpr attributes
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
13 files changed, 1178 insertions(+), 992 deletions(-)
diff --git a/distrho/DistrhoDetails.hpp b/distrho/DistrhoDetails.hpp
@@ -0,0 +1,1097 @@
+/*
+ * 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.
+ */
+
+#ifndef DISTRHO_DETAILS_HPP_INCLUDED
+#define DISTRHO_DETAILS_HPP_INCLUDED
+
+#include "extra/String.hpp"
+
+START_NAMESPACE_DISTRHO
+
+/* --------------------------------------------------------------------------------------------------------------------
+ * Audio Port Hints */
+
+/**
+ @defgroup AudioPortHints Audio Port Hints
+
+ Various audio port hints.
+ @see AudioPort::hints
+ @{
+ */
+
+/**
+ Audio port can be used as control voltage (LV2 and JACK standalone only).
+ */
+static constexpr const uint32_t kAudioPortIsCV = 0x1;
+
+/**
+ Audio port should be used as sidechan (LV2 and VST3 only).
+ This hint should not be used with CV style ports.
+ @note non-sidechain audio ports must exist in the plugin if this flag is set.
+ */
+static constexpr const uint32_t kAudioPortIsSidechain = 0x2;
+
+/**
+ CV port has bipolar range (-1 to +1, or -5 to +5 if scaled).
+ This is merely a hint to tell the host what value range to expect.
+ */
+static constexpr const uint32_t kCVPortHasBipolarRange = 0x10;
+
+/**
+ CV port has negative unipolar range (-1 to 0, or -10 to 0 if scaled).
+ This is merely a hint to tell the host what value range to expect.
+ */
+static constexpr const uint32_t kCVPortHasNegativeUnipolarRange = 0x20;
+
+/**
+ CV port has positive unipolar range (0 to +1, or 0 to +10 if scaled).
+ This is merely a hint to tell the host what value range to expect.
+ */
+static constexpr const uint32_t kCVPortHasPositiveUnipolarRange = 0x40;
+
+/**
+ CV port has scaled range to match real values (-5 to +5v bipolar, +/-10 to 0v unipolar).
+ One other range flag is required if this flag is set.
+
+ When enabled, this makes the port a mod:CVPort, compatible with the MOD Devices platform.
+ */
+static constexpr const uint32_t kCVPortHasScaledRange = 0x80;
+
+/**
+ CV port is optional, allowing hosts that do no CV ports to load the plugin.
+ When loaded in hosts that don't support CV, the float* buffer for this port will be null.
+ */
+static constexpr const uint32_t kCVPortIsOptional = 0x100;
+
+/** @} */
+
+/* --------------------------------------------------------------------------------------------------------------------
+ * Parameter Hints */
+
+/**
+ @defgroup ParameterHints Parameter Hints
+
+ Various parameter hints.
+ @see Parameter::hints
+ @{
+ */
+
+/**
+ Parameter is automatable (real-time safe).
+ @see Plugin::setParameterValue(uint32_t, float)
+ */
+static constexpr const uint32_t kParameterIsAutomatable = 0x01;
+
+/** It was a typo, sorry.. */
+DISTRHO_DEPRECATED_BY("kParameterIsAutomatable")
+static constexpr const uint32_t kParameterIsAutomable = kParameterIsAutomatable;
+
+/**
+ Parameter value is boolean.@n
+ It's always at either minimum or maximum value.
+ */
+static constexpr const uint32_t kParameterIsBoolean = 0x02;
+
+/**
+ Parameter value is integer.
+ */
+static constexpr const uint32_t kParameterIsInteger = 0x04;
+
+/**
+ Parameter value is logarithmic.
+ */
+static constexpr const uint32_t kParameterIsLogarithmic = 0x08;
+
+/**
+ Parameter is of output type.@n
+ When unset, parameter is assumed to be of input type.
+
+ Parameter inputs are changed by the host and typically should not be changed by the plugin.@n
+ One exception is when changing programs, see Plugin::loadProgram().@n
+ The other exception is with parameter change requests, see Plugin::requestParameterValueChange().@n
+ Outputs are changed by the plugin and never modified by the host.
+
+ If you are targetting VST2, make sure to order your parameters so that all inputs are before any outputs.
+ */
+static constexpr const uint32_t kParameterIsOutput = 0x10;
+
+/**
+ Parameter value is a trigger.@n
+ This means the value resets back to its default after each process/run call.@n
+ Cannot be used for output parameters.
+
+ @note Only officially supported under LV2. For other formats DPF simulates the behaviour.
+*/
+static constexpr const uint32_t kParameterIsTrigger = 0x20 | kParameterIsBoolean;
+
+/**
+ Parameter should be hidden from the host and user-visible GUIs.@n
+ It is still saved and handled as any regular parameter, just not visible to the user
+ (for example in a host generated GUI)
+ */
+static constexpr const uint32_t kParameterIsHidden = 0x40;
+
+/** @} */
+
+/* --------------------------------------------------------------------------------------------------------------------
+ * State Hints */
+
+/**
+ @defgroup StateHints State Hints
+
+ Various state hints.
+ @see State::hints
+ @{
+ */
+
+/**
+ State is visible and readable by hosts that support string-type plugin parameters.
+ */
+static constexpr const uint32_t kStateIsHostReadable = 0x01;
+
+/**
+ State is writable by the host, allowing users to arbitrarily change the state.@n
+ For obvious reasons a writable state is also readable by the host.
+ */
+static constexpr const uint32_t kStateIsHostWritable = 0x02 | kStateIsHostReadable;
+
+/**
+ State is a filename path instead of a regular string.@n
+ The readable and writable hints are required for filenames to work, and thus are automatically set.
+ */
+static constexpr const uint32_t kStateIsFilenamePath = 0x04 | kStateIsHostWritable;
+
+/**
+ State is a base64 encoded string.
+ */
+static constexpr const uint32_t kStateIsBase64Blob = 0x08;
+
+/**
+ State is for Plugin/DSP side only, meaning there is never a need to notify the UI when it changes.
+ */
+static constexpr const uint32_t kStateIsOnlyForDSP = 0x10;
+
+/**
+ State is for UI side only.@n
+ If the DSP and UI are separate and the UI is not available, this property won't be saved.
+ */
+static constexpr const uint32_t kStateIsOnlyForUI = 0x20;
+
+/** @} */
+
+/* --------------------------------------------------------------------------------------------------------------------
+ * Base Plugin structs */
+
+/**
+ @defgroup BasePluginStructs Base Plugin Structs
+ @{
+ */
+
+/**
+ Parameter designation.@n
+ Allows a parameter to be specially designated for a task, like bypass.
+
+ Each designation is unique, there must be only one parameter that uses it.@n
+ The use of designated parameters is completely optional.
+
+ @note Designated parameters have strict ranges.
+ @see ParameterRanges::adjustForDesignation()
+ */
+enum ParameterDesignation {
+ /**
+ Null or unset designation.
+ */
+ kParameterDesignationNull = 0,
+
+ /**
+ Bypass designation.@n
+ When on (> 0.5f), it means the plugin must run in a bypassed state.
+ */
+ kParameterDesignationBypass = 1
+};
+
+/**
+ Predefined Port Groups Ids.
+
+ This enumeration provides a few commonly used groups for convenient use in plugins.
+ For preventing conflicts with user code, negative values are used here.
+ When rolling your own port groups, you MUST start their group ids from 0 and they MUST be sequential.
+
+ @see PortGroup
+ */
+enum PredefinedPortGroupsIds {
+ /**
+ Null or unset port group.
+ */
+ kPortGroupNone = (uint32_t)-1,
+
+ /**
+ A single channel audio group.
+ */
+ kPortGroupMono = (uint32_t)-2,
+
+ /**
+ A 2-channel discrete stereo audio group,
+ where the 1st audio port is the left channel and the 2nd port is the right channel.
+ */
+ kPortGroupStereo = (uint32_t)-3
+};
+
+/**
+ Audio Port.
+
+ Can be used as CV port by specifying kAudioPortIsCV in hints,@n
+ but this is only supported in LV2 and JACK standalone formats.
+ */
+struct AudioPort {
+ /**
+ Hints describing this audio port.
+ @see AudioPortHints
+ */
+ uint32_t hints;
+
+ /**
+ The name of this audio port.@n
+ An audio port name can contain any character, but hosts might have a hard time with non-ascii ones.@n
+ The name doesn't have to be unique within a plugin instance, but it's recommended.
+ */
+ String name;
+
+ /**
+ The symbol of this audio port.@n
+ An audio port symbol is a short restricted name used as a machine and human readable identifier.@n
+ The first character must be one of _, a-z or A-Z and subsequent characters can be from _, a-z, A-Z and 0-9.
+ @note Audio port and parameter symbols MUST be unique within a plugin instance.
+ */
+ String symbol;
+
+ /**
+ The group id that this audio/cv port belongs to.
+ No group is assigned by default.
+
+ You can use a group from PredefinedPortGroups or roll your own.@n
+ When rolling your own port groups, you MUST start their group ids from 0 and they MUST be sequential.
+ @see PortGroup, Plugin::initPortGroup
+ */
+ uint32_t groupId;
+
+ /**
+ Default constructor for a regular audio port.
+ */
+ AudioPort() noexcept
+ : hints(0x0),
+ name(),
+ symbol(),
+ groupId(kPortGroupNone) {}
+};
+
+/**
+ Parameter ranges.@n
+ This is used to set the default, minimum and maximum values of a parameter.
+
+ By default a parameter has 0.0 as minimum, 1.0 as maximum and 0.0 as default.@n
+ When changing this struct values you must ensure maximum > minimum and default is within range.
+ */
+struct ParameterRanges {
+ /**
+ Default value.
+ */
+ float def;
+
+ /**
+ Minimum value.
+ */
+ float min;
+
+ /**
+ Maximum value.
+ */
+ float max;
+
+ /**
+ Default constructor, using 0.0 as default, 0.0 as minimum, 1.0 as maximum.
+ */
+ constexpr ParameterRanges() noexcept
+ : def(0.0f),
+ min(0.0f),
+ max(1.0f) {}
+
+ /**
+ Constructor using custom values.
+ */
+ constexpr ParameterRanges(float df, float mn, float mx) noexcept
+ : def(df),
+ min(mn),
+ max(mx) {}
+
+ /**
+ Fix the default value within range.
+ */
+ void fixDefault() noexcept
+ {
+ fixValue(def);
+ }
+
+ /**
+ Fix a value within range.
+ */
+ void fixValue(float& value) const noexcept
+ {
+ if (value < min)
+ value = min;
+ else if (value > max)
+ value = max;
+ }
+
+ /**
+ Get a fixed value within range.
+ */
+ float getFixedValue(const float& value) const noexcept
+ {
+ if (value <= min)
+ return min;
+ if (value >= max)
+ return max;
+ return value;
+ }
+
+ /**
+ Get a value normalized to 0.0<->1.0.
+ */
+ float getNormalizedValue(const float& value) const noexcept
+ {
+ const float normValue = (value - min) / (max - min);
+
+ if (normValue <= 0.0f)
+ return 0.0f;
+ if (normValue >= 1.0f)
+ return 1.0f;
+ return normValue;
+ }
+
+ /**
+ Get a value normalized to 0.0<->1.0.
+ Overloaded function using double precision values.
+ */
+ double getNormalizedValue(const double& value) const noexcept
+ {
+ const double normValue = (value - min) / (max - min);
+
+ if (normValue <= 0.0)
+ return 0.0;
+ if (normValue >= 1.0)
+ return 1.0;
+ return normValue;
+ }
+
+ /**
+ Get a value normalized to 0.0<->1.0, fixed within range.
+ */
+ float getFixedAndNormalizedValue(const float& value) const noexcept
+ {
+ if (value <= min)
+ return 0.0f;
+ if (value >= max)
+ return 1.0f;
+
+ const float normValue = (value - min) / (max - min);
+
+ if (normValue <= 0.0f)
+ return 0.0f;
+ if (normValue >= 1.0f)
+ return 1.0f;
+
+ return normValue;
+ }
+
+ /**
+ Get a value normalized to 0.0<->1.0, fixed within range.
+ Overloaded function using double precision values.
+ */
+ double getFixedAndNormalizedValue(const double& value) const noexcept
+ {
+ if (value <= min)
+ return 0.0;
+ if (value >= max)
+ return 1.0;
+
+ const double normValue = (value - min) / (max - min);
+
+ if (normValue <= 0.0)
+ return 0.0;
+ if (normValue >= 1.0)
+ return 1.0;
+
+ return normValue;
+ }
+
+ /**
+ Get a proper value previously normalized to 0.0<->1.0.
+ */
+ float getUnnormalizedValue(const float& value) const noexcept
+ {
+ if (value <= 0.0f)
+ return min;
+ if (value >= 1.0f)
+ return max;
+
+ return value * (max - min) + min;
+ }
+
+ /**
+ Get a proper value previously normalized to 0.0<->1.0.
+ Overloaded function using double precision values.
+ */
+ double getUnnormalizedValue(const double& value) const noexcept
+ {
+ if (value <= 0.0)
+ return min;
+ if (value >= 1.0)
+ return max;
+
+ return value * (max - min) + min;
+ }
+};
+
+/**
+ Parameter enumeration value.@n
+ A string representation of a plugin parameter value.@n
+ Used together can be used to give meaning to parameter values, working as an enumeration.
+ */
+struct ParameterEnumerationValue {
+ /**
+ Parameter value.
+ */
+ float value;
+
+ /**
+ String representation of this value.
+ */
+ String label;
+
+ /**
+ Default constructor, using 0.0 as value and empty label.
+ */
+ ParameterEnumerationValue() noexcept
+ : value(0.0f),
+ label() {}
+
+ /**
+ Constructor using custom values.
+ */
+ ParameterEnumerationValue(float v, const char* l) noexcept
+ : value(v),
+ label(l) {}
+
+#if __cplusplus >= 201703L
+ /**
+ Constructor using custom values, constexpr compatible variant.
+ */
+ ParameterEnumerationValue(float v, const std::string_view& l) noexcept
+ : value(v),
+ label(l) {}
+#endif
+};
+
+/**
+ Collection of parameter enumeration values.@n
+ Handy class to handle the lifetime and count of all enumeration values.
+ */
+struct ParameterEnumerationValues {
+ uint8_t count;
+ bool deleteLater;
+ const ParameterEnumerationValue* ptr;
+
+ constexpr ParameterEnumerationValues() noexcept
+ : count(0),
+ ptr(nullptr),
+ deleteLater(false) {}
+
+ constexpr ParameterEnumerationValues(uint32_t c, const ParameterEnumerationValue* v) noexcept
+ : count(c),
+ deleteLater(false),
+ ptr(v) {}
+
+ // constexpr
+ ~ParameterEnumerationValues() noexcept
+ {
+ if (deleteLater)
+ delete[] ptr;
+ }
+
+ const ParameterEnumerationValue& operator[](const uint8_t index) const noexcept
+ {
+ return ptr[index];
+ }
+
+ template<uint8_t numValues>
+ ParameterEnumerationValues& operator=(const ParameterEnumerationValue values[numValues]) noexcept
+ {
+ if (deleteLater)
+ delete[] ptr;
+
+ count = numValues;
+ ptr = values;
+ deleteLater = true;
+ return *this;
+ }
+
+ ParameterEnumerationValues& operator=(const ParameterEnumerationValues& other) noexcept
+ {
+ if (deleteLater)
+ delete[] ptr;
+
+ count = 0;
+ ptr = nullptr;
+ deleteLater = false;
+
+ if (other.ptr != nullptr && other.count != 0)
+ {
+ ParameterEnumerationValue* ptr2;
+
+ try {
+ ptr2 = new ParameterEnumerationValue[other.count];
+ } DISTRHO_SAFE_EXCEPTION_RETURN("ParameterEnumerationValues::recreate", *this);
+
+ for (uint8_t i=0; i<other.count; ++i)
+ {
+ ptr2[i].value = other.ptr[i].value;
+ ptr2[i].label = other.ptr[i].label;
+ }
+
+ count = other.count;
+ ptr = ptr2;
+ deleteLater = true;
+ }
+
+ return *this;
+ }
+
+private:
+ #ifdef DISTRHO_PROPER_CPP11_SUPPORT
+ ParameterEnumerationValues(const ParameterEnumerationValues&) = delete;
+ #else
+ ParameterEnumerationValues(const ParameterEnumerationValues&);
+ #endif
+};
+
+/**
+ Details around parameter enumeration values.@n
+ Wraps ParameterEnumerationValues and provides a few extra details to the host about these values.
+ */
+struct ParameterEnumerationDetails {
+ /**
+ Number of elements allocated in @values.
+ */
+ uint8_t count;
+
+ /**
+ Wherever the host is to be restricted to only use enumeration values.
+
+ @note This mode is only a hint! Not all hosts and plugin formats support this mode.
+ */
+ bool restrictedMode;
+
+ /**
+ Array of @ParameterEnumerationValue items.@n
+ This pointer must be null or have been allocated on the heap with `new ParameterEnumerationValue[count]`.
+ */
+ ParameterEnumerationValues values;
+
+ /**
+ Default constructor, for zero enumeration values.
+ */
+ constexpr ParameterEnumerationDetails() noexcept
+ : count(0),
+ restrictedMode(false),
+ values() {}
+
+ /**
+ Constructor using custom values.@n
+ The pointer to @values must have been allocated on the heap with `new`.
+ */
+ constexpr ParameterEnumerationDetails(uint32_t c, bool r, const ParameterEnumerationValue* v) noexcept
+ : count(c),
+ restrictedMode(r),
+ values(c, v) {}
+};
+
+/**
+ Parameter.
+ */
+struct Parameter {
+ /**
+ Hints describing this parameter.
+ @see ParameterHints
+ */
+ uint32_t hints;
+
+ /**
+ The name of this parameter.@n
+ A parameter name can contain any character, but hosts might have a hard time with non-ascii ones.@n
+ The name doesn't have to be unique within a plugin instance, but it's recommended.
+ */
+ String name;
+
+ /**
+ The short name of this parameter.@n
+ Used when displaying the parameter name in a very limited space.
+ @note This value is optional, the full name is used when the short one is missing.
+ */
+ String shortName;
+
+ /**
+ The symbol of this parameter.@n
+ A parameter symbol is a short restricted name used as a machine and human readable identifier.@n
+ The first character must be one of _, a-z or A-Z and subsequent characters can be from _, a-z, A-Z and 0-9.
+ @note Parameter symbols MUST be unique within a plugin instance.
+ */
+ String symbol;
+
+ /**
+ The unit of this parameter.@n
+ This means something like "dB", "kHz" and "ms".@n
+ Can be left blank if a unit does not apply to this parameter.
+ */
+ String unit;
+
+ /**
+ An extensive description/comment about the parameter.
+ @note This value is optional and only used for LV2.
+ */
+ String description;
+
+ /**
+ Ranges of this parameter.@n
+ The ranges describe the default, minimum and maximum values.
+ */
+ ParameterRanges ranges;
+
+ /**
+ Enumeration details.@n
+ Can be used to give meaning to parameter values, working as an enumeration.
+ @todo rename to enumDetails
+ */
+ ParameterEnumerationDetails enumValues;
+
+ /**
+ Designation for this parameter.
+ */
+ ParameterDesignation designation;
+
+ /**
+ MIDI CC to use by default on this parameter.@n
+ A value of 0 or 32 (bank change) is considered invalid.@n
+ Must also be less or equal to 120.
+ @note This value is only a hint! Hosts might map it automatically or completely ignore it.
+ */
+ uint8_t midiCC;
+
+ /**
+ The group id that this parameter belongs to.
+ No group is assigned by default.
+
+ You can use a group from PredefinedPortGroups or roll your own.@n
+ When rolling your own port groups, you MUST start their group ids from 0 and they MUST be sequential.
+ @see PortGroup, Plugin::initPortGroup
+ */
+ uint32_t groupId;
+
+ /**
+ Default constructor for a null parameter.
+ */
+ Parameter() noexcept
+ : hints(0x0),
+ name(),
+ shortName(),
+ symbol(),
+ unit(),
+ ranges(),
+ enumValues(),
+ designation(kParameterDesignationNull),
+ midiCC(0),
+ groupId(kPortGroupNone) {}
+
+ /**
+ Constructor using custom values.
+ */
+ Parameter(uint32_t h, const char* n, const char* s, const char* u, float def, float min, float max) noexcept
+ : hints(h),
+ name(n),
+ shortName(),
+ symbol(s),
+ unit(u),
+ ranges(def, min, max),
+ enumValues(),
+ designation(kParameterDesignationNull),
+ midiCC(0),
+ groupId(kPortGroupNone) {}
+
+#ifdef DISTRHO_PROPER_CPP11_SUPPORT
+ /**
+ Constructor using custom values and enumeration.
+ Assumes enumeration details should have `restrictedMode` on.
+ */
+ Parameter(uint32_t h, const char* n, const char* s, const char* u, float def, float min, float max,
+ uint8_t evcount, const ParameterEnumerationValue ev[]) noexcept
+ : hints(h),
+ name(n),
+ shortName(),
+ symbol(s),
+ unit(u),
+ ranges(def, min, max),
+ enumValues{ evcount, true, ev },
+ designation(kParameterDesignationNull),
+ midiCC(0),
+ groupId(kPortGroupNone) {}
+#endif
+
+#if __cplusplus >= 201703L
+ /**
+ Constructor for constexpr compatible data.
+ */
+ constexpr Parameter(uint32_t h,
+ const std::string_view& n,
+ const std::string_view& sn,
+ const std::string_view& sym,
+ const std::string_view& u,
+ const std::string_view& desc) noexcept
+ : hints(h),
+ name(n),
+ shortName(sn),
+ symbol(sym),
+ unit(u),
+ description(desc),
+ ranges(),
+ enumValues(),
+ designation(kParameterDesignationNull),
+ midiCC(0),
+ groupId(kPortGroupNone) {}
+#endif
+
+ /**
+ Initialize a parameter for a specific designation.
+ */
+ void initDesignation(ParameterDesignation d) noexcept
+ {
+ designation = d;
+
+ switch (d)
+ {
+ case kParameterDesignationNull:
+ break;
+ case kParameterDesignationBypass:
+ hints = kParameterIsAutomatable|kParameterIsBoolean|kParameterIsInteger;
+ name = "Bypass";
+ shortName = "Bypass";
+ symbol = "dpf_bypass";
+ unit = "";
+ midiCC = 0;
+ groupId = kPortGroupNone;
+ ranges.def = 0.0f;
+ ranges.min = 0.0f;
+ ranges.max = 1.0f;
+ break;
+ }
+ }
+};
+
+#if __cplusplus >= 202001L /* TODO */
+/**
+ Bypass parameter definition in constexpr form.
+ */
+static constexpr const Parameter kParameterBypass = {
+ kParameterIsAutomatable|kParameterIsBoolean|kParameterIsInteger,
+ "Bypass", "Bypass", "dpf_bypass", "", "", {}, {}, 0, kPortGroupNone,
+};
+#endif
+
+/**
+ Port Group.@n
+ Allows to group together audio/cv ports or parameters.
+
+ Each unique group MUST have an unique symbol and a name.
+ A group can be applied to both inputs and outputs (at the same time).
+ The same group cannot be used in audio ports and parameters.
+
+ When both audio and parameter groups are used, audio groups MUST be defined first.
+ That is, group indexes start with audio ports, then parameters.
+
+ An audio port group logically combines ports which should be considered part of the same stream.@n
+ For example, two audio ports in a group may form a stereo stream.
+
+ A parameter group provides meta-data to the host to indicate that some parameters belong together.
+
+ The use of port groups is completely optional.
+
+ @see Plugin::initPortGroup, AudioPort::group, Parameter::group
+ */
+struct PortGroup {
+ /**
+ The name of this port group.@n
+ A port group name can contain any character, but hosts might have a hard time with non-ascii ones.@n
+ The name doesn't have to be unique within a plugin instance, but it's recommended.
+ */
+ String name;
+
+ /**
+ The symbol of this port group.@n
+ A port group symbol is a short restricted name used as a machine and human readable identifier.@n
+ The first character must be one of _, a-z or A-Z and subsequent characters can be from _, a-z, A-Z and 0-9.
+ @note Port group symbols MUST be unique within a plugin instance.
+ */
+ String symbol;
+};
+
+/**
+ State.
+
+ In DPF states refer to key:value string pairs, used to store arbitrary non-parameter data.@n
+ By default states are completely internal to the plugin and not visible by the host.@n
+ Flags can be set to allow hosts to see and/or change them.
+
+ TODO API under construction
+ */
+struct State {
+ /**
+ Hints describing this state.
+ @note Changing these hints can break compatibility with previously saved data.
+ @see StateHints
+ */
+ uint32_t hints;
+
+ /**
+ The key or "symbol" of this state.@n
+ A state key is a short restricted name used as a machine and human readable identifier.
+ @note State keys MUST be unique within a plugin instance.
+ TODO define rules for allowed characters, must be usable as URI non-encoded parameters
+ */
+ String key;
+
+ /**
+ The default value of this state.@n
+ Can be left empty if considered a valid initial state.
+ */
+ String defaultValue;
+
+ /**
+ String representation of this state.
+ */
+ String label;
+
+ /**
+ An extensive description/comment about this state.
+ @note This value is optional and only used for LV2.
+ */
+ String description;
+
+ #ifdef __MOD_DEVICES__
+ /**
+ The file types that a filename path state supports, written as a comma-separated string without whitespace.
+ Currently supported file types are:
+ - audioloop: Audio Loops, meant to be used for looper-style plugins
+ - audiorecording: Audio Recordings, triggered by plugins and stored in the unit
+ - audiosample: One-shot Audio Samples, meant to be used for sampler-style plugins
+ - audiotrack: Audio Tracks, meant to be used as full-performance/song or backtrack
+ - cabsim: Speaker Cabinets, meant as small IR audio files
+ - h2drumkit: Hydrogen Drumkits, must use h2drumkit file extension
+ - ir: Impulse Responses
+ - midiclip: MIDI Clips, to be used in sync with host tempo, must have mid or midi file extension
+ - midisong: MIDI Songs, meant to be used as full-performance/song or backtrack
+ - sf2: SF2 Instruments, must have sf2 or sf3 file extension
+ - sfz: SFZ Instruments, must have sfz file extension
+
+ @note This is a custom extension only valid in builds MOD Audio.
+ */
+ String fileTypes;
+ #endif
+
+ /**
+ Default constructor for a null state.
+ */
+ State() noexcept
+ : hints(0x0),
+ key(),
+ defaultValue(),
+ label(),
+ description() {}
+};
+
+/**
+ MIDI event.
+ */
+struct MidiEvent {
+ /**
+ Size of internal data.
+ */
+ static constexpr const uint32_t kDataSize = 4;
+
+ /**
+ Time offset in frames.
+ */
+ uint32_t frame;
+
+ /**
+ Number of bytes used.
+ */
+ uint32_t size;
+
+ /**
+ MIDI data.@n
+ If size > kDataSize, dataExt is used (otherwise null).
+
+ When dataExt is used, the event holder is responsible for
+ keeping the pointer valid during the entirety of the run function.
+ */
+ uint8_t data[kDataSize];
+ const uint8_t* dataExt;
+};
+
+/**
+ Time position.@n
+ The @a playing and @a frame values are always valid.@n
+ BBT values are only valid when @a bbt.valid is true.
+
+ This struct is inspired by the [JACK Transport API](https://jackaudio.org/api/structjack__position__t.html).
+ */
+struct TimePosition {
+ /**
+ Wherever the host transport is playing/rolling.
+ */
+ bool playing;
+
+ /**
+ Current host transport position in frames.
+ @note This value is not always monotonic,
+ with some plugin hosts assigning it based on a source that can accumulate rounding errors.
+ */
+ uint64_t frame;
+
+ /**
+ Bar-Beat-Tick time position.
+ */
+ struct BarBeatTick {
+ /**
+ Wherever the host transport is using BBT.@n
+ If false you must not read from this struct.
+ */
+ bool valid;
+
+ /**
+ Current bar.@n
+ Should always be > 0.@n
+ The first bar is bar '1'.
+ */
+ int32_t bar;
+
+ /**
+ Current beat within bar.@n
+ Should always be > 0 and <= @a beatsPerBar.@n
+ The first beat is beat '1'.
+ */
+ int32_t beat;
+
+ /**
+ Current tick within beat.@n
+ Should always be >= 0 and < @a ticksPerBeat.@n
+ The first tick is tick '0'.
+ @note Fraction part of tick is only available on some plugin formats.
+ */
+ double tick;
+
+ /**
+ Number of ticks that have elapsed between frame 0 and the first beat of the current measure.
+ */
+ double barStartTick;
+
+ /**
+ Time signature "numerator".
+ */
+ float beatsPerBar;
+
+ /**
+ Time signature "denominator".
+ */
+ float beatType;
+
+ /**
+ Number of ticks within a beat.@n
+ Usually a moderately large integer with many denominators, such as 1920.0.
+ */
+ double ticksPerBeat;
+
+ /**
+ Number of beats per minute.
+ */
+ double beatsPerMinute;
+
+ /**
+ Default constructor for a null BBT time position.
+ */
+ BarBeatTick() noexcept
+ : valid(false),
+ bar(0),
+ beat(0),
+ tick(0),
+ barStartTick(0.0),
+ beatsPerBar(0.0f),
+ beatType(0.0f),
+ ticksPerBeat(0.0),
+ beatsPerMinute(0.0) {}
+
+ /**
+ Reinitialize this position using the default null initialization.
+ */
+ void clear() noexcept
+ {
+ valid = false;
+ bar = 0;
+ beat = 0;
+ tick = 0;
+ barStartTick = 0.0;
+ beatsPerBar = 0.0f;
+ beatType = 0.0f;
+ ticksPerBeat = 0.0;
+ beatsPerMinute = 0.0;
+ }
+ } bbt;
+
+ /**
+ Default constructor for a time position.
+ */
+ TimePosition() noexcept
+ : playing(false),
+ frame(0),
+ bbt() {}
+
+ /**
+ Reinitialize this position using the default null initialization.
+ */
+ void clear() noexcept
+ {
+ playing = false;
+ frame = 0;
+ bbt.clear();
+ }
+};
+
+/** @} */
+
+// --------------------------------------------------------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+#endif // DISTRHO_DETAILS_HPP_INCLUDED
diff --git a/distrho/DistrhoPlugin.hpp b/distrho/DistrhoPlugin.hpp
@@ -17,952 +17,13 @@
#ifndef DISTRHO_PLUGIN_HPP_INCLUDED
#define DISTRHO_PLUGIN_HPP_INCLUDED
-#include "extra/String.hpp"
+#include "DistrhoDetails.hpp"
#include "extra/LeakDetector.hpp"
#include "src/DistrhoPluginChecks.h"
START_NAMESPACE_DISTRHO
/* ------------------------------------------------------------------------------------------------------------
- * Audio Port Hints */
-
-/**
- @defgroup AudioPortHints Audio Port Hints
-
- Various audio port hints.
- @see AudioPort::hints
- @{
- */
-
-/**
- Audio port can be used as control voltage (LV2 and JACK standalone only).
- */
-static const uint32_t kAudioPortIsCV = 0x1;
-
-/**
- Audio port should be used as sidechan (LV2 and VST3 only).
- This hint should not be used with CV style ports.
- @note non-sidechain audio ports must exist in the plugin if this flag is set.
- */
-static const uint32_t kAudioPortIsSidechain = 0x2;
-
-/**
- CV port has bipolar range (-1 to +1, or -5 to +5 if scaled).
- This is merely a hint to tell the host what value range to expect.
- */
-static const uint32_t kCVPortHasBipolarRange = 0x10;
-
-/**
- CV port has negative unipolar range (-1 to 0, or -10 to 0 if scaled).
- This is merely a hint to tell the host what value range to expect.
- */
-static const uint32_t kCVPortHasNegativeUnipolarRange = 0x20;
-
-/**
- CV port has positive unipolar range (0 to +1, or 0 to +10 if scaled).
- This is merely a hint to tell the host what value range to expect.
- */
-static const uint32_t kCVPortHasPositiveUnipolarRange = 0x40;
-
-/**
- CV port has scaled range to match real values (-5 to +5v bipolar, +/-10 to 0v unipolar).
- One other range flag is required if this flag is set.
-
- When enabled, this makes the port a mod:CVPort, compatible with the MOD Devices platform.
- */
-static const uint32_t kCVPortHasScaledRange = 0x80;
-
-/**
- CV port is optional, allowing hosts that do no CV ports to load the plugin.
- When loaded in hosts that don't support CV, the float* buffer for this port will be null.
- */
-static const uint32_t kCVPortIsOptional = 0x100;
-
-/** @} */
-
-/* ------------------------------------------------------------------------------------------------------------
- * Parameter Hints */
-
-/**
- @defgroup ParameterHints Parameter Hints
-
- Various parameter hints.
- @see Parameter::hints
- @{
- */
-
-/**
- Parameter is automatable (real-time safe).
- @see Plugin::setParameterValue(uint32_t, float)
- */
-static const uint32_t kParameterIsAutomatable = 0x01;
-
-/** It was a typo, sorry.. */
-DISTRHO_DEPRECATED_BY("kParameterIsAutomatable")
-static const uint32_t kParameterIsAutomable = kParameterIsAutomatable;
-
-/**
- Parameter value is boolean.@n
- It's always at either minimum or maximum value.
- */
-static const uint32_t kParameterIsBoolean = 0x02;
-
-/**
- Parameter value is integer.
- */
-static const uint32_t kParameterIsInteger = 0x04;
-
-/**
- Parameter value is logarithmic.
- */
-static const uint32_t kParameterIsLogarithmic = 0x08;
-
-/**
- Parameter is of output type.@n
- When unset, parameter is assumed to be of input type.
-
- Parameter inputs are changed by the host and typically should not be changed by the plugin.@n
- One exception is when changing programs, see Plugin::loadProgram().@n
- The other exception is with parameter change requests, see Plugin::requestParameterValueChange().@n
- Outputs are changed by the plugin and never modified by the host.
-
- If you are targetting VST2, make sure to order your parameters so that all inputs are before any outputs.
- */
-static const uint32_t kParameterIsOutput = 0x10;
-
-/**
- Parameter value is a trigger.@n
- This means the value resets back to its default after each process/run call.@n
- Cannot be used for output parameters.
-
- @note Only officially supported under LV2. For other formats DPF simulates the behaviour.
-*/
-static const uint32_t kParameterIsTrigger = 0x20 | kParameterIsBoolean;
-
-/**
- Parameter should be hidden from the host and user-visible GUIs.@n
- It is still saved and handled as any regular parameter, just not visible to the user
- (for example in a host generated GUI)
- */
-static const uint32_t kParameterIsHidden = 0x40;
-
-/** @} */
-
-/* ------------------------------------------------------------------------------------------------------------
- * State Hints */
-
-/**
- @defgroup StateHints State Hints
-
- Various state hints.
- @see State::hints
- @{
- */
-
-/**
- State is visible and readable by hosts that support string-type plugin parameters.
- */
-static const uint32_t kStateIsHostReadable = 0x01;
-
-/**
- State is writable by the host, allowing users to arbitrarily change the state.@n
- For obvious reasons a writable state is also readable by the host.
- */
-static const uint32_t kStateIsHostWritable = 0x02 | kStateIsHostReadable;
-
-/**
- State is a filename path instead of a regular string.@n
- The readable and writable hints are required for filenames to work, and thus are automatically set.
- */
-static const uint32_t kStateIsFilenamePath = 0x04 | kStateIsHostWritable;
-
-/**
- State is a base64 encoded string.
- */
-static const uint32_t kStateIsBase64Blob = 0x08;
-
-/**
- State is for Plugin/DSP side only, meaning there is never a need to notify the UI when it changes.
- */
-static const uint32_t kStateIsOnlyForDSP = 0x10;
-
-/**
- State is for UI side only.@n
- If the DSP and UI are separate and the UI is not available, this property won't be saved.
- */
-static const uint32_t kStateIsOnlyForUI = 0x20;
-
-/** @} */
-
-/* ------------------------------------------------------------------------------------------------------------
- * Base Plugin structs */
-
-/**
- @defgroup BasePluginStructs Base Plugin Structs
- @{
- */
-
-/**
- Parameter designation.@n
- Allows a parameter to be specially designated for a task, like bypass.
-
- Each designation is unique, there must be only one parameter that uses it.@n
- The use of designated parameters is completely optional.
-
- @note Designated parameters have strict ranges.
- @see ParameterRanges::adjustForDesignation()
- */
-enum ParameterDesignation {
- /**
- Null or unset designation.
- */
- kParameterDesignationNull = 0,
-
- /**
- Bypass designation.@n
- When on (> 0.5f), it means the plugin must run in a bypassed state.
- */
- kParameterDesignationBypass = 1
-};
-
-/**
- Predefined Port Groups Ids.
-
- This enumeration provides a few commonly used groups for convenient use in plugins.
- For preventing conflicts with user code, negative values are used here.
- When rolling your own port groups, you MUST start their group ids from 0 and they MUST be sequential.
-
- @see PortGroup
- */
-enum PredefinedPortGroupsIds {
- /**
- Null or unset port group.
- */
- kPortGroupNone = (uint32_t)-1,
-
- /**
- A single channel audio group.
- */
- kPortGroupMono = (uint32_t)-2,
-
- /**
- A 2-channel discrete stereo audio group,
- where the 1st audio port is the left channel and the 2nd port is the right channel.
- */
- kPortGroupStereo = (uint32_t)-3
-};
-
-/**
- Audio Port.
-
- Can be used as CV port by specifying kAudioPortIsCV in hints,@n
- but this is only supported in LV2 and JACK standalone formats.
- */
-struct AudioPort {
- /**
- Hints describing this audio port.
- @see AudioPortHints
- */
- uint32_t hints;
-
- /**
- The name of this audio port.@n
- An audio port name can contain any character, but hosts might have a hard time with non-ascii ones.@n
- The name doesn't have to be unique within a plugin instance, but it's recommended.
- */
- String name;
-
- /**
- The symbol of this audio port.@n
- An audio port symbol is a short restricted name used as a machine and human readable identifier.@n
- The first character must be one of _, a-z or A-Z and subsequent characters can be from _, a-z, A-Z and 0-9.
- @note Audio port and parameter symbols MUST be unique within a plugin instance.
- */
- String symbol;
-
- /**
- The group id that this audio/cv port belongs to.
- No group is assigned by default.
-
- You can use a group from PredefinedPortGroups or roll your own.@n
- When rolling your own port groups, you MUST start their group ids from 0 and they MUST be sequential.
- @see PortGroup, Plugin::initPortGroup
- */
- uint32_t groupId;
-
- /**
- Default constructor for a regular audio port.
- */
- AudioPort() noexcept
- : hints(0x0),
- name(),
- symbol(),
- groupId(kPortGroupNone) {}
-};
-
-/**
- Parameter ranges.@n
- This is used to set the default, minimum and maximum values of a parameter.
-
- By default a parameter has 0.0 as minimum, 1.0 as maximum and 0.0 as default.@n
- When changing this struct values you must ensure maximum > minimum and default is within range.
- */
-struct ParameterRanges {
- /**
- Default value.
- */
- float def;
-
- /**
- Minimum value.
- */
- float min;
-
- /**
- Maximum value.
- */
- float max;
-
- /**
- Default constructor, using 0.0 as default, 0.0 as minimum, 1.0 as maximum.
- */
- ParameterRanges() noexcept
- : def(0.0f),
- min(0.0f),
- max(1.0f) {}
-
- /**
- Constructor using custom values.
- */
- ParameterRanges(float df, float mn, float mx) noexcept
- : def(df),
- min(mn),
- max(mx) {}
-
- /**
- Fix the default value within range.
- */
- void fixDefault() noexcept
- {
- fixValue(def);
- }
-
- /**
- Fix a value within range.
- */
- void fixValue(float& value) const noexcept
- {
- if (value < min)
- value = min;
- else if (value > max)
- value = max;
- }
-
- /**
- Get a fixed value within range.
- */
- float getFixedValue(const float& value) const noexcept
- {
- if (value <= min)
- return min;
- if (value >= max)
- return max;
- return value;
- }
-
- /**
- Get a value normalized to 0.0<->1.0.
- */
- float getNormalizedValue(const float& value) const noexcept
- {
- const float normValue = (value - min) / (max - min);
-
- if (normValue <= 0.0f)
- return 0.0f;
- if (normValue >= 1.0f)
- return 1.0f;
- return normValue;
- }
-
- /**
- Get a value normalized to 0.0<->1.0.
- Overloaded function using double precision values.
- */
- double getNormalizedValue(const double& value) const noexcept
- {
- const double normValue = (value - min) / (max - min);
-
- if (normValue <= 0.0)
- return 0.0;
- if (normValue >= 1.0)
- return 1.0;
- return normValue;
- }
-
- /**
- Get a value normalized to 0.0<->1.0, fixed within range.
- */
- float getFixedAndNormalizedValue(const float& value) const noexcept
- {
- if (value <= min)
- return 0.0f;
- if (value >= max)
- return 1.0f;
-
- const float normValue = (value - min) / (max - min);
-
- if (normValue <= 0.0f)
- return 0.0f;
- if (normValue >= 1.0f)
- return 1.0f;
-
- return normValue;
- }
-
- /**
- Get a value normalized to 0.0<->1.0, fixed within range.
- Overloaded function using double precision values.
- */
- double getFixedAndNormalizedValue(const double& value) const noexcept
- {
- if (value <= min)
- return 0.0;
- if (value >= max)
- return 1.0;
-
- const double normValue = (value - min) / (max - min);
-
- if (normValue <= 0.0)
- return 0.0;
- if (normValue >= 1.0)
- return 1.0;
-
- return normValue;
- }
-
- /**
- Get a proper value previously normalized to 0.0<->1.0.
- */
- float getUnnormalizedValue(const float& value) const noexcept
- {
- if (value <= 0.0f)
- return min;
- if (value >= 1.0f)
- return max;
-
- return value * (max - min) + min;
- }
-
- /**
- Get a proper value previously normalized to 0.0<->1.0.
- Overloaded function using double precision values.
- */
- double getUnnormalizedValue(const double& value) const noexcept
- {
- if (value <= 0.0)
- return min;
- if (value >= 1.0)
- return max;
-
- return value * (max - min) + min;
- }
-};
-
-/**
- Parameter enumeration value.@n
- A string representation of a plugin parameter value.@n
- Used together can be used to give meaning to parameter values, working as an enumeration.
- */
-struct ParameterEnumerationValue {
- /**
- Parameter value.
- */
- float value;
-
- /**
- String representation of this value.
- */
- String label;
-
- /**
- Default constructor, using 0.0 as value and empty label.
- */
- ParameterEnumerationValue() noexcept
- : value(0.0f),
- label() {}
-
- /**
- Constructor using custom values.
- */
- ParameterEnumerationValue(float v, const char* l) noexcept
- : value(v),
- label(l) {}
-};
-
-/**
- Collection of parameter enumeration values.@n
- Handy class to handle the lifetime and count of all enumeration values.
- */
-struct ParameterEnumerationValues {
- /**
- Number of elements allocated in @values.
- */
- uint8_t count;
-
- /**
- Wherever the host is to be restricted to only use enumeration values.
-
- @note This mode is only a hint! Not all hosts and plugin formats support this mode.
- */
- bool restrictedMode;
-
- /**
- Array of @ParameterEnumerationValue items.@n
- This pointer must be null or have been allocated on the heap with `new ParameterEnumerationValue[count]`.
- */
- ParameterEnumerationValue* values;
-
- /**
- Default constructor, for zero enumeration values.
- */
- ParameterEnumerationValues() noexcept
- : count(0),
- restrictedMode(false),
- values() {}
-
- /**
- Constructor using custom values.@n
- The pointer to @values must have been allocated on the heap with `new`.
- */
- ParameterEnumerationValues(uint32_t c, bool r, ParameterEnumerationValue* v) noexcept
- : count(c),
- restrictedMode(r),
- values(v) {}
-
- ~ParameterEnumerationValues() noexcept
- {
- count = 0;
- restrictedMode = false;
-
- if (values != nullptr)
- {
- delete[] values;
- values = nullptr;
- }
- }
-
- DISTRHO_DECLARE_NON_COPYABLE(ParameterEnumerationValues)
-};
-
-/**
- Parameter.
- */
-struct Parameter {
- /**
- Hints describing this parameter.
- @see ParameterHints
- */
- uint32_t hints;
-
- /**
- The name of this parameter.@n
- A parameter name can contain any character, but hosts might have a hard time with non-ascii ones.@n
- The name doesn't have to be unique within a plugin instance, but it's recommended.
- */
- String name;
-
- /**
- The short name of this parameter.@n
- Used when displaying the parameter name in a very limited space.
- @note This value is optional, the full name is used when the short one is missing.
- */
- String shortName;
-
- /**
- The symbol of this parameter.@n
- A parameter symbol is a short restricted name used as a machine and human readable identifier.@n
- The first character must be one of _, a-z or A-Z and subsequent characters can be from _, a-z, A-Z and 0-9.
- @note Parameter symbols MUST be unique within a plugin instance.
- */
- String symbol;
-
- /**
- The unit of this parameter.@n
- This means something like "dB", "kHz" and "ms".@n
- Can be left blank if a unit does not apply to this parameter.
- */
- String unit;
-
- /**
- An extensive description/comment about the parameter.
- @note This value is optional and only used for LV2.
- */
- String description;
-
- /**
- Ranges of this parameter.@n
- The ranges describe the default, minimum and maximum values.
- */
- ParameterRanges ranges;
-
- /**
- Enumeration values.@n
- Can be used to give meaning to parameter values, working as an enumeration.
- */
- ParameterEnumerationValues enumValues;
-
- /**
- Designation for this parameter.
- */
- ParameterDesignation designation;
-
- /**
- MIDI CC to use by default on this parameter.@n
- A value of 0 or 32 (bank change) is considered invalid.@n
- Must also be less or equal to 120.
- @note This value is only a hint! Hosts might map it automatically or completely ignore it.
- */
- uint8_t midiCC;
-
- /**
- The group id that this parameter belongs to.
- No group is assigned by default.
-
- You can use a group from PredefinedPortGroups or roll your own.@n
- When rolling your own port groups, you MUST start their group ids from 0 and they MUST be sequential.
- @see PortGroup, Plugin::initPortGroup
- */
- uint32_t groupId;
-
- /**
- Default constructor for a null parameter.
- */
- Parameter() noexcept
- : hints(0x0),
- name(),
- shortName(),
- symbol(),
- unit(),
- ranges(),
- enumValues(),
- designation(kParameterDesignationNull),
- midiCC(0),
- groupId(kPortGroupNone) {}
-
- /**
- Constructor using custom values.
- */
- Parameter(uint32_t h, const char* n, const char* s, const char* u, float def, float min, float max) noexcept
- : hints(h),
- name(n),
- shortName(),
- symbol(s),
- unit(u),
- ranges(def, min, max),
- enumValues(),
- designation(kParameterDesignationNull),
- midiCC(0),
- groupId(kPortGroupNone) {}
-
- /**
- Initialize a parameter for a specific designation.
- */
- void initDesignation(ParameterDesignation d) noexcept
- {
- designation = d;
-
- switch (d)
- {
- case kParameterDesignationNull:
- break;
- case kParameterDesignationBypass:
- hints = kParameterIsAutomatable|kParameterIsBoolean|kParameterIsInteger;
- name = "Bypass";
- shortName = "Bypass";
- symbol = "dpf_bypass";
- unit = "";
- midiCC = 0;
- groupId = kPortGroupNone;
- ranges.def = 0.0f;
- ranges.min = 0.0f;
- ranges.max = 1.0f;
- break;
- }
- }
-};
-
-/**
- Port Group.@n
- Allows to group together audio/cv ports or parameters.
-
- Each unique group MUST have an unique symbol and a name.
- A group can be applied to both inputs and outputs (at the same time).
- The same group cannot be used in audio ports and parameters.
-
- When both audio and parameter groups are used, audio groups MUST be defined first.
- That is, group indexes start with audio ports, then parameters.
-
- An audio port group logically combines ports which should be considered part of the same stream.@n
- For example, two audio ports in a group may form a stereo stream.
-
- A parameter group provides meta-data to the host to indicate that some parameters belong together.
-
- The use of port groups is completely optional.
-
- @see Plugin::initPortGroup, AudioPort::group, Parameter::group
- */
-struct PortGroup {
- /**
- The name of this port group.@n
- A port group name can contain any character, but hosts might have a hard time with non-ascii ones.@n
- The name doesn't have to be unique within a plugin instance, but it's recommended.
- */
- String name;
-
- /**
- The symbol of this port group.@n
- A port group symbol is a short restricted name used as a machine and human readable identifier.@n
- The first character must be one of _, a-z or A-Z and subsequent characters can be from _, a-z, A-Z and 0-9.
- @note Port group symbols MUST be unique within a plugin instance.
- */
- String symbol;
-};
-
-/**
- State.
-
- In DPF states refer to key:value string pairs, used to store arbitrary non-parameter data.@n
- By default states are completely internal to the plugin and not visible by the host.@n
- Flags can be set to allow hosts to see and/or change them.
-
- TODO API under construction
- */
-struct State {
- /**
- Hints describing this state.
- @note Changing these hints can break compatibility with previously saved data.
- @see StateHints
- */
- uint32_t hints;
-
- /**
- The key or "symbol" of this state.@n
- A state key is a short restricted name used as a machine and human readable identifier.
- @note State keys MUST be unique within a plugin instance.
- TODO define rules for allowed characters, must be usable as URI non-encoded parameters
- */
- String key;
-
- /**
- The default value of this state.@n
- Can be left empty if considered a valid initial state.
- */
- String defaultValue;
-
- /**
- String representation of this state.
- */
- String label;
-
- /**
- An extensive description/comment about this state.
- @note This value is optional and only used for LV2.
- */
- String description;
-
- #ifdef __MOD_DEVICES__
- /**
- The file types that a filename path state supports, written as a comma-separated string without whitespace.
- Currently supported file types are:
- - audioloop: Audio Loops, meant to be used for looper-style plugins
- - audiorecording: Audio Recordings, triggered by plugins and stored in the unit
- - audiosample: One-shot Audio Samples, meant to be used for sampler-style plugins
- - audiotrack: Audio Tracks, meant to be used as full-performance/song or backtrack
- - cabsim: Speaker Cabinets, meant as small IR audio files
- - h2drumkit: Hydrogen Drumkits, must use h2drumkit file extension
- - ir: Impulse Responses
- - midiclip: MIDI Clips, to be used in sync with host tempo, must have mid or midi file extension
- - midisong: MIDI Songs, meant to be used as full-performance/song or backtrack
- - sf2: SF2 Instruments, must have sf2 or sf3 file extension
- - sfz: SFZ Instruments, must have sfz file extension
-
- @note This is a custom extension only valid in builds MOD Audio.
- */
- String fileTypes;
- #endif
-
- /**
- Default constructor for a null state.
- */
- State() noexcept
- : hints(0x0),
- key(),
- defaultValue(),
- label(),
- description() {}
-};
-
-/**
- MIDI event.
- */
-struct MidiEvent {
- /**
- Size of internal data.
- */
- static const uint32_t kDataSize = 4;
-
- /**
- Time offset in frames.
- */
- uint32_t frame;
-
- /**
- Number of bytes used.
- */
- uint32_t size;
-
- /**
- MIDI data.@n
- If size > kDataSize, dataExt is used (otherwise null).
-
- When dataExt is used, the event holder is responsible for
- keeping the pointer valid during the entirety of the run function.
- */
- uint8_t data[kDataSize];
- const uint8_t* dataExt;
-};
-
-/**
- Time position.@n
- The @a playing and @a frame values are always valid.@n
- BBT values are only valid when @a bbt.valid is true.
-
- This struct is inspired by the [JACK Transport API](https://jackaudio.org/api/structjack__position__t.html).
- */
-struct TimePosition {
- /**
- Wherever the host transport is playing/rolling.
- */
- bool playing;
-
- /**
- Current host transport position in frames.
- @note This value is not always monotonic,
- with some plugin hosts assigning it based on a source that can accumulate rounding errors.
- */
- uint64_t frame;
-
- /**
- Bar-Beat-Tick time position.
- */
- struct BarBeatTick {
- /**
- Wherever the host transport is using BBT.@n
- If false you must not read from this struct.
- */
- bool valid;
-
- /**
- Current bar.@n
- Should always be > 0.@n
- The first bar is bar '1'.
- */
- int32_t bar;
-
- /**
- Current beat within bar.@n
- Should always be > 0 and <= @a beatsPerBar.@n
- The first beat is beat '1'.
- */
- int32_t beat;
-
- /**
- Current tick within beat.@n
- Should always be >= 0 and < @a ticksPerBeat.@n
- The first tick is tick '0'.
- @note Fraction part of tick is only available on some plugin formats.
- */
- double tick;
-
- /**
- Number of ticks that have elapsed between frame 0 and the first beat of the current measure.
- */
- double barStartTick;
-
- /**
- Time signature "numerator".
- */
- float beatsPerBar;
-
- /**
- Time signature "denominator".
- */
- float beatType;
-
- /**
- Number of ticks within a beat.@n
- Usually a moderately large integer with many denominators, such as 1920.0.
- */
- double ticksPerBeat;
-
- /**
- Number of beats per minute.
- */
- double beatsPerMinute;
-
- /**
- Default constructor for a null BBT time position.
- */
- BarBeatTick() noexcept
- : valid(false),
- bar(0),
- beat(0),
- tick(0),
- barStartTick(0.0),
- beatsPerBar(0.0f),
- beatType(0.0f),
- ticksPerBeat(0.0),
- beatsPerMinute(0.0) {}
-
- /**
- Reinitialize this position using the default null initialization.
- */
- void clear() noexcept
- {
- valid = false;
- bar = 0;
- beat = 0;
- tick = 0;
- barStartTick = 0.0;
- beatsPerBar = 0.0f;
- beatType = 0.0f;
- ticksPerBeat = 0.0;
- beatsPerMinute = 0.0;
- }
- } bbt;
-
- /**
- Default constructor for a time position.
- */
- TimePosition() noexcept
- : playing(false),
- frame(0),
- bbt() {}
-
- /**
- Reinitialize this position using the default null initialization.
- */
- void clear() noexcept
- {
- playing = false;
- frame = 0;
- bbt.clear();
- }
-};
-
-/** @} */
-
-/* ------------------------------------------------------------------------------------------------------------
* DPF Plugin */
/**
@@ -991,7 +52,7 @@ struct TimePosition {
When enabled you need to implement initProgramName() and loadProgram().
DISTRHO_PLUGIN_WANT_STATE activates internal state features.@n
- When enabled you need to implement initStateKey() and setState().
+ When enabled you need to implement initState() and setState().
The process function run() changes wherever DISTRHO_PLUGIN_WANT_MIDI_INPUT is enabled or not.@n
When enabled it provides midi input events.
diff --git a/distrho/DistrhoUI.hpp b/distrho/DistrhoUI.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -17,6 +17,7 @@
#ifndef DISTRHO_UI_HPP_INCLUDED
#define DISTRHO_UI_HPP_INCLUDED
+#include "DistrhoDetails.hpp"
#include "extra/LeakDetector.hpp"
#include "src/DistrhoPluginChecks.h"
diff --git a/distrho/DistrhoUtils.hpp b/distrho/DistrhoUtils.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -58,7 +58,7 @@ inline float round(float __x)
#define DISTRHO_MACRO_AS_STRING_VALUE(MACRO) #MACRO
#define DISTRHO_MACRO_AS_STRING(MACRO) DISTRHO_MACRO_AS_STRING_VALUE(MACRO)
-/* ------------------------------------------------------------------------------------------------------------
+/* --------------------------------------------------------------------------------------------------------------------
* misc functions */
/**
@@ -94,7 +94,7 @@ void d_pass() noexcept {}
/** @} */
-/* ------------------------------------------------------------------------------------------------------------
+/* --------------------------------------------------------------------------------------------------------------------
* string print functions */
/**
@@ -240,7 +240,7 @@ void d_safe_exception(const char* const exception, const char* const file, const
/** @} */
-/* ------------------------------------------------------------------------------------------------------------
+/* --------------------------------------------------------------------------------------------------------------------
* math functions */
/**
@@ -254,7 +254,7 @@ void d_safe_exception(const char* const exception, const char* const file, const
Returns true if they match.
*/
template<typename T>
-static inline
+static inline constexpr
bool d_isEqual(const T& v1, const T& v2)
{
return std::abs(v1-v2) < std::numeric_limits<T>::epsilon();
@@ -265,7 +265,7 @@ bool d_isEqual(const T& v1, const T& v2)
Returns true if they don't match.
*/
template<typename T>
-static inline
+static inline constexpr
bool d_isNotEqual(const T& v1, const T& v2)
{
return std::abs(v1-v2) >= std::numeric_limits<T>::epsilon();
@@ -275,7 +275,7 @@ bool d_isNotEqual(const T& v1, const T& v2)
Safely check if a floating point number is zero.
*/
template<typename T>
-static inline
+static inline constexpr
bool d_isZero(const T& value)
{
return std::abs(value) < std::numeric_limits<T>::epsilon();
@@ -285,7 +285,7 @@ bool d_isZero(const T& value)
Safely check if a floating point number is not zero.
*/
template<typename T>
-static inline
+static inline constexpr
bool d_isNotZero(const T& value)
{
return std::abs(value) >= std::numeric_limits<T>::epsilon();
@@ -311,7 +311,8 @@ uint32_t d_nextPowerOf2(uint32_t size) noexcept
/** @} */
-// -----------------------------------------------------------------------
+/* --------------------------------------------------------------------------------------------------------------------
+ * math functions */
#ifndef DONT_SET_USING_DISTRHO_NAMESPACE
// If your code uses a lot of DISTRHO classes, then this will obviously save you
@@ -320,6 +321,4 @@ uint32_t d_nextPowerOf2(uint32_t size) noexcept
using namespace DISTRHO_NAMESPACE;
#endif
-// -----------------------------------------------------------------------
-
#endif // DISTRHO_UTILS_HPP_INCLUDED
diff --git a/distrho/extra/String.hpp b/distrho/extra/String.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -22,6 +22,10 @@
#include <algorithm>
+#if __cplusplus >= 201703L
+# include <string_view>
+#endif
+
START_NAMESPACE_DISTRHO
// -----------------------------------------------------------------------
@@ -87,6 +91,16 @@ public:
_dup(strBuf);
}
+ #if __cplusplus >= 201703L
+ /*
+ * constexpr compatible variant.
+ */
+ explicit constexpr String(const std::string_view& strView) noexcept
+ : fBuffer(const_cast<char*>(strView.data())),
+ fBufferLen(strView.size()),
+ fBufferAlloc(false) {}
+ #endif
+
/*
* Integer.
*/
diff --git a/distrho/src/DistrhoPlugin.cpp b/distrho/src/DistrhoPlugin.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -31,11 +31,12 @@ bool d_nextCanRequestParameterValueChanges = false;
/* ------------------------------------------------------------------------------------------------------------
* Static fallback data, see DistrhoPluginInternal.hpp */
-const String PluginExporter::sFallbackString;
-/* */ AudioPortWithBusId PluginExporter::sFallbackAudioPort;
-const ParameterRanges PluginExporter::sFallbackRanges;
-const ParameterEnumerationValues PluginExporter::sFallbackEnumValues;
-const PortGroupWithId PluginExporter::sFallbackPortGroup;
+const String PluginExporter::sFallbackString;
+/* */ AudioPortWithBusId PluginExporter::sFallbackAudioPort;
+const ParameterRanges PluginExporter::sFallbackRanges;
+const ParameterEnumerationDetails PluginExporter::sFallbackEnumDetails;
+const ParameterEnumerationValues PluginExporter::sFallbackEnumValues;
+const PortGroupWithId PluginExporter::sFallbackPortGroup;
/* ------------------------------------------------------------------------------------------------------------
* Plugin */
diff --git a/distrho/src/DistrhoPluginCLAP.cpp b/distrho/src/DistrhoPluginCLAP.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -1181,9 +1181,9 @@ public:
for (uint32_t i=0; i < enumValues.count; ++i)
{
- if (d_isEqual(static_cast<double>(enumValues.values[i].value), value))
+ if (d_isEqual(static_cast<double>(enumValues.ptr[i].value), value))
{
- d_strncpy(display, enumValues.values[i].label, size);
+ d_strncpy(display, enumValues.ptr[i].label, size);
return true;
}
}
@@ -1203,9 +1203,9 @@ public:
for (uint32_t i=0; i < enumValues.count; ++i)
{
- if (std::strcmp(display, enumValues.values[i].label) == 0)
+ if (std::strcmp(display, enumValues.ptr[i].label) == 0)
{
- *value = enumValues.values[i].value;
+ *value = enumValues.ptr[i].value;
return true;
}
}
diff --git a/distrho/src/DistrhoPluginChecks.h b/distrho/src/DistrhoPluginChecks.h
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -17,6 +17,10 @@
#ifndef DISTRHO_PLUGIN_CHECKS_H_INCLUDED
#define DISTRHO_PLUGIN_CHECKS_H_INCLUDED
+#ifndef DISTRHO_DETAILS_HPP_INCLUDED
+# error wrong include order
+#endif
+
#include "DistrhoPluginInfo.h"
// -----------------------------------------------------------------------
diff --git a/distrho/src/DistrhoPluginInternal.hpp b/distrho/src/DistrhoPluginInternal.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -704,11 +704,18 @@ public:
return fData->parameters[index].description;
}
+ const ParameterEnumerationDetails& getParameterEnumDetails(const uint32_t index) const noexcept
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackEnumDetails);
+
+ return fData->parameters[index].enumValues;
+ }
+
const ParameterEnumerationValues& getParameterEnumValues(const uint32_t index) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackEnumValues);
- return fData->parameters[index].enumValues;
+ return fData->parameters[index].enumValues.values;
}
const ParameterRanges& getParameterRanges(const uint32_t index) const noexcept
@@ -1045,11 +1052,12 @@ private:
// -------------------------------------------------------------------
// Static fallback data, see DistrhoPlugin.cpp
- static const String sFallbackString;
- static /* */ AudioPortWithBusId sFallbackAudioPort;
- static const ParameterRanges sFallbackRanges;
- static const ParameterEnumerationValues sFallbackEnumValues;
- static const PortGroupWithId sFallbackPortGroup;
+ static const String sFallbackString;
+ static /* */ AudioPortWithBusId sFallbackAudioPort;
+ static const ParameterRanges sFallbackRanges;
+ static const ParameterEnumerationDetails sFallbackEnumDetails;
+ static const ParameterEnumerationValues sFallbackEnumValues;
+ static const PortGroupWithId sFallbackPortGroup;
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter)
};
diff --git a/distrho/src/DistrhoPluginLV2export.cpp b/distrho/src/DistrhoPluginLV2export.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -820,16 +820,16 @@ void lv2_generate_ttl(const char* const basename)
}
// enumeration
- const ParameterEnumerationValues& enumValues(plugin.getParameterEnumValues(i));
+ const ParameterEnumerationDetails& enumDetails(plugin.getParameterEnumDetails(i));
- if (enumValues.count > 0)
+ if (enumDetails.count > 0)
{
- if (enumValues.count >= 2 && enumValues.restrictedMode)
+ if (enumDetails.count >= 2 && enumDetails.restrictedMode)
pluginString += " lv2:portProperty lv2:enumeration ;\n";
- for (uint8_t j=0; j < enumValues.count; ++j)
+ for (uint8_t j=0; j < enumDetails.count; ++j)
{
- const ParameterEnumerationValue& enumValue(enumValues.values[j]);
+ const ParameterEnumerationValue& enumValue(enumDetails.values[j]);
if (j == 0)
pluginString += " lv2:scalePoint [\n";
@@ -851,7 +851,7 @@ void lv2_generate_ttl(const char* const basename)
pluginString += " rdf:value " + String(enumValue.value) + " ;\n";
}
- if (j+1 == enumValues.count)
+ if (j+1 == enumDetails.count)
pluginString += " ] ;\n";
else
pluginString += " ] ,\n";
diff --git a/distrho/src/DistrhoPluginVST2.cpp b/distrho/src/DistrhoPluginVST2.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -527,10 +527,10 @@ public:
for (uint8_t i = 0; i < enumValues.count; ++i)
{
- if (d_isNotEqual(value, enumValues.values[i].value))
+ if (d_isNotEqual(value, enumValues.ptr[i].value))
continue;
- strncpy((char*)ptr, enumValues.values[i].label.buffer(), 24);
+ strncpy((char*)ptr, enumValues.ptr[i].label.buffer(), 24);
return 1;
}
diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -1711,7 +1711,7 @@ public:
// set up flags
int32_t flags = 0;
- const ParameterEnumerationValues& enumValues(fPlugin.getParameterEnumValues(index));
+ const ParameterEnumerationDetails& enumDetails(fPlugin.getParameterEnumDetails(index));
const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
const uint32_t hints = fPlugin.getParameterHints(index);
@@ -1737,10 +1737,10 @@ public:
else if (hints & kParameterIsInteger)
step_count = ranges.max - ranges.min;
- if (enumValues.count >= 2 && enumValues.restrictedMode)
+ if (enumDetails.count >= 2 && enumDetails.restrictedMode)
{
flags |= V3_PARAM_IS_LIST;
- step_count = enumValues.count - 1;
+ step_count = enumDetails.count - 1;
}
info->flags = flags;
@@ -1810,9 +1810,9 @@ public:
for (uint32_t i=0; i < enumValues.count; ++i)
{
- if (d_isEqual(enumValues.values[i].value, value))
+ if (d_isEqual(enumValues.ptr[i].value, value))
{
- strncpy_utf16(output, enumValues.values[i].label, 128);
+ strncpy_utf16(output, enumValues.ptr[i].label, 128);
return V3_OK;
}
}
@@ -1874,9 +1874,9 @@ public:
for (uint32_t i=0; i < enumValues.count; ++i)
{
- if (strcmp_utf16(input, enumValues.values[i].label))
+ if (strcmp_utf16(input, enumValues.ptr[i].label))
{
- *output = ranges.getNormalizedValue(enumValues.values[i].value);
+ *output = ranges.getNormalizedValue(enumValues.ptr[i].value);
return V3_OK;
}
}
diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ * 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
@@ -14,6 +14,7 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "DistrhoDetails.hpp"
#include "src/DistrhoPluginChecks.h"
#include "src/DistrhoDefines.h"