Mercurial > hg > pub > prymula > com
diff DPF-Prymula-audioplugins/dpf/distrho/src/DistrhoPluginInternal.hpp @ 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/DistrhoPluginInternal.hpp Mon Oct 16 21:53:34 2023 +0200 @@ -0,0 +1,1061 @@ +/* + * 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_PLUGIN_INTERNAL_HPP_INCLUDED +#define DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED + +#include "../DistrhoPlugin.hpp" + +#ifdef DISTRHO_PLUGIN_TARGET_VST3 +# include "DistrhoPluginVST.hpp" +#endif + +#include <set> + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------- +// Maxmimum values + +static const uint32_t kMaxMidiEvents = 512; + +// ----------------------------------------------------------------------- +// Static data, see DistrhoPlugin.cpp + +extern uint32_t d_nextBufferSize; +extern double d_nextSampleRate; +extern const char* d_nextBundlePath; +extern bool d_nextPluginIsDummy; +extern bool d_nextPluginIsSelfTest; +extern bool d_nextCanRequestParameterValueChanges; + +// ----------------------------------------------------------------------- +// DSP callbacks + +typedef bool (*writeMidiFunc) (void* ptr, const MidiEvent& midiEvent); +typedef bool (*requestParameterValueChangeFunc) (void* ptr, uint32_t index, float value); +typedef bool (*updateStateValueFunc) (void* ptr, const char* key, const char* value); + +// ----------------------------------------------------------------------- +// Helpers + +struct AudioPortWithBusId : AudioPort { + uint32_t busId; + + AudioPortWithBusId() + : AudioPort(), + busId(0) {} +}; + +struct PortGroupWithId : PortGroup { + uint32_t groupId; + + PortGroupWithId() + : PortGroup(), + groupId(kPortGroupNone) {} +}; + +static inline +void fillInPredefinedPortGroupData(const uint32_t groupId, PortGroup& portGroup) +{ + switch (groupId) + { + case kPortGroupNone: + portGroup.name.clear(); + portGroup.symbol.clear(); + break; + case kPortGroupMono: + portGroup.name = "Mono"; + portGroup.symbol = "dpf_mono"; + break; + case kPortGroupStereo: + portGroup.name = "Stereo"; + portGroup.symbol = "dpf_stereo"; + break; + } +} + +static inline +void d_strncpy(char* const dst, const char* const src, const size_t length) +{ + DISTRHO_SAFE_ASSERT_RETURN(length > 0,); + + if (const size_t len = std::min(std::strlen(src), length-1U)) + { + std::memcpy(dst, src, len); + dst[len] = '\0'; + } + else + { + dst[0] = '\0'; + } +} + +template<typename T> +static inline +void snprintf_t(char* const dst, const T value, const char* const format, const size_t size) +{ + DISTRHO_SAFE_ASSERT_RETURN(size > 0,); + std::snprintf(dst, size-1, format, value); + dst[size-1] = '\0'; +} + +static inline +void snprintf_f32(char* const dst, const float value, const size_t size) +{ + return snprintf_t<float>(dst, value, "%f", size); +} + +static inline +void snprintf_f32(char* const dst, const double value, const size_t size) +{ + return snprintf_t<double>(dst, value, "%f", size); +} + +static inline +void snprintf_i32(char* const dst, const int32_t value, const size_t size) +{ + return snprintf_t<int32_t>(dst, value, "%d", size); +} + +static inline +void snprintf_u32(char* const dst, const uint32_t value, const size_t size) +{ + return snprintf_t<uint32_t>(dst, value, "%u", size); +} + +// ----------------------------------------------------------------------- +// Plugin private data + +struct Plugin::PrivateData { + const bool canRequestParameterValueChanges; + const bool isDummy; + const bool isSelfTest; + bool isProcessing; + +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + AudioPortWithBusId* audioPorts; +#endif + + uint32_t parameterCount; + uint32_t parameterOffset; + Parameter* parameters; + + uint32_t portGroupCount; + PortGroupWithId* portGroups; + +#if DISTRHO_PLUGIN_WANT_PROGRAMS + uint32_t programCount; + String* programNames; +#endif + +#if DISTRHO_PLUGIN_WANT_STATE + uint32_t stateCount; + State* states; +#endif + +#if DISTRHO_PLUGIN_WANT_LATENCY + uint32_t latency; +#endif + +#if DISTRHO_PLUGIN_WANT_TIMEPOS + TimePosition timePosition; +#endif + + // Callbacks + void* callbacksPtr; + writeMidiFunc writeMidiCallbackFunc; + requestParameterValueChangeFunc requestParameterValueChangeCallbackFunc; + updateStateValueFunc updateStateValueCallbackFunc; + + uint32_t bufferSize; + double sampleRate; + char* bundlePath; + + PrivateData() noexcept + : canRequestParameterValueChanges(d_nextCanRequestParameterValueChanges), + isDummy(d_nextPluginIsDummy), + isSelfTest(d_nextPluginIsSelfTest), + isProcessing(false), +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + audioPorts(nullptr), +#endif + parameterCount(0), + parameterOffset(0), + parameters(nullptr), + portGroupCount(0), + portGroups(nullptr), +#if DISTRHO_PLUGIN_WANT_PROGRAMS + programCount(0), + programNames(nullptr), +#endif +#if DISTRHO_PLUGIN_WANT_STATE + stateCount(0), + states(nullptr), +#endif +#if DISTRHO_PLUGIN_WANT_LATENCY + latency(0), +#endif + callbacksPtr(nullptr), + writeMidiCallbackFunc(nullptr), + requestParameterValueChangeCallbackFunc(nullptr), + updateStateValueCallbackFunc(nullptr), + bufferSize(d_nextBufferSize), + sampleRate(d_nextSampleRate), + bundlePath(d_nextBundlePath != nullptr ? strdup(d_nextBundlePath) : nullptr) + { + DISTRHO_SAFE_ASSERT(bufferSize != 0); + DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate)); + +#if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2) + parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS; +# if DISTRHO_PLUGIN_WANT_LATENCY + parameterOffset += 1; +# endif +#endif + +#ifdef DISTRHO_PLUGIN_TARGET_LV2 +# if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_STATE || DISTRHO_PLUGIN_WANT_TIMEPOS) + parameterOffset += 1; +# endif +# if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) + parameterOffset += 1; +# endif +#endif + +#ifdef DISTRHO_PLUGIN_TARGET_VST3 + parameterOffset += kVst3InternalParameterCount; +#endif + } + + ~PrivateData() noexcept + { +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + if (audioPorts != nullptr) + { + delete[] audioPorts; + audioPorts = nullptr; + } +#endif + + if (parameters != nullptr) + { + delete[] parameters; + parameters = nullptr; + } + + if (portGroups != nullptr) + { + delete[] portGroups; + portGroups = nullptr; + } + +#if DISTRHO_PLUGIN_WANT_PROGRAMS + if (programNames != nullptr) + { + delete[] programNames; + programNames = nullptr; + } +#endif + +#if DISTRHO_PLUGIN_WANT_STATE + if (states != nullptr) + { + delete[] states; + states = nullptr; + } +#endif + + if (bundlePath != nullptr) + { + std::free(bundlePath); + bundlePath = nullptr; + } + } + +#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + bool writeMidiCallback(const MidiEvent& midiEvent) + { + if (writeMidiCallbackFunc != nullptr) + return writeMidiCallbackFunc(callbacksPtr, midiEvent); + + return false; + } +#endif + +#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST + bool requestParameterValueChangeCallback(const uint32_t index, const float value) + { + if (requestParameterValueChangeCallbackFunc != nullptr) + return requestParameterValueChangeCallbackFunc(callbacksPtr, index, value); + + return false; + } +#endif + +#if DISTRHO_PLUGIN_WANT_STATE + bool updateStateValueCallback(const char* const key, const char* const value) + { + d_stdout("updateStateValueCallback %p", updateStateValueCallbackFunc); + if (updateStateValueCallbackFunc != nullptr) + return updateStateValueCallbackFunc(callbacksPtr, key, value); + + return false; + } +#endif +}; + +// ----------------------------------------------------------------------- +// Plugin exporter class + +class PluginExporter +{ +public: + PluginExporter(void* const callbacksPtr, + const writeMidiFunc writeMidiCall, + const requestParameterValueChangeFunc requestParameterValueChangeCall, + const updateStateValueFunc updateStateValueCall) + : fPlugin(createPlugin()), + fData((fPlugin != nullptr) ? fPlugin->pData : nullptr), + fIsActive(false) + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); + +#if defined(DPF_RUNTIME_TESTING) && defined(__GNUC__) && !defined(__clang__) + /* Run-time testing build. + * Verify that virtual functions are overriden if parameters, programs or states are in use. + * This does not work on all compilers, but we use it purely as informational check anyway. */ + if (fData->parameterCount != 0) + { + if ((void*)(fPlugin->*(&Plugin::initParameter)) == (void*)&Plugin::initParameter) + { + d_stderr2("DPF warning: Plugins with parameters must implement `initParameter`"); + abort(); + } + if ((void*)(fPlugin->*(&Plugin::getParameterValue)) == (void*)&Plugin::getParameterValue) + { + d_stderr2("DPF warning: Plugins with parameters must implement `getParameterValue`"); + abort(); + } + if ((void*)(fPlugin->*(&Plugin::setParameterValue)) == (void*)&Plugin::setParameterValue) + { + d_stderr2("DPF warning: Plugins with parameters must implement `setParameterValue`"); + abort(); + } + } + +# if DISTRHO_PLUGIN_WANT_PROGRAMS + if (fData->programCount != 0) + { + if ((void*)(fPlugin->*(&Plugin::initProgramName)) == (void*)&Plugin::initProgramName) + { + d_stderr2("DPF warning: Plugins with programs must implement `initProgramName`"); + abort(); + } + if ((void*)(fPlugin->*(&Plugin::loadProgram)) == (void*)&Plugin::loadProgram) + { + d_stderr2("DPF warning: Plugins with programs must implement `loadProgram`"); + abort(); + } + } +# endif + +# if DISTRHO_PLUGIN_WANT_STATE + if (fData->stateCount != 0) + { + if ((void*)(fPlugin->*(static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState))) == + (void*)static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState)) + { + d_stderr2("DPF warning: Plugins with state must implement `initState`"); + abort(); + } + + if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState) + { + d_stderr2("DPF warning: Plugins with state must implement `setState`"); + abort(); + } + } +# endif + +# if DISTRHO_PLUGIN_WANT_FULL_STATE + if (fData->stateCount != 0) + { + if ((void*)(fPlugin->*(&Plugin::getState)) == (void*)&Plugin::getState) + { + d_stderr2("DPF warning: Plugins with full state must implement `getState`"); + abort(); + } + } + else + { + d_stderr2("DPF warning: Plugins with full state must have at least 1 state"); + abort(); + } +# endif +#endif + +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + { + uint32_t j=0; +# if DISTRHO_PLUGIN_NUM_INPUTS > 0 + for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j) + fPlugin->initAudioPort(true, i, fData->audioPorts[j]); +# endif +# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j) + fPlugin->initAudioPort(false, i, fData->audioPorts[j]); +# endif + } +#endif // DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + + for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) + fPlugin->initParameter(i, fData->parameters[i]); + + { + std::set<uint32_t> portGroupIndices; + +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) + portGroupIndices.insert(fData->audioPorts[i].groupId); +#endif + for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) + portGroupIndices.insert(fData->parameters[i].groupId); + + portGroupIndices.erase(kPortGroupNone); + + if (const uint32_t portGroupSize = static_cast<uint32_t>(portGroupIndices.size())) + { + fData->portGroups = new PortGroupWithId[portGroupSize]; + fData->portGroupCount = portGroupSize; + + uint32_t index = 0; + for (std::set<uint32_t>::iterator it = portGroupIndices.begin(); it != portGroupIndices.end(); ++it, ++index) + { + PortGroupWithId& portGroup(fData->portGroups[index]); + portGroup.groupId = *it; + + if (portGroup.groupId < portGroupSize) + fPlugin->initPortGroup(portGroup.groupId, portGroup); + else + fillInPredefinedPortGroupData(portGroup.groupId, portGroup); + } + } + } + +#if DISTRHO_PLUGIN_WANT_PROGRAMS + for (uint32_t i=0, count=fData->programCount; i < count; ++i) + fPlugin->initProgramName(i, fData->programNames[i]); +#endif + +#if DISTRHO_PLUGIN_WANT_STATE + for (uint32_t i=0, count=fData->stateCount; i < count; ++i) + fPlugin->initState(i, fData->states[i]); +#endif + + fData->callbacksPtr = callbacksPtr; + fData->writeMidiCallbackFunc = writeMidiCall; + fData->requestParameterValueChangeCallbackFunc = requestParameterValueChangeCall; + fData->updateStateValueCallbackFunc = updateStateValueCall; + } + + ~PluginExporter() + { + delete fPlugin; + } + + // ------------------------------------------------------------------- + + const char* getName() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, ""); + + return fPlugin->getName(); + } + + const char* getLabel() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, ""); + + return fPlugin->getLabel(); + } + + const char* getDescription() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, ""); + + return fPlugin->getDescription(); + } + + const char* getMaker() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, ""); + + return fPlugin->getMaker(); + } + + const char* getHomePage() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, ""); + + return fPlugin->getHomePage(); + } + + const char* getLicense() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, ""); + + return fPlugin->getLicense(); + } + + uint32_t getVersion() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0); + + return fPlugin->getVersion(); + } + + long getUniqueId() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0); + + return fPlugin->getUniqueId(); + } + + void* getInstancePointer() const noexcept + { + return fPlugin; + } + + // ------------------------------------------------------------------- + +#if DISTRHO_PLUGIN_WANT_LATENCY + uint32_t getLatency() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); + + return fData->latency; + } +#endif + +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + AudioPortWithBusId& getAudioPort(const bool input, const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort); + + if (input) + { +# if DISTRHO_PLUGIN_NUM_INPUTS > 0 + DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_INPUTS, sFallbackAudioPort); +# endif + } + else + { +# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_OUTPUTS, sFallbackAudioPort); +# endif + } + + return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)]; + } + + uint32_t getAudioPortHints(const bool input, const uint32_t index) const noexcept + { + return getAudioPort(input, index).hints; + } + + uint32_t getAudioPortCountWithGroupId(const bool input, const uint32_t groupId) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); + + uint32_t numPorts = 0; + + if (input) + { + #if DISTRHO_PLUGIN_NUM_INPUTS > 0 + for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i) + { + if (fData->audioPorts[i].groupId == groupId) + ++numPorts; + } + #endif + } + else + { + #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 + for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) + { + if (fData->audioPorts[i + DISTRHO_PLUGIN_NUM_INPUTS].groupId == groupId) + ++numPorts; + } + #endif + } + + return numPorts; + } +#endif + + uint32_t getParameterCount() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); + + return fData->parameterCount; + } + + uint32_t getParameterOffset() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); + + return fData->parameterOffset; + } + + uint32_t getParameterHints(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0x0); + + return fData->parameters[index].hints; + } + + ParameterDesignation getParameterDesignation(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kParameterDesignationNull); + + return fData->parameters[index].designation; + } + + bool isParameterInput(const uint32_t index) const noexcept + { + return (getParameterHints(index) & kParameterIsOutput) == 0x0; + } + + bool isParameterOutput(const uint32_t index) const noexcept + { + return (getParameterHints(index) & kParameterIsOutput) != 0x0; + } + + bool isParameterInteger(const uint32_t index) const noexcept + { + return (getParameterHints(index) & kParameterIsInteger) != 0x0; + } + + bool isParameterTrigger(const uint32_t index) const noexcept + { + return (getParameterHints(index) & kParameterIsTrigger) == kParameterIsTrigger; + } + + bool isParameterOutputOrTrigger(const uint32_t index) const noexcept + { + const uint32_t hints = getParameterHints(index); + + if (hints & kParameterIsOutput) + return true; + if ((hints & kParameterIsTrigger) == kParameterIsTrigger) + return true; + + return false; + } + + const String& getParameterName(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString); + + return fData->parameters[index].name; + } + + const String& getParameterShortName(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString); + + return fData->parameters[index].shortName; + } + + const String& getParameterSymbol(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString); + + return fData->parameters[index].symbol; + } + + const String& getParameterUnit(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString); + + return fData->parameters[index].unit; + } + + const String& getParameterDescription(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString); + + return fData->parameters[index].description; + } + + const ParameterEnumerationValues& getParameterEnumValues(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackEnumValues); + + return fData->parameters[index].enumValues; + } + + const ParameterRanges& getParameterRanges(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackRanges); + + return fData->parameters[index].ranges; + } + + uint8_t getParameterMidiCC(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0); + + return fData->parameters[index].midiCC; + } + + uint32_t getParameterGroupId(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kPortGroupNone); + + return fData->parameters[index].groupId; + } + + float getParameterDefault(const uint32_t index) const + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f); + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f); + + return fData->parameters[index].ranges.def; + } + + float getParameterValue(const uint32_t index) const + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f); + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f); + + return fPlugin->getParameterValue(index); + } + + void setParameterValue(const uint32_t index, const float value) + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount,); + + fPlugin->setParameterValue(index, value); + } + + uint32_t getPortGroupCount() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); + + return fData->portGroupCount; + } + + const PortGroupWithId& getPortGroupById(const uint32_t groupId) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && fData->portGroupCount != 0, sFallbackPortGroup); + + for (uint32_t i=0; i < fData->portGroupCount; ++i) + { + const PortGroupWithId& portGroup(fData->portGroups[i]); + + if (portGroup.groupId == groupId) + return portGroup; + } + + return sFallbackPortGroup; + } + + const PortGroupWithId& getPortGroupByIndex(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->portGroupCount, sFallbackPortGroup); + + return fData->portGroups[index]; + } + + const String& getPortGroupSymbolForId(const uint32_t groupId) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString); + + return getPortGroupById(groupId).symbol; + } + +#if DISTRHO_PLUGIN_WANT_PROGRAMS + uint32_t getProgramCount() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); + + return fData->programCount; + } + + const String& getProgramName(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount, sFallbackString); + + return fData->programNames[index]; + } + + void loadProgram(const uint32_t index) + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount,); + + fPlugin->loadProgram(index); + } +#endif + +#if DISTRHO_PLUGIN_WANT_STATE + uint32_t getStateCount() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); + + return fData->stateCount; + } + + uint32_t getStateHints(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, 0x0); + + return fData->states[index].hints; + } + + const String& getStateKey(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); + + return fData->states[index].key; + } + + const String& getStateDefaultValue(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); + + return fData->states[index].defaultValue; + } + + const String& getStateLabel(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); + + return fData->states[index].label; + } + + const String& getStateDescription(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); + + return fData->states[index].description; + } + + #ifdef __MOD_DEVICES__ + const String& getStateFileTypes(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); + + return fData->states[index].fileTypes; + } + #endif + +# if DISTRHO_PLUGIN_WANT_FULL_STATE + String getStateValue(const char* const key) const + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString); + DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', sFallbackString); + + return fPlugin->getState(key); + } +# endif + + void setState(const char* const key, const char* const value) + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); + DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,); + + fPlugin->setState(key, value); + } + + bool wantStateKey(const char* const key) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false); + DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false); + + for (uint32_t i=0; i < fData->stateCount; ++i) + { + if (fData->states[i].key == key) + return true; + } + + return false; + } +#endif + +#if DISTRHO_PLUGIN_WANT_TIMEPOS + void setTimePosition(const TimePosition& timePosition) noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); + + std::memcpy(&fData->timePosition, &timePosition, sizeof(TimePosition)); + } +#endif + + // ------------------------------------------------------------------- + + bool isActive() const noexcept + { + return fIsActive; + } + + void activate() + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(! fIsActive,); + + fIsActive = true; + fPlugin->activate(); + } + + void deactivate() + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fIsActive,); + + fIsActive = false; + fPlugin->deactivate(); + } + + void deactivateIfNeeded() + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + + if (fIsActive) + { + fIsActive = false; + fPlugin->deactivate(); + } + } + +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT + void run(const float** const inputs, float** const outputs, const uint32_t frames, + const MidiEvent* const midiEvents, const uint32_t midiEventCount) + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + + if (! fIsActive) + { + fIsActive = true; + fPlugin->activate(); + } + + fData->isProcessing = true; + fPlugin->run(inputs, outputs, frames, midiEvents, midiEventCount); + fData->isProcessing = false; + } +#else + void run(const float** const inputs, float** const outputs, const uint32_t frames) + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + + if (! fIsActive) + { + fIsActive = true; + fPlugin->activate(); + } + + fData->isProcessing = true; + fPlugin->run(inputs, outputs, frames); + fData->isProcessing = false; + } +#endif + + // ------------------------------------------------------------------- + + uint32_t getBufferSize() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); + return fData->bufferSize; + } + + double getSampleRate() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0.0); + return fData->sampleRate; + } + + void setBufferSize(const uint32_t bufferSize, const bool doCallback = false) + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + DISTRHO_SAFE_ASSERT(bufferSize >= 2); + + if (fData->bufferSize == bufferSize) + return; + + fData->bufferSize = bufferSize; + + if (doCallback) + { + if (fIsActive) fPlugin->deactivate(); + fPlugin->bufferSizeChanged(bufferSize); + if (fIsActive) fPlugin->activate(); + } + } + + void setSampleRate(const double sampleRate, const bool doCallback = false) + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + DISTRHO_SAFE_ASSERT(sampleRate > 0.0); + + if (d_isEqual(fData->sampleRate, sampleRate)) + return; + + fData->sampleRate = sampleRate; + + if (doCallback) + { + if (fIsActive) fPlugin->deactivate(); + fPlugin->sampleRateChanged(sampleRate); + if (fIsActive) fPlugin->activate(); + } + } + +private: + // ------------------------------------------------------------------- + // Plugin and DistrhoPlugin data + + Plugin* const fPlugin; + Plugin::PrivateData* const fData; + bool fIsActive; + + // ------------------------------------------------------------------- + // 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; + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter) +}; + +// ----------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO + +#endif // DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED