diff --git a/source/modules/distrho/DistrhoPlugin.hpp b/source/modules/distrho/DistrhoPlugin.hpp index fcb40dd59..2fb9ec6f5 100644 --- a/source/modules/distrho/DistrhoPlugin.hpp +++ b/source/modules/distrho/DistrhoPlugin.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2018 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 @@ -89,6 +89,15 @@ static const uint32_t kParameterIsLogarithmic = 0x08; */ 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; + /** @} */ /* ------------------------------------------------------------------------------------------------------------ @@ -274,6 +283,90 @@ struct ParameterRanges { } }; +/** + 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`. + */ + const 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, const ParameterEnumerationValue* v) noexcept + : count(c), + restrictedMode(r), + values(v) {} + + ~ParameterEnumerationValues() noexcept + { + count = 0; + restrictedMode = false; + + if (values != nullptr) + { + delete[] values; + values = nullptr; + } + } +}; + /** Parameter. */ @@ -312,6 +405,12 @@ struct Parameter { */ ParameterRanges ranges; + /** + Enumeration values.@n + Can be used to give meaning to parameter values, working as an enumeration. + */ + ParameterEnumerationValues enumValues; + /** Designation for this parameter. */ @@ -334,6 +433,7 @@ struct Parameter { symbol(), unit(), ranges(), + enumValues(), designation(kParameterDesignationNull), midiCC(0) {} @@ -346,6 +446,7 @@ struct Parameter { symbol(s), unit(u), ranges(def, min, max), + enumValues(), designation(kParameterDesignationNull), midiCC(0) {} @@ -593,9 +694,6 @@ public: Write a MIDI output event.@n This function must only be called during run().@n Returns false when the host buffer is full, in which case do not call this again until the next run(). - @note This function is not implemented yet!@n - It's here so that developers can prepare MIDI plugins in advance.@n - If you plan to use this, please report to DPF authors so it can be implemented. */ bool writeMidiEvent(const MidiEvent& midiEvent) noexcept; #endif diff --git a/source/modules/distrho/DistrhoUI.hpp b/source/modules/distrho/DistrhoUI.hpp index 7429bdc28..a4ec9e610 100644 --- a/source/modules/distrho/DistrhoUI.hpp +++ b/source/modules/distrho/DistrhoUI.hpp @@ -90,10 +90,11 @@ public: void setState(const char* key, const char* value); #endif -#if DISTRHO_PLUGIN_IS_SYNTH +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT /** sendNote. @TODO Document this. + @note Work in progress. Implemented for DSSI and LV2 formats. */ void sendNote(uint8_t channel, uint8_t note, uint8_t velocity); #endif diff --git a/source/modules/distrho/extra/Base64.hpp b/source/modules/distrho/extra/Base64.hpp index da661c17d..d3eed6bee 100644 --- a/source/modules/distrho/extra/Base64.hpp +++ b/source/modules/distrho/extra/Base64.hpp @@ -106,7 +106,7 @@ std::vector d_getChunkFromBase64String(const char* const base64string) if (c == ' ' || c == '\n') continue; - DISTRHO_SAFE_ASSERT_CONTINUE(CarlaBase64Helpers::isBase64Char(c)); + DISTRHO_SAFE_ASSERT_CONTINUE(DistrhoBase64Helpers::isBase64Char(c)); charArray4[i++] = static_cast(c); diff --git a/source/modules/distrho/src/DistrhoPlugin.cpp b/source/modules/distrho/src/DistrhoPlugin.cpp index 20cdfcb01..345987615 100644 --- a/source/modules/distrho/src/DistrhoPlugin.cpp +++ b/source/modules/distrho/src/DistrhoPlugin.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2018 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 @@ -27,9 +27,10 @@ double d_lastSampleRate = 0.0; /* ------------------------------------------------------------------------------------------------------------ * Static fallback data, see DistrhoPluginInternal.hpp */ -const String PluginExporter::sFallbackString; -const AudioPort PluginExporter::sFallbackAudioPort; -const ParameterRanges PluginExporter::sFallbackRanges; +const String PluginExporter::sFallbackString; +const AudioPort PluginExporter::sFallbackAudioPort; +const ParameterRanges PluginExporter::sFallbackRanges; +const ParameterEnumerationValues PluginExporter::sFallbackEnumValues; /* ------------------------------------------------------------------------------------------------------------ * Plugin */ @@ -102,10 +103,9 @@ void Plugin::setLatency(uint32_t frames) noexcept #endif #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT -bool Plugin::writeMidiEvent(const MidiEvent& /*midiEvent*/) noexcept +bool Plugin::writeMidiEvent(const MidiEvent& midiEvent) noexcept { - // TODO - return false; + return pData->writeMidiCallback(midiEvent); } #endif diff --git a/source/modules/distrho/src/DistrhoPluginCarla.cpp b/source/modules/distrho/src/DistrhoPluginCarla.cpp index 6f7346635..3b50cd3e4 100644 --- a/source/modules/distrho/src/DistrhoPluginCarla.cpp +++ b/source/modules/distrho/src/DistrhoPluginCarla.cpp @@ -1,17 +1,17 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2018 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. + * 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. * - * 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 + * 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" @@ -30,6 +30,9 @@ START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- // Carla UI +#if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT +static const writeMidiFunc writeMidiCallback = nullptr; +#endif #if ! DISTRHO_PLUGIN_WANT_STATE static const setStateFunc setStateCallback = nullptr; #endif @@ -104,15 +107,19 @@ protected: 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 void handleSetSize(const uint width, const uint height) { @@ -175,7 +182,8 @@ class PluginCarla : public NativePluginClass { public: PluginCarla(const NativeHostDescriptor* const host) - : NativePluginClass(host) + : NativePluginClass(host), + fPlugin(this, writeMidiCallback) { #if DISTRHO_PLUGIN_HAS_UI fUiPtr = nullptr; @@ -317,7 +325,7 @@ protected: fPlugin.deactivate(); } -#if DISTRHO_PLUGIN_IS_SYNTH +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override { MidiEvent realMidiEvents[midiEventCount]; @@ -455,6 +463,20 @@ private: } #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 + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla) // ------------------------------------------------------------------- diff --git a/source/modules/distrho/src/DistrhoPluginInternal.hpp b/source/modules/distrho/src/DistrhoPluginInternal.hpp index d9677c140..604f4d985 100644 --- a/source/modules/distrho/src/DistrhoPluginInternal.hpp +++ b/source/modules/distrho/src/DistrhoPluginInternal.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2018 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 @@ -32,6 +32,11 @@ static const uint32_t kMaxMidiEvents = 512; extern uint32_t d_lastBufferSize; extern double d_lastSampleRate; +// ----------------------------------------------------------------------- +// DSP callbacks + +typedef bool (*writeMidiFunc) (void* ptr, const MidiEvent& midiEvent); + // ----------------------------------------------------------------------- // Plugin private data @@ -65,6 +70,10 @@ struct Plugin::PrivateData { TimePosition timePosition; #endif + // Callbacks + void* callbacksPtr; + writeMidiFunc writeMidiCallbackFunc; + uint32_t bufferSize; double sampleRate; @@ -88,6 +97,8 @@ struct Plugin::PrivateData { #if DISTRHO_PLUGIN_WANT_LATENCY latency(0), #endif + callbacksPtr(nullptr), + writeMidiCallbackFunc(nullptr), bufferSize(d_lastBufferSize), sampleRate(d_lastSampleRate) { @@ -149,6 +160,16 @@ struct Plugin::PrivateData { } #endif } + +#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + bool writeMidiCallback(const MidiEvent& midiEvent) + { + if (writeMidiCallbackFunc != nullptr) + return writeMidiCallbackFunc(callbacksPtr, midiEvent); + + return false; + } +#endif }; // ----------------------------------------------------------------------- @@ -157,7 +178,7 @@ struct Plugin::PrivateData { class PluginExporter { public: - PluginExporter() + PluginExporter(void* const callbacksPtr, const writeMidiFunc writeMidiCall) : fPlugin(createPlugin()), fData((fPlugin != nullptr) ? fPlugin->pData : nullptr), fIsActive(false) @@ -191,6 +212,9 @@ public: for (uint32_t i=0, count=fData->stateCount; i < count; ++i) fPlugin->initState(i, fData->stateKeys[i], fData->stateDefValues[i]); #endif + + fData->callbacksPtr = callbacksPtr; + fData->writeMidiCallbackFunc = writeMidiCall; } ~PluginExporter() @@ -322,9 +346,26 @@ public: 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); + return (getParameterHints(index) & kParameterIsOutput) != 0x0; + } + + 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 @@ -348,6 +389,13 @@ public: return fData->parameters[index].unit; } + 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); @@ -503,7 +551,7 @@ public: } } -#if DISTRHO_PLUGIN_IS_SYNTH +#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) { @@ -601,9 +649,10 @@ private: // ------------------------------------------------------------------- // Static fallback data, see DistrhoPlugin.cpp - static const String sFallbackString; - static const AudioPort sFallbackAudioPort; - static const ParameterRanges sFallbackRanges; + static const String sFallbackString; + static const AudioPort sFallbackAudioPort; + static const ParameterRanges sFallbackRanges; + static const ParameterEnumerationValues sFallbackEnumValues; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter) DISTRHO_PREVENT_HEAP_ALLOCATION diff --git a/source/modules/distrho/src/DistrhoUI.cpp b/source/modules/distrho/src/DistrhoUI.cpp index 5500e394e..f180ee2e6 100644 --- a/source/modules/distrho/src/DistrhoUI.cpp +++ b/source/modules/distrho/src/DistrhoUI.cpp @@ -82,7 +82,7 @@ void UI::setState(const char* key, const char* value) } #endif -#if DISTRHO_PLUGIN_IS_SYNTH +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity) { pData->sendNoteCallback(channel, note, velocity); diff --git a/source/modules/distrho/src/DistrhoUIInternal.hpp b/source/modules/distrho/src/DistrhoUIInternal.hpp index b2dd7e67a..bcd4c042f 100644 --- a/source/modules/distrho/src/DistrhoUIInternal.hpp +++ b/source/modules/distrho/src/DistrhoUIInternal.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2018 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 @@ -61,12 +61,12 @@ struct UI::PrivateData { #endif // Callbacks + void* callbacksPtr; editParamFunc editParamCallbackFunc; setParamFunc setParamCallbackFunc; setStateFunc setStateCallbackFunc; sendNoteFunc sendNoteCallbackFunc; setSizeFunc setSizeCallbackFunc; - void* ptr; PrivateData() noexcept : sampleRate(d_lastUiSampleRate), @@ -74,12 +74,12 @@ struct UI::PrivateData { #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS dspPtr(d_lastUiDspPtr), #endif + callbacksPtr(nullptr), editParamCallbackFunc(nullptr), setParamCallbackFunc(nullptr), setStateCallbackFunc(nullptr), sendNoteCallbackFunc(nullptr), - setSizeCallbackFunc(nullptr), - ptr(nullptr) + setSizeCallbackFunc(nullptr) { DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate)); @@ -103,31 +103,31 @@ struct UI::PrivateData { void editParamCallback(const uint32_t rindex, const bool started) { if (editParamCallbackFunc != nullptr) - editParamCallbackFunc(ptr, rindex, started); + editParamCallbackFunc(callbacksPtr, rindex, started); } void setParamCallback(const uint32_t rindex, const float value) { if (setParamCallbackFunc != nullptr) - setParamCallbackFunc(ptr, rindex, value); + setParamCallbackFunc(callbacksPtr, rindex, value); } void setStateCallback(const char* const key, const char* const value) { if (setStateCallbackFunc != nullptr) - setStateCallbackFunc(ptr, key, value); + setStateCallbackFunc(callbacksPtr, key, value); } void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity) { if (sendNoteCallbackFunc != nullptr) - sendNoteCallbackFunc(ptr, channel, note, velocity); + sendNoteCallbackFunc(callbacksPtr, channel, note, velocity); } void setSizeCallback(const uint width, const uint height) { if (setSizeCallbackFunc != nullptr) - setSizeCallbackFunc(ptr, width, height); + setSizeCallbackFunc(callbacksPtr, width, height); } }; @@ -221,8 +221,13 @@ UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const char* const class UIExporter { public: - UIExporter(void* const ptr, const intptr_t winId, - const editParamFunc editParamCall, const setParamFunc setParamCall, const setStateFunc setStateCall, const sendNoteFunc sendNoteCall, const setSizeFunc setSizeCall, + UIExporter(void* const callbacksPtr, + const intptr_t winId, + const editParamFunc editParamCall, + const setParamFunc setParamCall, + const setStateFunc setStateCall, + const sendNoteFunc sendNoteCall, + const setSizeFunc setSizeCall, void* const dspPtr = nullptr, const char* const bundlePath = nullptr) #ifdef HAVE_DGL @@ -238,7 +243,7 @@ public: DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); - fData->ptr = ptr; + fData->callbacksPtr = callbacksPtr; fData->editParamCallbackFunc = editParamCall; fData->setParamCallbackFunc = setParamCall; fData->setStateCallbackFunc = setStateCall;