/* * DISTRHO Plugin Framework (DPF) * Copyright (C) 2012-2022 Filipe Coelho * * 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 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_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 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; } } // ----------------------------------------------------------------------- // Plugin private data struct Plugin::PrivateData { const bool canRequestParameterValueChanges; const bool isDummy; 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), 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->*(&Plugin::initState)) == (void*)&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 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(portGroupIndices.size())) { fData->portGroups = new PortGroupWithId[portGroupSize]; fData->portGroupCount = portGroupSize; uint32_t index = 0; for (std::set::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; iaudioPorts[i].groupId == groupId) ++numPorts; } #endif } else { #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 for (uint32_t i=0; iaudioPorts[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 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; } # 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