Mercurial > hg > pub > prymula > com
diff DPF-Prymula-audioplugins/dpf/distrho/src/DistrhoPluginCarla.cpp @ 3:84e66ea83026
DPF-Prymula-audioplugins-0.231015-2
author | prymula <prymula76@outlook.com> |
---|---|
date | Mon, 16 Oct 2023 21:53:34 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DPF-Prymula-audioplugins/dpf/distrho/src/DistrhoPluginCarla.cpp Mon Oct 16 21:53:34 2023 +0200 @@ -0,0 +1,551 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "DistrhoPluginInternal.hpp" + +#if DISTRHO_PLUGIN_HAS_UI +# include "DistrhoUIInternal.hpp" +#endif + +#include "CarlaNative.hpp" + +// TODO +#undef DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST +#define DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 0 + +// ----------------------------------------------------------------------- + +START_NAMESPACE_DISTRHO + +#if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT +static constexpr const writeMidiFunc writeMidiCallback = nullptr; +#endif +#if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST +static constexpr const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr; +#endif +// TODO +static constexpr const updateStateValueFunc updateStateValueCallback = nullptr; + +#if DISTRHO_PLUGIN_HAS_UI +// ----------------------------------------------------------------------- +// Carla UI + +#if ! DISTRHO_PLUGIN_WANT_STATE +static const setStateFunc setStateCallback = nullptr; +#endif +#if ! DISTRHO_PLUGIN_IS_SYNTH +static const sendNoteFunc sendNoteCallback = nullptr; +#endif + +class UICarla +{ +public: + UICarla(const NativeHostDescriptor* const host, PluginExporter* const plugin) + : fHost(host), + fUI(this, 0, plugin->getSampleRate(), + editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, + nullptr, // window size + nullptr, // TODO file request + nullptr, // bundle path + plugin->getInstancePointer()) + { + fUI.setWindowTitle(host->uiName); + + if (host->uiParentId != 0) + fUI.setWindowTransientWinId(host->uiParentId); + } + + ~UICarla() + { + fUI.quit(); + } + + // --------------------------------------------- + + void carla_show(const bool yesNo) + { + fUI.setWindowVisible(yesNo); + } + + bool carla_idle() + { + return fUI.plugin_idle(); + } + + void carla_setParameterValue(const uint32_t index, const float value) + { + fUI.parameterChanged(index, value); + } + +#if DISTRHO_PLUGIN_WANT_PROGRAMS + void carla_setMidiProgram(const uint32_t realProgram) + { + fUI.programLoaded(realProgram); + } +#endif + +#if DISTRHO_PLUGIN_WANT_STATE + void carla_setCustomData(const char* const key, const char* const value) + { + fUI.stateChanged(key, value); + } +#endif + + void carla_setUiTitle(const char* const uiTitle) + { + fUI.setWindowTitle(uiTitle); + } + + // --------------------------------------------- + +protected: + void handleEditParameter(const uint32_t, const bool) + { + // TODO + } + + void handleSetParameterValue(const uint32_t rindex, const float value) + { + fHost->ui_parameter_changed(fHost->handle, rindex, value); + } + +#if DISTRHO_PLUGIN_WANT_STATE + void handleSetState(const char* const key, const char* const value) + { + fHost->ui_custom_data_changed(fHost->handle, key, value); + } +#endif + +#if DISTRHO_PLUGIN_IS_SYNTH + void handleSendNote(const uint8_t, const uint8_t, const uint8_t) + { + // TODO + } +#endif + + // --------------------------------------------- + +private: + // Plugin stuff + const NativeHostDescriptor* const fHost; + + // UI + UIExporter fUI; + + // --------------------------------------------- + // Callbacks + + #define handlePtr ((UICarla*)ptr) + + static void editParameterCallback(void* ptr, uint32_t index, bool started) + { + handlePtr->handleEditParameter(index, started); + } + + static void setParameterCallback(void* ptr, uint32_t rindex, float value) + { + handlePtr->handleSetParameterValue(rindex, value); + } + +#if DISTRHO_PLUGIN_WANT_STATE + static void setStateCallback(void* ptr, const char* key, const char* value) + { + handlePtr->handleSetState(key, value); + } +#endif + +#if DISTRHO_PLUGIN_IS_SYNTH + static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) + { + handlePtr->handleSendNote(channel, note, velocity); + } +#endif + + #undef handlePtr + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UICarla) +}; +#endif // DISTRHO_PLUGIN_HAS_UI + +// ----------------------------------------------------------------------- +// Carla Plugin + +class PluginCarla : public NativePluginClass +{ +public: + PluginCarla(const NativeHostDescriptor* const host) + : NativePluginClass(host), + fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, updateStateValueCallback), + fScalePointsCache(nullptr) + { +#if DISTRHO_PLUGIN_HAS_UI + fUiPtr = nullptr; +#endif + } + + ~PluginCarla() override + { +#if DISTRHO_PLUGIN_HAS_UI + if (fUiPtr != nullptr) + { + delete fUiPtr; + fUiPtr = nullptr; + } +#endif + + if (fScalePointsCache != nullptr) + { + delete[] fScalePointsCache; + fScalePointsCache = nullptr; + } + } + +protected: + // ------------------------------------------------------------------- + // Plugin parameter calls + + uint32_t getParameterCount() const override + { + return fPlugin.getParameterCount(); + } + + const NativeParameter* getParameterInfo(const uint32_t index) const override + { + CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(), nullptr); + + static NativeParameter param; + + param.scalePointCount = 0; + param.scalePoints = nullptr; + + { + int nativeParamHints = ::NATIVE_PARAMETER_IS_ENABLED; + const uint32_t paramHints = fPlugin.getParameterHints(index); + + if (paramHints & kParameterIsAutomatable) + nativeParamHints |= ::NATIVE_PARAMETER_IS_AUTOMABLE; + if (paramHints & kParameterIsBoolean) + nativeParamHints |= ::NATIVE_PARAMETER_IS_BOOLEAN; + if (paramHints & kParameterIsInteger) + nativeParamHints |= ::NATIVE_PARAMETER_IS_INTEGER; + if (paramHints & kParameterIsLogarithmic) + nativeParamHints |= ::NATIVE_PARAMETER_IS_LOGARITHMIC; + if (paramHints & kParameterIsOutput) + nativeParamHints |= ::NATIVE_PARAMETER_IS_OUTPUT; + + param.hints = static_cast<NativeParameterHints>(nativeParamHints); + } + + param.name = fPlugin.getParameterName(index); + param.unit = fPlugin.getParameterUnit(index); + + { + const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); + + param.ranges.def = ranges.def; + param.ranges.min = ranges.min; + param.ranges.max = ranges.max; + } + + { + const ParameterEnumerationValues& enumValues(fPlugin.getParameterEnumValues(index)); + + if (const uint32_t scalePointCount = enumValues.count) + { + NativeParameterScalePoint* const scalePoints = new NativeParameterScalePoint[scalePointCount]; + + for (uint32_t i=0; i<scalePointCount; ++i) + { + scalePoints[i].label = enumValues.values[i].label.buffer(); + scalePoints[i].value = enumValues.values[i].value; + } + + param.scalePoints = scalePoints; + param.scalePointCount = scalePointCount; + + if (enumValues.restrictedMode) + param.hints = static_cast<NativeParameterHints>(param.hints|::NATIVE_PARAMETER_USES_SCALEPOINTS); + } + else if (fScalePointsCache != nullptr) + { + delete[] fScalePointsCache; + fScalePointsCache = nullptr; + } + } + + return ¶m; + } + + float getParameterValue(const uint32_t index) const override + { + CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(), 0.0f); + + return fPlugin.getParameterValue(index); + } + + // ------------------------------------------------------------------- + // Plugin midi-program calls + +#if DISTRHO_PLUGIN_WANT_PROGRAMS + uint32_t getMidiProgramCount() const override + { + return fPlugin.getProgramCount(); + } + + const NativeMidiProgram* getMidiProgramInfo(const uint32_t index) const override + { + CARLA_SAFE_ASSERT_RETURN(index < getMidiProgramCount(), nullptr); + + static NativeMidiProgram midiProgram; + + midiProgram.bank = index / 128; + midiProgram.program = index % 128; + midiProgram.name = fPlugin.getProgramName(index); + + return &midiProgram; + } +#endif + + // ------------------------------------------------------------------- + // Plugin state calls + + void setParameterValue(const uint32_t index, const float value) override + { + CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),); + + fPlugin.setParameterValue(index, value); + } + +#if DISTRHO_PLUGIN_WANT_PROGRAMS + void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override + { + const uint32_t realProgram(bank * 128 + program); + + CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),); + + fPlugin.loadProgram(realProgram); + } +#endif + +#if DISTRHO_PLUGIN_WANT_STATE + void setCustomData(const char* const key, const char* const value) override + { + CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); + CARLA_SAFE_ASSERT_RETURN(value != nullptr,); + + fPlugin.setState(key, value); + } +#endif + + // ------------------------------------------------------------------- + // Plugin process calls + + void activate() override + { + fPlugin.activate(); + } + + void deactivate() override + { + fPlugin.deactivate(); + } + +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT + void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames, + const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override + { + MidiEvent realMidiEvents[midiEventCount]; + + for (uint32_t i=0; i < midiEventCount; ++i) + { + const NativeMidiEvent& midiEvent(midiEvents[i]); + MidiEvent& realMidiEvent(realMidiEvents[i]); + + realMidiEvent.frame = midiEvent.time; + realMidiEvent.size = midiEvent.size; + + uint8_t j=0; + for (; j<midiEvent.size; ++j) + realMidiEvent.data[j] = midiEvent.data[j]; + for (; j<midiEvent.size; ++j) + realMidiEvent.data[j] = midiEvent.data[j]; + + realMidiEvent.dataExt = nullptr; + } + + fPlugin.run(const_cast<const float**>(inBuffer), outBuffer, frames, realMidiEvents, midiEventCount); + } +#else + void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames, + const NativeMidiEvent* const, const uint32_t) override + { + fPlugin.run(const_cast<const float**>(inBuffer), outBuffer, frames); + } +#endif + + // ------------------------------------------------------------------- + // Plugin UI calls + +#if DISTRHO_PLUGIN_HAS_UI + void uiShow(const bool show) override + { + if (show) + { + createUiIfNeeded(); + CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); + + fUiPtr->carla_show(show); + } + else if (fUiPtr != nullptr) + { + delete fUiPtr; + fUiPtr = nullptr; + } + } + + void uiIdle() override + { + CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); + + if (! fUiPtr->carla_idle()) + { + uiClosed(); + + delete fUiPtr; + fUiPtr = nullptr; + } + } + + void uiSetParameterValue(const uint32_t index, const float value) override + { + CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); + CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),); + + fUiPtr->carla_setParameterValue(index, value); + } + +# if DISTRHO_PLUGIN_WANT_PROGRAMS + void uiSetMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override + { + CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); + + const uint32_t realProgram(bank * 128 + program); + + CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),); + + fUiPtr->carla_setMidiProgram(realProgram); + } +# endif + +# if DISTRHO_PLUGIN_WANT_STATE + void uiSetCustomData(const char* const key, const char* const value) override + { + CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); + CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); + CARLA_SAFE_ASSERT_RETURN(value != nullptr,); + + fUiPtr->carla_setCustomData(key, value); + } +# endif +#endif + + // ------------------------------------------------------------------- + // Plugin dispatcher calls + + void bufferSizeChanged(const uint32_t bufferSize) override + { + fPlugin.setBufferSize(bufferSize, true); + } + + void sampleRateChanged(const double sampleRate) override + { + fPlugin.setSampleRate(sampleRate, true); + } + +#if DISTRHO_PLUGIN_HAS_UI + void uiNameChanged(const char* const uiName) override + { + CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); + + fUiPtr->carla_setUiTitle(uiName); + } +#endif + + // ------------------------------------------------------------------- + +private: + PluginExporter fPlugin; + mutable NativeParameterScalePoint* fScalePointsCache; + +#if DISTRHO_PLUGIN_HAS_UI + // UI + UICarla* fUiPtr; + + void createUiIfNeeded() + { + if (fUiPtr == nullptr) + fUiPtr = new UICarla(getHostHandle(), &fPlugin); + } +#endif + +#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent) + { + if (midiEvent.size > 4) + return; + + const NativeMidiEvent event = { + midiEvent.frame, 0, midiEvent.size, midiEvent.data + }; + + return ((PluginCarla*)ptr)->fPlugin.writeMidiEvent(midiEvent); + } +#endif + +#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST + bool requestParameterValueChange(const uint32_t index, const float value) + { + // TODO implementation + return false; + } + + static bool requestParameterValueChangeCallback(void* ptr, const uint32_t index, const float value) + { + return thisPtr->requestParameterValueChange(index, value); + } +#endif + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla) + + // ------------------------------------------------------------------- + +public: + static NativePluginHandle _instantiate(const NativeHostDescriptor* host) + { + d_nextBufferSize = host->get_buffer_size(host->handle); + d_nextSampleRate = host->get_sample_rate(host->handle); + return new PluginCarla(host); + } + + static void _cleanup(NativePluginHandle handle) + { + delete (PluginCarla*)handle; + } +}; + +END_NAMESPACE_DISTRHO + +// -----------------------------------------------------------------------