diff --git a/distrho/src/DistrhoPluginCarla.cpp b/distrho/src/DistrhoPluginCarla.cpp new file mode 100644 index 00000000..334bb876 --- /dev/null +++ b/distrho/src/DistrhoPluginCarla.cpp @@ -0,0 +1,471 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2014 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * For a full copy of the license see the LGPL.txt file + */ + +#include "DistrhoPluginInternal.hpp" + +#if DISTRHO_PLUGIN_HAS_UI +# include "DistrhoUIInternal.hpp" +#endif + +#include "CarlaNative.hpp" + +// ----------------------------------------------------------------------- + +START_NAMESPACE_DISTRHO + +#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), + fPlugin(plugin), + fUI(this, 0, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback) + { + fUI.setTitle(host->uiName); + } + + // --------------------------------------------- + + void carla_show(const bool yesNo) + { + fUI.setVisible(yesNo); + } + + void carla_idle() + { + fUI.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.programChanged(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.setTitle(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); + } + + void handleSetState(const char* const key, const char* const value) + { + fHost->ui_custom_data_changed(fHost->handle, key, value); + } + + void handleSendNote(const uint8_t, const uint8_t, const uint8_t) + { + // TODO + } + + void handleUiResize(const unsigned int width, const unsigned int height) + { + fUI.setSize(width, height); + } + + // --------------------------------------------- + +private: + // Plugin stuff + const NativeHostDescriptor* const fHost; + PluginExporter* const fPlugin; + + // 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 + + static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height) + { + handlePtr->handleUiResize(width, height); + } + + #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) + { +#if DISTRHO_PLUGIN_HAS_UI + fUiPtr = nullptr; +#endif + } + + ~PluginCarla() override + { +#if DISTRHO_PLUGIN_HAS_UI + if (fUiPtr != nullptr) + { + delete fUiPtr; + fUiPtr = nullptr; + } +#endif + } + +protected: + // ------------------------------------------------------------------- + // Plugin parameter calls + + uint32_t getParameterCount() const override + { + return fPlugin.getParameterCount(); + } + + const NativeParameter* getParameterInfo(const uint32_t index) const override + { + CARLA_ASSERT(index < getParameterCount()); + + static NativeParameter param; + + // reset + param.hints = ::PARAMETER_IS_ENABLED; + param.scalePointCount = 0; + param.scalePoints = nullptr; + + { + int nativeParamHints = ::PARAMETER_IS_ENABLED; + const uint32_t paramHints = fPlugin.getParameterHints(index); + + if (paramHints & PARAMETER_IS_AUTOMABLE) + nativeParamHints |= ::PARAMETER_IS_AUTOMABLE; + if (paramHints & PARAMETER_IS_BOOLEAN) + nativeParamHints |= ::PARAMETER_IS_BOOLEAN; + if (paramHints & PARAMETER_IS_INTEGER) + nativeParamHints |= ::PARAMETER_IS_INTEGER; + if (paramHints & PARAMETER_IS_LOGARITHMIC) + nativeParamHints |= ::PARAMETER_IS_LOGARITHMIC; + if (paramHints & PARAMETER_IS_OUTPUT) + nativeParamHints |= ::PARAMETER_IS_OUTPUT; + + param.hints = static_cast(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; + //param.ranges.step = ranges.step; + //param.ranges.stepSmall = ranges.stepSmall; + //param.ranges.stepLarge = ranges.stepLarge; + } + + return ¶m; + } + + float getParameterValue(const uint32_t index) const override + { + CARLA_ASSERT(index < getParameterCount()); + + 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_ASSERT(index < getMidiProgramCount()); + + if (index >= fPlugin.getProgramCount()) + return 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_ASSERT(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); + + if (realProgram >= fPlugin.getProgramCount()) + return; + + fPlugin.setProgram(realProgram); + } +#endif + +#if DISTRHO_PLUGIN_WANT_STATE + void setCustomData(const char* const key, const char* const value) override + { + CARLA_ASSERT(key != nullptr); + CARLA_ASSERT(value != nullptr); + + fPlugin.setState(key, value); + } +#endif + + // ------------------------------------------------------------------- + // Plugin process calls + + void activate() override + { + fPlugin.activate(); + } + + void deactivate() override + { + fPlugin.deactivate(); + } + +#if DISTRHO_PLUGIN_IS_SYNTH + void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override + { + uint32_t i; + + for (i=0; i < midiEventCount && i < kMaxMidiEvents; ++i) + { + const NativeMidiEvent* const midiEvent(&midiEvents[i]); + MidiEvent* const realMidiEvent(&fRealMidiEvents[i]); + + realMidiEvent->frame = midiEvent->time; + realMidiEvent->size = midiEvent->size; + + for (uint8_t j=0; j < midiEvent->size; ++j) + realMidiEvent->buf[j] = midiEvent->data[j]; + } + + fPlugin.run(inBuffer, outBuffer, frames, fRealMidiEvents, i); + } +#else + void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const, const uint32_t) override + { + fPlugin.run(inBuffer, outBuffer, frames); + } +#endif + + // ------------------------------------------------------------------- + // Plugin UI calls + +#if DISTRHO_PLUGIN_HAS_UI + void uiShow(const bool show) override + { + if (show) + createUiIfNeeded(); + + if (fUiPtr != nullptr) + fUiPtr->carla_show(show); + } + + void uiIdle() override + { + CARLA_ASSERT(fUiPtr != nullptr); + + if (fUiPtr != nullptr) + fUiPtr->carla_idle(); + } + + void uiSetParameterValue(const uint32_t index, const float value) override + { + CARLA_ASSERT(fUiPtr != nullptr); + CARLA_ASSERT(index < getParameterCount()); + + if (fUiPtr != nullptr) + 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_ASSERT(fUiPtr != nullptr); + + const uint32_t realProgram(bank * 128 + program); + + if (realProgram >= fPlugin.getProgramCount()) + return; + + if (fUiPtr != nullptr) + fUiPtr->carla_setMidiProgram(realProgram); + } +# endif + +# if DISTRHO_PLUGIN_WANT_STATE + void uiSetCustomData(const char* const key, const char* const value) override + { + CARLA_ASSERT(fUiPtr != nullptr); + CARLA_ASSERT(key != nullptr); + CARLA_ASSERT(value != nullptr); + + if (fUiPtr != 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 + { + if (fUiPtr != nullptr) + fUiPtr->carla_setUiTitle(uiName); + } +#endif + + // ------------------------------------------------------------------- + +private: + PluginExporter fPlugin; + +#if DISTRHO_PLUGIN_IS_SYNTH + MidiEvent fRealMidiEvents[kMaxMidiEvents]; +#endif + +#if DISTRHO_PLUGIN_HAS_UI + // UI + UICarla* fUiPtr; + + void createUiIfNeeded() + { + if (fUiPtr == nullptr) + { + d_lastUiSampleRate = getSampleRate(); + fUiPtr = new UICarla(getHostHandle(), &fPlugin); + } + } +#endif + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla) + + // ------------------------------------------------------------------- + +public: + static NativePluginHandle _instantiate(const NativeHostDescriptor* host) + { + d_lastBufferSize = host->get_buffer_size(host->handle); + d_lastSampleRate = host->get_sample_rate(host->handle); + return new PluginCarla(host); + } + + static void _cleanup(NativePluginHandle handle) + { + delete (PluginCarla*)handle; + } +}; + +END_NAMESPACE_DISTRHO + +// -----------------------------------------------------------------------