| @@ -62,7 +62,7 @@ public: | |||||
| idle() is called at regular intervals. | idle() is called at regular intervals. | ||||
| @note This function is meant for standalones only, *never* call this from plugins. | @note This function is meant for standalones only, *never* call this from plugins. | ||||
| */ | */ | ||||
| void exec(); | |||||
| void exec(int idleTime = 10); | |||||
| /** | /** | ||||
| Quit the application. | Quit the application. | ||||
| @@ -44,12 +44,12 @@ void Application::idle() | |||||
| } | } | ||||
| } | } | ||||
| void Application::exec() | |||||
| void Application::exec(int idleTime) | |||||
| { | { | ||||
| for (; pData->doLoop;) | for (; pData->doLoop;) | ||||
| { | { | ||||
| idle(); | idle(); | ||||
| d_msleep(10); | |||||
| d_msleep(idleTime); | |||||
| } | } | ||||
| } | } | ||||
| @@ -472,8 +472,8 @@ void NanoVG::skewY(float angle) | |||||
| void NanoVG::scale(float x, float y) | void NanoVG::scale(float x, float y) | ||||
| { | { | ||||
| if (fContext == nullptr) return; | if (fContext == nullptr) return; | ||||
| DISTRHO_SAFE_ASSERT_RETURN(x > 0.0f,); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(y > 0.0f,); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(d_isNotZero(x),); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(d_isNotZero(y),); | |||||
| nvgScale(fContext, x, y); | nvgScale(fContext, x, y); | ||||
| } | } | ||||
| @@ -865,7 +865,7 @@ float NanoVG::textBounds(float x, float y, const char* string, const char* end, | |||||
| float b[4]; | float b[4]; | ||||
| const float ret = nvgTextBounds(fContext, x, y, string, end, b); | const float ret = nvgTextBounds(fContext, x, y, string, end, b); | ||||
| bounds = Rectangle<float>(b[0], b[1], b[2], b[3]); | |||||
| bounds = Rectangle<float>(b[0], b[1], b[2] - b[0], b[3] - b[1]); | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
| @@ -63,9 +63,9 @@ struct Widget::PrivateData { | |||||
| subWidgets.clear(); | subWidgets.clear(); | ||||
| } | } | ||||
| void display(const uint width, const uint height) | |||||
| void display(const uint width, const uint height, const bool renderingSubWidget) | |||||
| { | { | ||||
| if (skipDisplay || ! visible) | |||||
| if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) | |||||
| return; | return; | ||||
| bool needsDisableScissor = false; | bool needsDisableScissor = false; | ||||
| @@ -123,7 +123,7 @@ struct Widget::PrivateData { | |||||
| Widget* const widget(*it); | Widget* const widget(*it); | ||||
| DISTRHO_SAFE_ASSERT_CONTINUE(widget->pData != this); | DISTRHO_SAFE_ASSERT_CONTINUE(widget->pData != this); | ||||
| widget->pData->display(width, height); | |||||
| widget->pData->display(width, height, true); | |||||
| } | } | ||||
| } | } | ||||
| @@ -33,6 +33,8 @@ | |||||
| #if defined(DISTRHO_OS_WINDOWS) | #if defined(DISTRHO_OS_WINDOWS) | ||||
| # include "pugl/pugl_win.cpp" | # include "pugl/pugl_win.cpp" | ||||
| #elif defined(DISTRHO_OS_MAC) | #elif defined(DISTRHO_OS_MAC) | ||||
| # define PuglWindow DISTRHO_JOIN_MACRO(PuglWindow, DGL_NAMESPACE) | |||||
| # define PuglOpenGLView DISTRHO_JOIN_MACRO(PuglOpenGLView, DGL_NAMESPACE) | |||||
| # include "pugl/pugl_osx.m" | # include "pugl/pugl_osx.m" | ||||
| #else | #else | ||||
| # include <sys/types.h> | # include <sys/types.h> | ||||
| @@ -721,7 +723,7 @@ struct Window::PrivateData { | |||||
| FOR_EACH_WIDGET(it) | FOR_EACH_WIDGET(it) | ||||
| { | { | ||||
| Widget* const widget(*it); | Widget* const widget(*it); | ||||
| widget->pData->display(fWidth, fHeight); | |||||
| widget->pData->display(fWidth, fHeight, false); | |||||
| } | } | ||||
| fSelf->onDisplayAfter(); | fSelf->onDisplayAfter(); | ||||
| @@ -24,9 +24,6 @@ | |||||
| #include "pugl_internal.h" | #include "pugl_internal.h" | ||||
| #define PuglWindow PuglWindow ## DGL_NAMESPACE | |||||
| #define PuglOpenGLView PuglOpenGLView ## DGL_NAMESPACE | |||||
| @interface PuglWindow : NSWindow | @interface PuglWindow : NSWindow | ||||
| { | { | ||||
| @public | @public | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * 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; | 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. | Parameter. | ||||
| */ | */ | ||||
| @@ -312,6 +405,12 @@ struct Parameter { | |||||
| */ | */ | ||||
| ParameterRanges ranges; | ParameterRanges ranges; | ||||
| /** | |||||
| Enumeration values.@n | |||||
| Can be used to give meaning to parameter values, working as an enumeration. | |||||
| */ | |||||
| ParameterEnumerationValues enumValues; | |||||
| /** | /** | ||||
| Designation for this parameter. | Designation for this parameter. | ||||
| */ | */ | ||||
| @@ -334,6 +433,7 @@ struct Parameter { | |||||
| symbol(), | symbol(), | ||||
| unit(), | unit(), | ||||
| ranges(), | ranges(), | ||||
| enumValues(), | |||||
| designation(kParameterDesignationNull), | designation(kParameterDesignationNull), | ||||
| midiCC(0) {} | midiCC(0) {} | ||||
| @@ -346,6 +446,7 @@ struct Parameter { | |||||
| symbol(s), | symbol(s), | ||||
| unit(u), | unit(u), | ||||
| ranges(def, min, max), | ranges(def, min, max), | ||||
| enumValues(), | |||||
| designation(kParameterDesignationNull), | designation(kParameterDesignationNull), | ||||
| midiCC(0) {} | midiCC(0) {} | ||||
| @@ -593,9 +694,6 @@ public: | |||||
| Write a MIDI output event.@n | Write a MIDI output event.@n | ||||
| This function must only be called during run().@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(). | 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; | bool writeMidiEvent(const MidiEvent& midiEvent) noexcept; | ||||
| #endif | #endif | ||||
| @@ -90,10 +90,11 @@ public: | |||||
| void setState(const char* key, const char* value); | void setState(const char* key, const char* value); | ||||
| #endif | #endif | ||||
| #if DISTRHO_PLUGIN_IS_SYNTH | |||||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| /** | /** | ||||
| sendNote. | sendNote. | ||||
| @TODO Document this. | @TODO Document this. | ||||
| @note Work in progress. Implemented for DSSI and LV2 formats. | |||||
| */ | */ | ||||
| void sendNote(uint8_t channel, uint8_t note, uint8_t velocity); | void sendNote(uint8_t channel, uint8_t note, uint8_t velocity); | ||||
| #endif | #endif | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * 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 */ | * 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 */ | * Plugin */ | ||||
| @@ -102,10 +103,9 @@ void Plugin::setLatency(uint32_t frames) noexcept | |||||
| #endif | #endif | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | #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 | #endif | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * 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 uint32_t d_lastBufferSize; | ||||
| extern double d_lastSampleRate; | extern double d_lastSampleRate; | ||||
| // ----------------------------------------------------------------------- | |||||
| // DSP callbacks | |||||
| typedef bool (*writeMidiFunc) (void* ptr, const MidiEvent& midiEvent); | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // Plugin private data | // Plugin private data | ||||
| @@ -65,6 +70,10 @@ struct Plugin::PrivateData { | |||||
| TimePosition timePosition; | TimePosition timePosition; | ||||
| #endif | #endif | ||||
| // Callbacks | |||||
| void* callbacksPtr; | |||||
| writeMidiFunc writeMidiCallbackFunc; | |||||
| uint32_t bufferSize; | uint32_t bufferSize; | ||||
| double sampleRate; | double sampleRate; | ||||
| @@ -88,6 +97,8 @@ struct Plugin::PrivateData { | |||||
| #if DISTRHO_PLUGIN_WANT_LATENCY | #if DISTRHO_PLUGIN_WANT_LATENCY | ||||
| latency(0), | latency(0), | ||||
| #endif | #endif | ||||
| callbacksPtr(nullptr), | |||||
| writeMidiCallbackFunc(nullptr), | |||||
| bufferSize(d_lastBufferSize), | bufferSize(d_lastBufferSize), | ||||
| sampleRate(d_lastSampleRate) | sampleRate(d_lastSampleRate) | ||||
| { | { | ||||
| @@ -149,6 +160,16 @@ struct Plugin::PrivateData { | |||||
| } | } | ||||
| #endif | #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 | class PluginExporter | ||||
| { | { | ||||
| public: | public: | ||||
| PluginExporter() | |||||
| PluginExporter(void* const callbacksPtr, const writeMidiFunc writeMidiCall) | |||||
| : fPlugin(createPlugin()), | : fPlugin(createPlugin()), | ||||
| fData((fPlugin != nullptr) ? fPlugin->pData : nullptr), | fData((fPlugin != nullptr) ? fPlugin->pData : nullptr), | ||||
| fIsActive(false) | fIsActive(false) | ||||
| @@ -191,6 +212,9 @@ public: | |||||
| for (uint32_t i=0, count=fData->stateCount; i < count; ++i) | for (uint32_t i=0, count=fData->stateCount; i < count; ++i) | ||||
| fPlugin->initState(i, fData->stateKeys[i], fData->stateDefValues[i]); | fPlugin->initState(i, fData->stateKeys[i], fData->stateDefValues[i]); | ||||
| #endif | #endif | ||||
| fData->callbacksPtr = callbacksPtr; | |||||
| fData->writeMidiCallbackFunc = writeMidiCall; | |||||
| } | } | ||||
| ~PluginExporter() | ~PluginExporter() | ||||
| @@ -322,9 +346,26 @@ public: | |||||
| return fData->parameters[index].designation; | 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 | 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 | const String& getParameterName(const uint32_t index) const noexcept | ||||
| @@ -348,6 +389,13 @@ public: | |||||
| return fData->parameters[index].unit; | 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 | const ParameterRanges& getParameterRanges(const uint32_t index) const noexcept | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackRanges); | DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackRanges); | ||||
| @@ -601,9 +649,10 @@ private: | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Static fallback data, see DistrhoPlugin.cpp | // 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_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter) | ||||
| DISTRHO_PREVENT_HEAP_ALLOCATION | DISTRHO_PREVENT_HEAP_ALLOCATION | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU Lesser General Public | * modify it under the terms of the GNU Lesser General Public | ||||
| @@ -42,6 +42,9 @@ START_NAMESPACE_DISTRHO | |||||
| #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_STATE | ||||
| static const setStateFunc setStateCallback = nullptr; | static const setStateFunc setStateCallback = nullptr; | ||||
| #endif | #endif | ||||
| #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| static const writeMidiFunc writeMidiCallback = nullptr; | |||||
| #endif | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -91,7 +94,7 @@ class PluginJack | |||||
| { | { | ||||
| public: | public: | ||||
| PluginJack(jack_client_t* const client) | PluginJack(jack_client_t* const client) | ||||
| : fPlugin(), | |||||
| : fPlugin(this, writeMidiCallback), | |||||
| #if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
| fUI(this, 0, nullptr, setParameterValueCallback, setStateCallback, nullptr, setSizeCallback, fPlugin.getInstancePointer()), | fUI(this, 0, nullptr, setParameterValueCallback, setStateCallback, nullptr, setSizeCallback, fPlugin.getInstancePointer()), | ||||
| #endif | #endif | ||||
| @@ -119,6 +122,11 @@ public: | |||||
| fPortEventsIn = jack_port_register(fClient, "events-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | fPortEventsIn = jack_port_register(fClient, "events-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| fPortMidiOut = jack_port_register(fClient, "midi-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); | |||||
| fPortMidiOutBuffer = nullptr; | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | #if DISTRHO_PLUGIN_WANT_PROGRAMS | ||||
| if (fPlugin.getProgramCount() > 0) | if (fPlugin.getProgramCount() > 0) | ||||
| { | { | ||||
| @@ -196,11 +204,24 @@ public: | |||||
| fLastOutputValues = nullptr; | fLastOutputValues = nullptr; | ||||
| } | } | ||||
| #if DISTRHO_PLUGIN_HAS_UI | |||||
| if (fParametersChanged != nullptr) | |||||
| { | |||||
| delete[] fParametersChanged; | |||||
| fParametersChanged = nullptr; | |||||
| } | |||||
| #endif | |||||
| fPlugin.deactivate(); | fPlugin.deactivate(); | ||||
| if (fClient == nullptr) | if (fClient == nullptr) | ||||
| return; | return; | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| jack_port_unregister(fClient, fPortMidiOut); | |||||
| fPortMidiOut = nullptr; | |||||
| #endif | |||||
| jack_port_unregister(fClient, fPortEventsIn); | jack_port_unregister(fClient, fPortEventsIn); | ||||
| fPortEventsIn = nullptr; | fPortEventsIn = nullptr; | ||||
| @@ -330,6 +351,11 @@ protected: | |||||
| void* const midiBuf = jack_port_get_buffer(fPortEventsIn, nframes); | void* const midiBuf = jack_port_get_buffer(fPortEventsIn, nframes); | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| fPortMidiOutBuffer = jack_port_get_buffer(fPortMidiOut, nframes); | |||||
| jack_midi_clear_buffer(fPortMidiOutBuffer); | |||||
| #endif | |||||
| if (const uint32_t eventCount = jack_midi_get_event_count(midiBuf)) | if (const uint32_t eventCount = jack_midi_get_event_count(midiBuf)) | ||||
| { | { | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
| @@ -408,6 +434,12 @@ protected: | |||||
| #else | #else | ||||
| fPlugin.run(audioIns, audioOuts, nframes); | fPlugin.run(audioIns, audioOuts, nframes); | ||||
| #endif | #endif | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| fPortMidiOutBuffer = nullptr; | |||||
| #endif | |||||
| updateParameterTriggers(); | |||||
| } | } | ||||
| void jackShutdown() | void jackShutdown() | ||||
| @@ -440,6 +472,35 @@ protected: | |||||
| } | } | ||||
| #endif | #endif | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| bool writeMidi(const MidiEvent& midiEvent) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fPortMidiOutBuffer != nullptr, false); | |||||
| return jack_midi_event_write(fPortMidiOutBuffer, | |||||
| midiEvent.frame, | |||||
| midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data, | |||||
| midiEvent.size) == 0; | |||||
| } | |||||
| #endif | |||||
| // NOTE: no trigger support for JACK, simulate it here | |||||
| void updateParameterTriggers() | |||||
| { | |||||
| float defValue; | |||||
| for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||||
| { | |||||
| if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) != kParameterIsTrigger) | |||||
| continue; | |||||
| defValue = fPlugin.getParameterRanges(i).def; | |||||
| if (d_isNotEqual(defValue, fPlugin.getParameterValue(i))) | |||||
| fPlugin.setParameterValue(i, defValue); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| private: | private: | ||||
| @@ -457,6 +518,10 @@ private: | |||||
| jack_port_t* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; | jack_port_t* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; | ||||
| #endif | #endif | ||||
| jack_port_t* fPortEventsIn; | jack_port_t* fPortEventsIn; | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| jack_port_t* fPortMidiOut; | |||||
| void* fPortMidiOutBuffer; | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_TIMEPOS | #if DISTRHO_PLUGIN_WANT_TIMEPOS | ||||
| TimePosition fTimePosition; | TimePosition fTimePosition; | ||||
| #endif | #endif | ||||
| @@ -475,51 +540,58 @@ private: | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Callbacks | // Callbacks | ||||
| #define uiPtr ((PluginJack*)ptr) | |||||
| #define thisPtr ((PluginJack*)ptr) | |||||
| static int jackBufferSizeCallback(jack_nframes_t nframes, void* ptr) | static int jackBufferSizeCallback(jack_nframes_t nframes, void* ptr) | ||||
| { | { | ||||
| uiPtr->jackBufferSize(nframes); | |||||
| thisPtr->jackBufferSize(nframes); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int jackSampleRateCallback(jack_nframes_t nframes, void* ptr) | static int jackSampleRateCallback(jack_nframes_t nframes, void* ptr) | ||||
| { | { | ||||
| uiPtr->jackSampleRate(nframes); | |||||
| thisPtr->jackSampleRate(nframes); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int jackProcessCallback(jack_nframes_t nframes, void* ptr) | static int jackProcessCallback(jack_nframes_t nframes, void* ptr) | ||||
| { | { | ||||
| uiPtr->jackProcess(nframes); | |||||
| thisPtr->jackProcess(nframes); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static void jackShutdownCallback(void* ptr) | static void jackShutdownCallback(void* ptr) | ||||
| { | { | ||||
| uiPtr->jackShutdown(); | |||||
| thisPtr->jackShutdown(); | |||||
| } | } | ||||
| static void setParameterValueCallback(void* ptr, uint32_t index, float value) | static void setParameterValueCallback(void* ptr, uint32_t index, float value) | ||||
| { | { | ||||
| uiPtr->setParameterValue(index, value); | |||||
| thisPtr->setParameterValue(index, value); | |||||
| } | } | ||||
| #if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
| static void setStateCallback(void* ptr, const char* key, const char* value) | static void setStateCallback(void* ptr, const char* key, const char* value) | ||||
| { | { | ||||
| uiPtr->setState(key, value); | |||||
| thisPtr->setState(key, value); | |||||
| } | } | ||||
| #endif | #endif | ||||
| #if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
| static void setSizeCallback(void* ptr, uint width, uint height) | static void setSizeCallback(void* ptr, uint width, uint height) | ||||
| { | { | ||||
| uiPtr->setSize(width, height); | |||||
| thisPtr->setSize(width, height); | |||||
| } | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent) | |||||
| { | |||||
| return thisPtr->writeMidi(midiEvent); | |||||
| } | } | ||||
| #endif | #endif | ||||
| #undef uiPtr | |||||
| #undef thisPtr | |||||
| }; | }; | ||||
| END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
| @@ -22,9 +22,12 @@ | |||||
| #ifdef DISTRHO_PLUGIN_TARGET_DSSI | #ifdef DISTRHO_PLUGIN_TARGET_DSSI | ||||
| # include "dssi/dssi.h" | # include "dssi/dssi.h" | ||||
| # if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| # error DSSI does not support MIDI output | |||||
| # endif | |||||
| #else | #else | ||||
| # include "ladspa/ladspa.h" | # include "ladspa/ladspa.h" | ||||
| # if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| # if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| # error Cannot use MIDI with LADSPA | # error Cannot use MIDI with LADSPA | ||||
| # endif | # endif | ||||
| # if DISTRHO_PLUGIN_WANT_STATE | # if DISTRHO_PLUGIN_WANT_STATE | ||||
| @@ -44,7 +47,8 @@ class PluginLadspaDssi | |||||
| { | { | ||||
| public: | public: | ||||
| PluginLadspaDssi() | PluginLadspaDssi() | ||||
| : fPortControls(nullptr), | |||||
| : fPlugin(nullptr, nullptr), | |||||
| fPortControls(nullptr), | |||||
| fLastControlValues(nullptr) | fLastControlValues(nullptr) | ||||
| { | { | ||||
| #if DISTRHO_PLUGIN_NUM_INPUTS > 0 | #if DISTRHO_PLUGIN_NUM_INPUTS > 0 | ||||
| @@ -171,7 +175,7 @@ public: | |||||
| { | { | ||||
| // pre-roll | // pre-roll | ||||
| if (sampleCount == 0) | if (sampleCount == 0) | ||||
| return updateParameterOutputs(); | |||||
| return updateParameterOutputsAndTriggers(); | |||||
| // Check for updated parameters | // Check for updated parameters | ||||
| float curValue; | float curValue; | ||||
| @@ -183,7 +187,7 @@ public: | |||||
| curValue = *fPortControls[i]; | curValue = *fPortControls[i]; | ||||
| if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i)) | |||||
| if (fPlugin.isParameterInput(i) && d_isNotEqual(fLastControlValues[i], curValue)) | |||||
| { | { | ||||
| fLastControlValues[i] = curValue; | fLastControlValues[i] = curValue; | ||||
| fPlugin.setParameterValue(i, curValue); | fPlugin.setParameterValue(i, curValue); | ||||
| @@ -268,7 +272,7 @@ public: | |||||
| fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); | fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); | ||||
| #endif | #endif | ||||
| updateParameterOutputs(); | |||||
| updateParameterOutputsAndTriggers(); | |||||
| #if defined(DISTRHO_PLUGIN_TARGET_DSSI) && ! DISTRHO_PLUGIN_WANT_MIDI_INPUT | #if defined(DISTRHO_PLUGIN_TARGET_DSSI) && ! DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
| return; // unused | return; // unused | ||||
| @@ -371,17 +375,33 @@ private: | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| void updateParameterOutputs() | |||||
| void updateParameterOutputsAndTriggers() | |||||
| { | { | ||||
| float value; | |||||
| for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | ||||
| { | { | ||||
| if (! fPlugin.isParameterOutput(i)) | |||||
| continue; | |||||
| if (fPlugin.isParameterOutput(i)) | |||||
| { | |||||
| value = fLastControlValues[i] = fPlugin.getParameterValue(i); | |||||
| fLastControlValues[i] = fPlugin.getParameterValue(i); | |||||
| if (fPortControls[i] != nullptr) | |||||
| *fPortControls[i] = value; | |||||
| } | |||||
| else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger) | |||||
| { | |||||
| // NOTE: no trigger support in LADSPA control ports, simulate it here | |||||
| value = fPlugin.getParameterRanges(i).def; | |||||
| if (fPortControls[i] != nullptr) | |||||
| *fPortControls[i] = fLastControlValues[i]; | |||||
| if (d_isEqual(value, fPlugin.getParameterValue(i))) | |||||
| continue; | |||||
| fLastControlValues[i] = value; | |||||
| fPlugin.setParameterValue(i, value); | |||||
| if (fPortControls[i] != nullptr) | |||||
| *fPortControls[i] = value; | |||||
| } | |||||
| } | } | ||||
| #if DISTRHO_PLUGIN_WANT_LATENCY | #if DISTRHO_PLUGIN_WANT_LATENCY | ||||
| @@ -531,7 +551,7 @@ public: | |||||
| // Create dummy plugin to get data from | // Create dummy plugin to get data from | ||||
| d_lastBufferSize = 512; | d_lastBufferSize = 512; | ||||
| d_lastSampleRate = 44100.0; | d_lastSampleRate = 44100.0; | ||||
| PluginExporter plugin; | |||||
| PluginExporter plugin(nullptr, nullptr); | |||||
| d_lastBufferSize = 0; | d_lastBufferSize = 0; | ||||
| d_lastSampleRate = 0.0; | d_lastSampleRate = 0.0; | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
| @@ -32,7 +32,7 @@ | |||||
| #include "lv2/lv2_programs.h" | #include "lv2/lv2_programs.h" | ||||
| #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD | #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD | ||||
| # include "libmodauth.h" | |||||
| # include "libmodla.h" | |||||
| #endif | #endif | ||||
| #ifdef noexcept | #ifdef noexcept | ||||
| @@ -56,13 +56,18 @@ START_NAMESPACE_DISTRHO | |||||
| typedef std::map<const String, String> StringMap; | typedef std::map<const String, String> StringMap; | ||||
| #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| static const writeMidiFunc writeMidiCallback = nullptr; | |||||
| #endif | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| class PluginLv2 | class PluginLv2 | ||||
| { | { | ||||
| public: | public: | ||||
| PluginLv2(const double sampleRate, const LV2_URID_Map* const uridMap, const LV2_Worker_Schedule* const worker, const bool usingNominal) | PluginLv2(const double sampleRate, const LV2_URID_Map* const uridMap, const LV2_Worker_Schedule* const worker, const bool usingNominal) | ||||
| : fUsingNominal(usingNominal), | |||||
| : fPlugin(this, writeMidiCallback), | |||||
| fUsingNominal(usingNominal), | |||||
| #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD | #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD | ||||
| fRunCount(0), | fRunCount(0), | ||||
| #endif | #endif | ||||
| @@ -107,9 +112,6 @@ public: | |||||
| #if DISTRHO_LV2_USE_EVENTS_IN | #if DISTRHO_LV2_USE_EVENTS_IN | ||||
| fPortEventsIn = nullptr; | fPortEventsIn = nullptr; | ||||
| #endif | #endif | ||||
| #if DISTRHO_LV2_USE_EVENTS_OUT | |||||
| fPortEventsOut = nullptr; | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_LATENCY | #if DISTRHO_PLUGIN_WANT_LATENCY | ||||
| fPortLatency = nullptr; | fPortLatency = nullptr; | ||||
| #endif | #endif | ||||
| @@ -226,7 +228,7 @@ public: | |||||
| #if DISTRHO_LV2_USE_EVENTS_OUT | #if DISTRHO_LV2_USE_EVENTS_OUT | ||||
| if (port == index++) | if (port == index++) | ||||
| { | { | ||||
| fPortEventsOut = (LV2_Atom_Sequence*)dataLocation; | |||||
| fEventsOutData.port = (LV2_Atom_Sequence*)dataLocation; | |||||
| return; | return; | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -517,14 +519,12 @@ public: | |||||
| curValue = *fPortControls[i]; | curValue = *fPortControls[i]; | ||||
| if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i)) | |||||
| if (fPlugin.isParameterInput(i) && d_isNotEqual(fLastControlValues[i], curValue)) | |||||
| { | { | ||||
| fLastControlValues[i] = curValue; | fLastControlValues[i] = curValue; | ||||
| if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass) | if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass) | ||||
| { | |||||
| curValue = 1.0f - curValue; | curValue = 1.0f - curValue; | ||||
| } | |||||
| fPlugin.setParameterValue(i, curValue); | fPlugin.setParameterValue(i, curValue); | ||||
| } | } | ||||
| @@ -607,20 +607,14 @@ public: | |||||
| #endif | #endif | ||||
| } | } | ||||
| updateParameterOutputs(); | |||||
| updateParameterOutputsAndTriggers(); | |||||
| #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI | ||||
| const uint32_t capacity = fPortEventsOut->atom.size; | |||||
| fEventsOutData.initIfNeeded(fURIDs.atomSequence); | |||||
| uint32_t size, offset = 0; | |||||
| LV2_Atom_Event* aev; | LV2_Atom_Event* aev; | ||||
| fPortEventsOut->atom.size = sizeof(LV2_Atom_Sequence_Body); | |||||
| fPortEventsOut->atom.type = fURIDs.atomSequence; | |||||
| fPortEventsOut->body.unit = 0; | |||||
| fPortEventsOut->body.pad = 0; | |||||
| // TODO - MIDI Output | |||||
| uint32_t offset = fEventsOutData.offset; | |||||
| const uint32_t capacity = fEventsOutData.capacity; | |||||
| for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | ||||
| { | { | ||||
| @@ -645,6 +639,7 @@ public: | |||||
| break; | break; | ||||
| // reserve msg space | // reserve msg space | ||||
| // FIXME create a large enough buffer beforehand | |||||
| char msgBuf[msgSize]; | char msgBuf[msgSize]; | ||||
| std::memset(msgBuf, 0, msgSize); | std::memset(msgBuf, 0, msgSize); | ||||
| @@ -653,21 +648,23 @@ public: | |||||
| std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()); | std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()); | ||||
| // put data | // put data | ||||
| aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fPortEventsOut) + offset); | |||||
| aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + offset); | |||||
| aev->time.frames = 0; | aev->time.frames = 0; | ||||
| aev->body.type = fURIDs.distrhoState; | aev->body.type = fURIDs.distrhoState; | ||||
| aev->body.size = msgSize; | aev->body.size = msgSize; | ||||
| std::memcpy(LV2_ATOM_BODY(&aev->body), msgBuf, msgSize-1); | std::memcpy(LV2_ATOM_BODY(&aev->body), msgBuf, msgSize-1); | ||||
| size = lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize); | |||||
| offset += size; | |||||
| fPortEventsOut->atom.size += size; | |||||
| fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize)); | |||||
| fNeededUiSends[i] = false; | fNeededUiSends[i] = false; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| #if DISTRHO_LV2_USE_EVENTS_OUT | |||||
| fEventsOutData.endRun(); | |||||
| #endif | |||||
| } | } | ||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -883,9 +880,6 @@ private: | |||||
| #if DISTRHO_LV2_USE_EVENTS_IN | #if DISTRHO_LV2_USE_EVENTS_IN | ||||
| LV2_Atom_Sequence* fPortEventsIn; | LV2_Atom_Sequence* fPortEventsIn; | ||||
| #endif | #endif | ||||
| #if DISTRHO_LV2_USE_EVENTS_OUT | |||||
| LV2_Atom_Sequence* fPortEventsOut; | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_LATENCY | #if DISTRHO_PLUGIN_WANT_LATENCY | ||||
| float* fPortLatency; | float* fPortLatency; | ||||
| #endif | #endif | ||||
| @@ -922,6 +916,44 @@ private: | |||||
| } fLastPositionData; | } fLastPositionData; | ||||
| #endif | #endif | ||||
| #if DISTRHO_LV2_USE_EVENTS_OUT | |||||
| struct Lv2EventsOutData { | |||||
| uint32_t capacity, offset; | |||||
| LV2_Atom_Sequence* port; | |||||
| Lv2EventsOutData() | |||||
| : capacity(0), | |||||
| offset(0), | |||||
| port(nullptr) {} | |||||
| void initIfNeeded(const LV2_URID uridAtomSequence) | |||||
| { | |||||
| if (capacity != 0) | |||||
| return; | |||||
| capacity = port->atom.size; | |||||
| port->atom.size = sizeof(LV2_Atom_Sequence_Body); | |||||
| port->atom.type = uridAtomSequence; | |||||
| port->body.unit = 0; | |||||
| port->body.pad = 0; | |||||
| } | |||||
| void growBy(const uint32_t size) | |||||
| { | |||||
| offset += size; | |||||
| port->atom.size += size; | |||||
| } | |||||
| void endRun() | |||||
| { | |||||
| capacity = 0; | |||||
| offset = 0; | |||||
| } | |||||
| } fEventsOutData; | |||||
| #endif | |||||
| // LV2 URIDs | // LV2 URIDs | ||||
| struct URIDs { | struct URIDs { | ||||
| LV2_URID atomBlank; | LV2_URID atomBlank; | ||||
| @@ -998,17 +1030,23 @@ private: | |||||
| } | } | ||||
| #endif | #endif | ||||
| void updateParameterOutputs() | |||||
| void updateParameterOutputsAndTriggers() | |||||
| { | { | ||||
| float curValue; | |||||
| for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | ||||
| { | { | ||||
| if (! fPlugin.isParameterOutput(i)) | |||||
| continue; | |||||
| fLastControlValues[i] = fPlugin.getParameterValue(i); | |||||
| if (fPlugin.isParameterOutput(i)) | |||||
| { | |||||
| curValue = fLastControlValues[i] = fPlugin.getParameterValue(i); | |||||
| if (fPortControls[i] != nullptr) | |||||
| *fPortControls[i] = fLastControlValues[i]; | |||||
| if (fPortControls[i] != nullptr) | |||||
| *fPortControls[i] = curValue; | |||||
| } | |||||
| else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger) | |||||
| { | |||||
| // NOTE: host is responsible for auto-updating control port buffers | |||||
| } | |||||
| } | } | ||||
| #if DISTRHO_PLUGIN_WANT_LATENCY | #if DISTRHO_PLUGIN_WANT_LATENCY | ||||
| @@ -1016,6 +1054,38 @@ private: | |||||
| *fPortLatency = fPlugin.getLatency(); | *fPortLatency = fPlugin.getLatency(); | ||||
| #endif | #endif | ||||
| } | } | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| bool writeMidi(const MidiEvent& midiEvent) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fEventsOutData.port != nullptr, false); | |||||
| fEventsOutData.initIfNeeded(fURIDs.atomSequence); | |||||
| const uint32_t capacity = fEventsOutData.capacity; | |||||
| const uint32_t offset = fEventsOutData.offset; | |||||
| if (sizeof(LV2_Atom_Event) + midiEvent.size > capacity - offset) | |||||
| return false; | |||||
| LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + offset); | |||||
| aev->time.frames = midiEvent.frame; | |||||
| aev->body.type = fURIDs.midiEvent; | |||||
| aev->body.size = midiEvent.size; | |||||
| std::memcpy(LV2_ATOM_BODY(&aev->body), | |||||
| midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data, | |||||
| midiEvent.size); | |||||
| fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + midiEvent.size)); | |||||
| return true; | |||||
| } | |||||
| static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent) | |||||
| { | |||||
| return ((PluginLv2*)ptr)->writeMidi(midiEvent); | |||||
| } | |||||
| #endif | |||||
| }; | }; | ||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -1057,7 +1127,7 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons | |||||
| #endif | #endif | ||||
| #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD | #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD | ||||
| mod_check_license(features, DISTRHO_PLUGIN_URI); | |||||
| mod_license_check(features, DISTRHO_PLUGIN_URI); | |||||
| #endif | #endif | ||||
| d_lastBufferSize = 0; | d_lastBufferSize = 0; | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
| @@ -80,7 +80,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
| // Dummy plugin to get data from | // Dummy plugin to get data from | ||||
| d_lastBufferSize = 512; | d_lastBufferSize = 512; | ||||
| d_lastSampleRate = 44100.0; | d_lastSampleRate = 44100.0; | ||||
| PluginExporter plugin; | |||||
| PluginExporter plugin(nullptr, nullptr); | |||||
| d_lastBufferSize = 0; | d_lastBufferSize = 0; | ||||
| d_lastSampleRate = 0.0; | d_lastSampleRate = 0.0; | ||||
| @@ -202,6 +202,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
| pluginString += "@prefix mod: <http://moddevices.com/ns/mod#> .\n"; | pluginString += "@prefix mod: <http://moddevices.com/ns/mod#> .\n"; | ||||
| #endif | #endif | ||||
| pluginString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | pluginString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | ||||
| pluginString += "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"; | |||||
| pluginString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | pluginString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | ||||
| pluginString += "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n"; | pluginString += "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n"; | ||||
| #if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
| @@ -398,7 +399,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
| bool designated = false; | bool designated = false; | ||||
| // designation | // designation | ||||
| if (! plugin.isParameterOutput(i)) | |||||
| if (plugin.isParameterInput(i)) | |||||
| { | { | ||||
| switch (plugin.getParameterDesignation(i)) | switch (plugin.getParameterDesignation(i)) | ||||
| { | { | ||||
| @@ -417,10 +418,10 @@ void lv2_generate_ttl(const char* const basename) | |||||
| } | } | ||||
| } | } | ||||
| // name and symbol | |||||
| if (! designated) | if (! designated) | ||||
| { | { | ||||
| pluginString += " lv2:name \"" + plugin.getParameterName(i) + "\" ;\n"; | |||||
| // name and symbol | |||||
| pluginString += " lv2:name \"\"\"" + plugin.getParameterName(i) + "\"\"\" ;\n"; | |||||
| String symbol(plugin.getParameterSymbol(i)); | String symbol(plugin.getParameterSymbol(i)); | ||||
| @@ -428,32 +429,53 @@ void lv2_generate_ttl(const char* const basename) | |||||
| symbol = "lv2_port_" + String(portIndex-1); | symbol = "lv2_port_" + String(portIndex-1); | ||||
| pluginString += " lv2:symbol \"" + symbol + "\" ;\n"; | pluginString += " lv2:symbol \"" + symbol + "\" ;\n"; | ||||
| } | |||||
| // ranges | |||||
| if (! designated) | |||||
| { | |||||
| // ranges | |||||
| const ParameterRanges& ranges(plugin.getParameterRanges(i)); | const ParameterRanges& ranges(plugin.getParameterRanges(i)); | ||||
| if (plugin.getParameterHints(i) & kParameterIsInteger) | if (plugin.getParameterHints(i) & kParameterIsInteger) | ||||
| { | { | ||||
| if (! plugin.isParameterOutput(i)) | |||||
| if (plugin.isParameterInput(i)) | |||||
| pluginString += " lv2:default " + String(int(plugin.getParameterValue(i))) + " ;\n"; | pluginString += " lv2:default " + String(int(plugin.getParameterValue(i))) + " ;\n"; | ||||
| pluginString += " lv2:minimum " + String(int(ranges.min)) + " ;\n"; | pluginString += " lv2:minimum " + String(int(ranges.min)) + " ;\n"; | ||||
| pluginString += " lv2:maximum " + String(int(ranges.max)) + " ;\n"; | pluginString += " lv2:maximum " + String(int(ranges.max)) + " ;\n"; | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| if (! plugin.isParameterOutput(i)) | |||||
| if (plugin.isParameterInput(i)) | |||||
| pluginString += " lv2:default " + String(plugin.getParameterValue(i)) + " ;\n"; | pluginString += " lv2:default " + String(plugin.getParameterValue(i)) + " ;\n"; | ||||
| pluginString += " lv2:minimum " + String(ranges.min) + " ;\n"; | pluginString += " lv2:minimum " + String(ranges.min) + " ;\n"; | ||||
| pluginString += " lv2:maximum " + String(ranges.max) + " ;\n"; | pluginString += " lv2:maximum " + String(ranges.max) + " ;\n"; | ||||
| } | } | ||||
| } | |||||
| // unit | |||||
| if (! designated) | |||||
| { | |||||
| // enumeration | |||||
| const ParameterEnumerationValues& enumValues(plugin.getParameterEnumValues(i)); | |||||
| if (enumValues.count > 0) | |||||
| { | |||||
| if (enumValues.count >= 2 && enumValues.restrictedMode) | |||||
| pluginString += " lv2:portProperty lv2:enumeration ;\n"; | |||||
| for (uint8_t j=0; j < enumValues.count; ++j) | |||||
| { | |||||
| const ParameterEnumerationValue& enumValue(enumValues.values[j]); | |||||
| if (j == 0) | |||||
| pluginString += " lv2:scalePoint [\n"; | |||||
| else | |||||
| pluginString += " [\n"; | |||||
| pluginString += " rdfs:label \"\"\"" + enumValue.label + "\"\"\" ;\n"; | |||||
| pluginString += " rdf:value " + String(enumValue.value) + " ;\n"; | |||||
| if (j+1 == enumValues.count) | |||||
| pluginString += " ] ;\n\n"; | |||||
| else | |||||
| pluginString += " ] ,\n"; | |||||
| } | |||||
| } | |||||
| // unit | |||||
| const String& unit(plugin.getParameterUnit(i)); | const String& unit(plugin.getParameterUnit(i)); | ||||
| if (! unit.isEmpty()) | if (! unit.isEmpty()) | ||||
| @@ -495,25 +517,26 @@ void lv2_generate_ttl(const char* const basename) | |||||
| pluginString += " ] ;\n"; | pluginString += " ] ;\n"; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| // hints | |||||
| if (! designated) | |||||
| { | |||||
| // hints | |||||
| const uint32_t hints(plugin.getParameterHints(i)); | const uint32_t hints(plugin.getParameterHints(i)); | ||||
| if (hints & kParameterIsBoolean) | if (hints & kParameterIsBoolean) | ||||
| { | |||||
| if ((hints & kParameterIsTrigger) == kParameterIsTrigger) | |||||
| pluginString += " lv2:portProperty <" LV2_PORT_PROPS__trigger "> ;\n"; | |||||
| pluginString += " lv2:portProperty lv2:toggled ;\n"; | pluginString += " lv2:portProperty lv2:toggled ;\n"; | ||||
| } | |||||
| if (hints & kParameterIsInteger) | if (hints & kParameterIsInteger) | ||||
| pluginString += " lv2:portProperty lv2:integer ;\n"; | pluginString += " lv2:portProperty lv2:integer ;\n"; | ||||
| if (hints & kParameterIsLogarithmic) | if (hints & kParameterIsLogarithmic) | ||||
| pluginString += " lv2:portProperty <" LV2_PORT_PROPS__logarithmic "> ;\n"; | pluginString += " lv2:portProperty <" LV2_PORT_PROPS__logarithmic "> ;\n"; | ||||
| if ((hints & kParameterIsAutomable) == 0 && ! plugin.isParameterOutput(i)) | |||||
| if ((hints & kParameterIsAutomable) == 0 && plugin.isParameterInput(i)) | |||||
| { | { | ||||
| pluginString += " lv2:portProperty <" LV2_PORT_PROPS__expensive "> ,\n"; | pluginString += " lv2:portProperty <" LV2_PORT_PROPS__expensive "> ,\n"; | ||||
| pluginString += " <" LV2_KXSTUDIO_PROPERTIES__NonAutomable "> ;\n"; | pluginString += " <" LV2_KXSTUDIO_PROPERTIES__NonAutomable "> ;\n"; | ||||
| } | } | ||||
| } | |||||
| } // ! designated | |||||
| if (i+1 == count) | if (i+1 == count) | ||||
| pluginString += " ] ;\n\n"; | pluginString += " ] ;\n\n"; | ||||
| @@ -537,7 +560,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
| #endif | #endif | ||||
| // name | // name | ||||
| pluginString += " doap:name \"" + String(plugin.getName()) + "\" ;\n"; | |||||
| pluginString += " doap:name \"\"\"" + String(plugin.getName()) + "\"\"\" ;\n"; | |||||
| // license | // license | ||||
| { | { | ||||
| @@ -546,7 +569,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
| if (license.contains("://")) | if (license.contains("://")) | ||||
| pluginString += " doap:license <" + license + "> ;\n\n"; | pluginString += " doap:license <" + license + "> ;\n\n"; | ||||
| else | else | ||||
| pluginString += " doap:license \"" + license + "\" ;\n\n"; | |||||
| pluginString += " doap:license \"\"\"" + license + "\"\"\" ;\n\n"; | |||||
| } | } | ||||
| // developer | // developer | ||||
| @@ -554,7 +577,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
| const String homepage(plugin.getHomePage()); | const String homepage(plugin.getHomePage()); | ||||
| pluginString += " doap:maintainer [\n"; | pluginString += " doap:maintainer [\n"; | ||||
| pluginString += " foaf:name \"" + String(plugin.getMaker()) + "\" ;\n"; | |||||
| pluginString += " foaf:name \"\"\"" + String(plugin.getMaker()) + "\"\"\" ;\n"; | |||||
| if (homepage.isNotEmpty()) | if (homepage.isNotEmpty()) | ||||
| pluginString += " foaf:homepage <" + homepage + "> ;\n"; | pluginString += " foaf:homepage <" + homepage + "> ;\n"; | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
| @@ -37,11 +37,12 @@ | |||||
| #define VESTIGE_HEADER | #define VESTIGE_HEADER | ||||
| #define VST_FORCE_DEPRECATED 0 | #define VST_FORCE_DEPRECATED 0 | ||||
| #include <clocale> | |||||
| #include <map> | #include <map> | ||||
| #include <string> | #include <string> | ||||
| #ifdef VESTIGE_HEADER | #ifdef VESTIGE_HEADER | ||||
| # include "vestige/aeffectx.h" | |||||
| # include "vestige/vestige.h" | |||||
| #define effFlagsProgramChunks (1 << 5) | #define effFlagsProgramChunks (1 << 5) | ||||
| #define effSetProgramName 4 | #define effSetProgramName 4 | ||||
| #define effGetParamLabel 6 | #define effGetParamLabel 6 | ||||
| @@ -51,11 +52,8 @@ | |||||
| #define effCanBeAutomated 26 | #define effCanBeAutomated 26 | ||||
| #define effGetProgramNameIndexed 29 | #define effGetProgramNameIndexed 29 | ||||
| #define effGetPlugCategory 35 | #define effGetPlugCategory 35 | ||||
| #define effIdle 53 | |||||
| #define effEditKeyDown 59 | #define effEditKeyDown 59 | ||||
| #define effEditKeyUp 60 | #define effEditKeyUp 60 | ||||
| #define kPlugCategEffect 1 | |||||
| #define kPlugCategSynth 2 | |||||
| #define kVstVersion 2400 | #define kVstVersion 2400 | ||||
| struct ERect { | struct ERect { | ||||
| int16_t top, left, bottom, right; | int16_t top, left, bottom, right; | ||||
| @@ -68,6 +66,12 @@ START_NAMESPACE_DISTRHO | |||||
| typedef std::map<const String, String> StringMap; | typedef std::map<const String, String> StringMap; | ||||
| static const int kVstMidiEventSize = static_cast<int>(sizeof(VstMidiEvent)); | |||||
| #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| static const writeMidiFunc writeMidiCallback = nullptr; | |||||
| #endif | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| void strncpy(char* const dst, const char* const src, const size_t size) | void strncpy(char* const dst, const char* const src, const size_t size) | ||||
| @@ -88,17 +92,42 @@ void snprintf_iparam(char* const dst, const int32_t value, const size_t size) | |||||
| dst[size-1] = '\0'; | dst[size-1] = '\0'; | ||||
| } | } | ||||
| #if DISTRHO_PLUGIN_HAS_UI | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| class UiHelper | |||||
| class ScopedSafeLocale { | |||||
| public: | |||||
| ScopedSafeLocale() noexcept | |||||
| : locale(::strdup(::setlocale(LC_NUMERIC, nullptr))) | |||||
| { | |||||
| ::setlocale(LC_NUMERIC, "C"); | |||||
| } | |||||
| ~ScopedSafeLocale() noexcept | |||||
| { | |||||
| if (locale != nullptr) | |||||
| { | |||||
| ::setlocale(LC_NUMERIC, locale); | |||||
| std::free(locale); | |||||
| } | |||||
| } | |||||
| private: | |||||
| char* const locale; | |||||
| DISTRHO_DECLARE_NON_COPY_CLASS(ScopedSafeLocale) | |||||
| DISTRHO_PREVENT_HEAP_ALLOCATION | |||||
| }; | |||||
| // ----------------------------------------------------------------------- | |||||
| class ParameterCheckHelper | |||||
| { | { | ||||
| public: | public: | ||||
| UiHelper() | |||||
| ParameterCheckHelper() | |||||
| : parameterChecks(nullptr), | : parameterChecks(nullptr), | ||||
| parameterValues(nullptr) {} | parameterValues(nullptr) {} | ||||
| virtual ~UiHelper() | |||||
| virtual ~ParameterCheckHelper() | |||||
| { | { | ||||
| if (parameterChecks != nullptr) | if (parameterChecks != nullptr) | ||||
| { | { | ||||
| @@ -112,20 +141,21 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| bool* parameterChecks; | |||||
| float* parameterValues; | |||||
| bool* parameterChecks; | |||||
| float* parameterValues; | |||||
| # if DISTRHO_PLUGIN_WANT_STATE | |||||
| #if DISTRHO_PLUGIN_WANT_STATE | |||||
| virtual void setStateFromUI(const char* const newKey, const char* const newValue) = 0; | virtual void setStateFromUI(const char* const newKey, const char* const newValue) = 0; | ||||
| # endif | |||||
| #endif | |||||
| }; | }; | ||||
| #if DISTRHO_PLUGIN_HAS_UI | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| class UIVst | class UIVst | ||||
| { | { | ||||
| public: | public: | ||||
| UIVst(const audioMasterCallback audioMaster, AEffect* const effect, UiHelper* const uiHelper, PluginExporter* const plugin, const intptr_t winId) | |||||
| UIVst(const audioMasterCallback audioMaster, AEffect* const effect, ParameterCheckHelper* const uiHelper, PluginExporter* const plugin, const intptr_t winId) | |||||
| : fAudioMaster(audioMaster), | : fAudioMaster(audioMaster), | ||||
| fEffect(effect), | fEffect(effect), | ||||
| fUiHelper(uiHelper), | fUiHelper(uiHelper), | ||||
| @@ -300,7 +330,7 @@ private: | |||||
| // Vst stuff | // Vst stuff | ||||
| const audioMasterCallback fAudioMaster; | const audioMasterCallback fAudioMaster; | ||||
| AEffect* const fEffect; | AEffect* const fEffect; | ||||
| UiHelper* const fUiHelper; | |||||
| ParameterCheckHelper* const fUiHelper; | |||||
| PluginExporter* const fPlugin; | PluginExporter* const fPlugin; | ||||
| // Plugin UI | // Plugin UI | ||||
| @@ -343,15 +373,12 @@ private: | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| #if DISTRHO_PLUGIN_HAS_UI | |||||
| class PluginVst : public UiHelper | |||||
| #else | |||||
| class PluginVst | |||||
| #endif | |||||
| class PluginVst : public ParameterCheckHelper | |||||
| { | { | ||||
| public: | public: | ||||
| PluginVst(const audioMasterCallback audioMaster, AEffect* const effect) | PluginVst(const audioMasterCallback audioMaster, AEffect* const effect) | ||||
| : fAudioMaster(audioMaster), | |||||
| : fPlugin(this, writeMidiCallback), | |||||
| fAudioMaster(audioMaster), | |||||
| fEffect(effect) | fEffect(effect) | ||||
| { | { | ||||
| std::memset(fProgramName, 0, sizeof(char)*(32+1)); | std::memset(fProgramName, 0, sizeof(char)*(32+1)); | ||||
| @@ -376,14 +403,14 @@ public: | |||||
| for (uint32_t i=0; i < paramCount; ++i) | for (uint32_t i=0; i < paramCount; ++i) | ||||
| { | { | ||||
| parameterChecks[i] = false; | parameterChecks[i] = false; | ||||
| parameterValues[i] = 0.0f; | |||||
| parameterValues[i] = NAN; | |||||
| } | } | ||||
| } | } | ||||
| # if DISTRHO_OS_MAC | # if DISTRHO_OS_MAC | ||||
| # ifdef __LP64__ | # ifdef __LP64__ | ||||
| fUsingNsView = true; | fUsingNsView = true; | ||||
| # else | # else | ||||
| # warning 32bit VST UIs on OSX only work if the host supports "hasCockosViewAsConfig" | |||||
| # warning 32bit VST UIs on OSX only work if the host supports "hasCockosViewAsConfig" | |||||
| fUsingNsView = false; | fUsingNsView = false; | ||||
| # endif | # endif | ||||
| # endif // DISTRHO_OS_MAC | # endif // DISTRHO_OS_MAC | ||||
| @@ -453,24 +480,35 @@ public: | |||||
| { | { | ||||
| const uint32_t hints = fPlugin.getParameterHints(index); | const uint32_t hints = fPlugin.getParameterHints(index); | ||||
| float value = fPlugin.getParameterValue(index); | float value = fPlugin.getParameterValue(index); | ||||
| if (hints & kParameterIsBoolean) | if (hints & kParameterIsBoolean) | ||||
| { | { | ||||
| const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); | const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); | ||||
| const float midRange = ranges.min + (ranges.max - ranges.min) / 2.0f; | const float midRange = ranges.min + (ranges.max - ranges.min) / 2.0f; | ||||
| value = value > midRange ? ranges.max : ranges.min; | value = value > midRange ? ranges.max : ranges.min; | ||||
| } | } | ||||
| if (hints & kParameterIsInteger) | |||||
| else if (hints & kParameterIsInteger) | |||||
| { | { | ||||
| DISTRHO_NAMESPACE::snprintf_iparam((char*)ptr, (int32_t)std::round(value), 24); | |||||
| value = std::round(value); | |||||
| } | } | ||||
| else | |||||
| const ParameterEnumerationValues& enumValues(fPlugin.getParameterEnumValues(index)); | |||||
| for (uint8_t i = 0; i < enumValues.count; ++i) | |||||
| { | { | ||||
| DISTRHO_NAMESPACE::snprintf_param((char*)ptr, value, 24); | |||||
| if (d_isNotEqual(value, enumValues.values[i].value)) | |||||
| continue; | |||||
| DISTRHO_NAMESPACE::strncpy((char*)ptr, enumValues.values[i].label.buffer(), 24); | |||||
| return 1; | |||||
| } | } | ||||
| if (hints & kParameterIsInteger) | |||||
| DISTRHO_NAMESPACE::snprintf_iparam((char*)ptr, (int32_t)value, 24); | |||||
| else | |||||
| DISTRHO_NAMESPACE::snprintf_param((char*)ptr, value, 24); | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| break; | break; | ||||
| @@ -607,6 +645,7 @@ public: | |||||
| #if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
| case effGetChunk: | case effGetChunk: | ||||
| { | |||||
| if (ptr == nullptr) | if (ptr == nullptr) | ||||
| return 0; | return 0; | ||||
| @@ -616,7 +655,9 @@ public: | |||||
| fStateChunk = nullptr; | fStateChunk = nullptr; | ||||
| } | } | ||||
| if (fPlugin.getStateCount() == 0) | |||||
| const uint32_t paramCount = fPlugin.getParameterCount(); | |||||
| if (fPlugin.getStateCount() == 0 && paramCount == 0) | |||||
| { | { | ||||
| fStateChunk = new char[1]; | fStateChunk = new char[1]; | ||||
| fStateChunk[0] = '\0'; | fStateChunk[0] = '\0'; | ||||
| @@ -650,6 +691,30 @@ public: | |||||
| chunkStr += tmpStr; | chunkStr += tmpStr; | ||||
| } | } | ||||
| if (paramCount != 0) | |||||
| { | |||||
| // add another separator | |||||
| chunkStr += "\xff"; | |||||
| // temporarily set locale to "C" while converting floats | |||||
| const ScopedSafeLocale ssl; | |||||
| for (uint32_t i=0; i<paramCount; ++i) | |||||
| { | |||||
| if (fPlugin.isParameterOutputOrTrigger(i)) | |||||
| continue; | |||||
| // join key and value | |||||
| String tmpStr; | |||||
| tmpStr = fPlugin.getParameterSymbol(i); | |||||
| tmpStr += "\xff"; | |||||
| tmpStr += String(fPlugin.getParameterValue(i)); | |||||
| tmpStr += "\xff"; | |||||
| chunkStr += tmpStr; | |||||
| } | |||||
| } | |||||
| const std::size_t chunkSize(chunkStr.length()+1); | const std::size_t chunkSize(chunkStr.length()+1); | ||||
| fStateChunk = new char[chunkSize]; | fStateChunk = new char[chunkSize]; | ||||
| @@ -667,21 +732,27 @@ public: | |||||
| *(void**)ptr = fStateChunk; | *(void**)ptr = fStateChunk; | ||||
| return ret; | return ret; | ||||
| } | |||||
| case effSetChunk: | case effSetChunk: | ||||
| { | { | ||||
| if (value <= 1 || ptr == nullptr) | if (value <= 1 || ptr == nullptr) | ||||
| return 0; | return 0; | ||||
| const size_t chunkSize = static_cast<size_t>(value); | |||||
| const char* key = (const char*)ptr; | const char* key = (const char*)ptr; | ||||
| const char* value = nullptr; | const char* value = nullptr; | ||||
| size_t size, bytesRead = 0; | |||||
| for (;;) | |||||
| while (bytesRead < chunkSize) | |||||
| { | { | ||||
| if (key[0] == '\0') | if (key[0] == '\0') | ||||
| break; | break; | ||||
| value = key+(std::strlen(key)+1); | |||||
| size = std::strlen(key)+1; | |||||
| value = key + size; | |||||
| bytesRead += size; | |||||
| setStateFromUI(key, value); | setStateFromUI(key, value); | ||||
| @@ -691,7 +762,52 @@ public: | |||||
| # endif | # endif | ||||
| // get next key | // get next key | ||||
| key = value+(std::strlen(value)+1); | |||||
| size = std::strlen(value)+1; | |||||
| key = value + size; | |||||
| bytesRead += size; | |||||
| } | |||||
| const uint32_t paramCount = fPlugin.getParameterCount(); | |||||
| if (bytesRead+4 < chunkSize && paramCount != 0) | |||||
| { | |||||
| ++key; | |||||
| float fvalue; | |||||
| // temporarily set locale to "C" while converting floats | |||||
| const ScopedSafeLocale ssl; | |||||
| while (bytesRead < chunkSize) | |||||
| { | |||||
| if (key[0] == '\0') | |||||
| break; | |||||
| size = std::strlen(key)+1; | |||||
| value = key + size; | |||||
| bytesRead += size; | |||||
| // find parameter with this symbol, and set its value | |||||
| for (uint32_t i=0; i<paramCount; ++i) | |||||
| { | |||||
| if (fPlugin.isParameterOutputOrTrigger(i)) | |||||
| continue; | |||||
| if (fPlugin.getParameterSymbol(i) != key) | |||||
| continue; | |||||
| fvalue = std::atof(value); | |||||
| fPlugin.setParameterValue(i, fvalue); | |||||
| # if DISTRHO_PLUGIN_HAS_UI | |||||
| if (fVstUI != nullptr) | |||||
| setParameterValueFromPlugin(i, fvalue); | |||||
| # endif | |||||
| break; | |||||
| } | |||||
| // get next key | |||||
| size = std::strlen(value)+1; | |||||
| key = value + size; | |||||
| bytesRead += size; | |||||
| } | |||||
| } | } | ||||
| return 1; | return 1; | ||||
| @@ -805,7 +921,10 @@ public: | |||||
| void vst_processReplacing(const float** const inputs, float** const outputs, const int32_t sampleFrames) | void vst_processReplacing(const float** const inputs, float** const outputs, const int32_t sampleFrames) | ||||
| { | { | ||||
| if (sampleFrames <= 0) | if (sampleFrames <= 0) | ||||
| { | |||||
| updateParameterOutputsAndTriggers(); | |||||
| return; | return; | ||||
| } | |||||
| if (! fPlugin.isActive()) | if (! fPlugin.isActive()) | ||||
| { | { | ||||
| @@ -864,16 +983,7 @@ public: | |||||
| fPlugin.run(inputs, outputs, sampleFrames); | fPlugin.run(inputs, outputs, sampleFrames); | ||||
| #endif | #endif | ||||
| #if DISTRHO_PLUGIN_HAS_UI | |||||
| if (fVstUI == nullptr) | |||||
| return; | |||||
| for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||||
| { | |||||
| if (fPlugin.isParameterOutput(i)) | |||||
| setParameterValueFromPlugin(i, fPlugin.getParameterValue(i)); | |||||
| } | |||||
| #endif | |||||
| updateParameterOutputsAndTriggers(); | |||||
| } | } | ||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -881,13 +991,13 @@ public: | |||||
| friend class UIVst; | friend class UIVst; | ||||
| private: | private: | ||||
| // Plugin | |||||
| PluginExporter fPlugin; | |||||
| // VST stuff | // VST stuff | ||||
| const audioMasterCallback fAudioMaster; | const audioMasterCallback fAudioMaster; | ||||
| AEffect* const fEffect; | AEffect* const fEffect; | ||||
| // Plugin | |||||
| PluginExporter fPlugin; | |||||
| // Temporary data | // Temporary data | ||||
| char fProgramName[32+1]; | char fProgramName[32+1]; | ||||
| @@ -929,6 +1039,56 @@ private: | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // functions called from the plugin side, RT no block | // functions called from the plugin side, RT no block | ||||
| void updateParameterOutputsAndTriggers() | |||||
| { | |||||
| float curValue; | |||||
| for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||||
| { | |||||
| if (fPlugin.isParameterOutput(i)) | |||||
| { | |||||
| // NOTE: no output parameter support in VST, simulate it here | |||||
| curValue = fPlugin.getParameterValue(i); | |||||
| if (d_isEqual(curValue, parameterValues[i])) | |||||
| continue; | |||||
| #if DISTRHO_PLUGIN_HAS_UI | |||||
| if (fVstUI != nullptr) | |||||
| setParameterValueFromPlugin(i, curValue); | |||||
| else | |||||
| #endif | |||||
| parameterValues[i] = curValue; | |||||
| #ifndef DPF_VST_SHOW_PARAMETER_OUTPUTS | |||||
| // skip automating parameter outputs from plugin if we disable them on VST | |||||
| continue; | |||||
| #endif | |||||
| } | |||||
| else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger) | |||||
| { | |||||
| // NOTE: no trigger support in VST parameters, simulate it here | |||||
| curValue = fPlugin.getParameterValue(i); | |||||
| if (d_isEqual(curValue, fPlugin.getParameterRanges(i).def)) | |||||
| continue; | |||||
| #if DISTRHO_PLUGIN_HAS_UI | |||||
| if (fVstUI != nullptr) | |||||
| setParameterValueFromPlugin(i, curValue); | |||||
| #endif | |||||
| fPlugin.setParameterValue(i, curValue); | |||||
| } | |||||
| else | |||||
| { | |||||
| continue; | |||||
| } | |||||
| const ParameterRanges& ranges(fPlugin.getParameterRanges(i)); | |||||
| hostCallback(audioMasterAutomate, i, 0, nullptr, ranges.getNormalizedValue(curValue)); | |||||
| } | |||||
| } | |||||
| #if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
| void setParameterValueFromPlugin(const uint32_t index, const float realValue) | void setParameterValueFromPlugin(const uint32_t index, const float realValue) | ||||
| { | { | ||||
| @@ -937,6 +1097,37 @@ private: | |||||
| } | } | ||||
| #endif | #endif | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
| bool writeMidi(const MidiEvent& midiEvent) | |||||
| { | |||||
| if (midiEvent.size > 4) | |||||
| return true; | |||||
| VstEvents vstEvents; | |||||
| std::memset(&vstEvents, 0, sizeof(VstEvents)); | |||||
| VstMidiEvent vstMidiEvent; | |||||
| std::memset(&vstMidiEvent, 0, sizeof(VstMidiEvent)); | |||||
| vstEvents.numEvents = 1; | |||||
| vstEvents.events[0] = (VstEvent*)&vstMidiEvent; | |||||
| vstMidiEvent.type = kVstMidiType; | |||||
| vstMidiEvent.byteSize = kVstMidiEventSize; | |||||
| vstMidiEvent.deltaFrames = midiEvent.frame; | |||||
| for (uint8_t i=0; i<midiEvent.size; ++i) | |||||
| vstMidiEvent.midiData[i] = midiEvent.data[i]; | |||||
| return hostCallback(audioMasterProcessEvents, 0, 0, &vstEvents) == 1; | |||||
| } | |||||
| static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent) | |||||
| { | |||||
| return ((PluginVst*)ptr)->writeMidi(midiEvent); | |||||
| } | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // functions called from the UI side, may block | // functions called from the UI side, may block | ||||
| @@ -977,17 +1168,10 @@ struct VstObject { | |||||
| PluginVst* plugin; | PluginVst* plugin; | ||||
| }; | }; | ||||
| #ifdef VESTIGE_HEADER | |||||
| # define validObject effect != nullptr && effect->ptr3 != nullptr | |||||
| # define validPlugin effect != nullptr && effect->ptr3 != nullptr && ((VstObject*)effect->ptr3)->plugin != nullptr | |||||
| # define vstObjectPtr (VstObject*)effect->ptr3 | |||||
| #else | |||||
| # define validObject effect != nullptr && effect->object != nullptr | |||||
| # define validPlugin effect != nullptr && effect->object != nullptr && ((VstObject*)effect->object)->plugin != nullptr | |||||
| # define vstObjectPtr (VstObject*)effect->object | |||||
| #endif | |||||
| #define pluginPtr (vstObjectPtr)->plugin | |||||
| #define validObject effect != nullptr && effect->object != nullptr | |||||
| #define validPlugin effect != nullptr && effect->object != nullptr && ((VstObject*)effect->object)->plugin != nullptr | |||||
| #define vstObjectPtr (VstObject*)effect->object | |||||
| #define pluginPtr (vstObjectPtr)->plugin | |||||
| static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) | static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) | ||||
| { | { | ||||
| @@ -1002,7 +1186,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||||
| } | } | ||||
| // Create dummy plugin to get data from | // Create dummy plugin to get data from | ||||
| static PluginExporter plugin; | |||||
| static PluginExporter plugin(nullptr, nullptr); | |||||
| if (doInternalInit) | if (doInternalInit) | ||||
| { | { | ||||
| @@ -1055,11 +1239,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||||
| /* This code invalidates the object created in VSTPluginMain | /* This code invalidates the object created in VSTPluginMain | ||||
| * Probably not safe against all hosts */ | * Probably not safe against all hosts */ | ||||
| obj->audioMaster = nullptr; | obj->audioMaster = nullptr; | ||||
| # ifdef VESTIGE_HEADER | |||||
| effect->ptr3 = nullptr; | |||||
| # else | |||||
| vstObjectPtr = nullptr; | |||||
| # endif | |||||
| effect->object = nullptr; | |||||
| delete obj; | delete obj; | ||||
| #endif | #endif | ||||
| @@ -1083,14 +1263,14 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| case effGetParameterProperties: | case effGetParameterProperties: | ||||
| if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount())) | if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount())) | ||||
| { | { | ||||
| if (VstParameterProperties* const properties = (VstParameterProperties*)ptr) | if (VstParameterProperties* const properties = (VstParameterProperties*)ptr) | ||||
| { | { | ||||
| memset(properties, 0, sizeof(VstParameterProperties)); | memset(properties, 0, sizeof(VstParameterProperties)); | ||||
| const uint32_t hints = plugin.getParameterHints(index); | const uint32_t hints = plugin.getParameterHints(index); | ||||
| if (hints & kParameterIsOutput) | if (hints & kParameterIsOutput) | ||||
| @@ -1100,7 +1280,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||||
| { | { | ||||
| properties->flags |= kVstParameterIsSwitch; | properties->flags |= kVstParameterIsSwitch; | ||||
| } | } | ||||
| if (hints & kParameterIsInteger) | if (hints & kParameterIsInteger) | ||||
| { | { | ||||
| properties->flags |= kVstParameterUsesIntegerMinMax; | properties->flags |= kVstParameterUsesIntegerMinMax; | ||||
| @@ -1119,7 +1299,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||||
| } | } | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| case effGetPlugCategory: | case effGetPlugCategory: | ||||
| #if DISTRHO_PLUGIN_IS_SYNTH | #if DISTRHO_PLUGIN_IS_SYNTH | ||||
| return kPlugCategSynth; | return kPlugCategSynth; | ||||
| @@ -1226,20 +1406,18 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) | |||||
| // vst fields | // vst fields | ||||
| effect->magic = kEffectMagic; | effect->magic = kEffectMagic; | ||||
| effect->uniqueID = plugin->getUniqueId(); | effect->uniqueID = plugin->getUniqueId(); | ||||
| #ifdef VESTIGE_HEADER | |||||
| int32_t* const version = (int32_t*)&effect->unknown1; | |||||
| *version = plugin->getVersion(); | |||||
| #else | |||||
| effect->version = plugin->getVersion(); | |||||
| #endif | |||||
| effect->version = plugin->getVersion(); | |||||
| // VST doesn't support parameter outputs, hide them | |||||
| // VST doesn't support parameter outputs. we can fake them, but it is a hack. Disabled by default. | |||||
| #ifdef DPF_VST_SHOW_PARAMETER_OUTPUTS | |||||
| const int numParams = plugin->getParameterCount(); | |||||
| #else | |||||
| int numParams = 0; | int numParams = 0; | ||||
| bool outputsReached = false; | bool outputsReached = false; | ||||
| for (uint32_t i=0, count=plugin->getParameterCount(); i < count; ++i) | for (uint32_t i=0, count=plugin->getParameterCount(); i < count; ++i) | ||||
| { | { | ||||
| if (! plugin->isParameterOutput(i)) | |||||
| if (plugin->isParameterInput(i)) | |||||
| { | { | ||||
| // parameter outputs must be all at the end | // parameter outputs must be all at the end | ||||
| DISTRHO_SAFE_ASSERT_BREAK(! outputsReached); | DISTRHO_SAFE_ASSERT_BREAK(! outputsReached); | ||||
| @@ -1248,6 +1426,7 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) | |||||
| } | } | ||||
| outputsReached = true; | outputsReached = true; | ||||
| } | } | ||||
| #endif | |||||
| // plugin fields | // plugin fields | ||||
| effect->numParams = numParams; | effect->numParams = numParams; | ||||
| @@ -1278,11 +1457,9 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) | |||||
| VstObject* const obj(new VstObject()); | VstObject* const obj(new VstObject()); | ||||
| obj->audioMaster = audioMaster; | obj->audioMaster = audioMaster; | ||||
| obj->plugin = nullptr; | obj->plugin = nullptr; | ||||
| #ifdef VESTIGE_HEADER | |||||
| effect->ptr3 = obj; | |||||
| #else | |||||
| // done | |||||
| effect->object = obj; | effect->object = obj; | ||||
| #endif | |||||
| return effect; | return effect; | ||||
| } | } | ||||
| @@ -82,7 +82,7 @@ void UI::setState(const char* key, const char* value) | |||||
| } | } | ||||
| #endif | #endif | ||||
| #if DISTRHO_PLUGIN_IS_SYNTH | |||||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity) | void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity) | ||||
| { | { | ||||
| pData->sendNoteCallback(channel, note, velocity); | pData->sendNoteCallback(channel, note, velocity); | ||||
| @@ -26,6 +26,10 @@ | |||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| #if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| static const sendNoteFunc sendNoteCallback = nullptr; | |||||
| #endif | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| struct OscData { | struct OscData { | ||||
| @@ -180,6 +184,7 @@ protected: | |||||
| fOscData.send_configure(key, value); | fOscData.send_configure(key, value); | ||||
| } | } | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) | void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) | ||||
| { | { | ||||
| if (fOscData.server == nullptr) | if (fOscData.server == nullptr) | ||||
| @@ -187,11 +192,15 @@ protected: | |||||
| if (channel > 0xF) | if (channel > 0xF) | ||||
| return; | return; | ||||
| uint8_t mdata[4] = { 0, channel, note, velocity }; | |||||
| mdata[1] += (velocity != 0) ? 0x90 : 0x80; | |||||
| uint8_t mdata[4] = { | |||||
| 0, | |||||
| channel + (velocity != 0 ? 0x90 : 0x80), | |||||
| note, | |||||
| velocity | |||||
| }; | |||||
| fOscData.send_midi(mdata); | fOscData.send_midi(mdata); | ||||
| } | } | ||||
| #endif | |||||
| void setSize(const uint width, const uint height) | void setSize(const uint width, const uint height) | ||||
| { | { | ||||
| @@ -219,10 +228,12 @@ private: | |||||
| uiPtr->setState(key, value); | uiPtr->setState(key, value); | ||||
| } | } | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) | static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) | ||||
| { | { | ||||
| uiPtr->sendNote(channel, note, velocity); | uiPtr->sendNote(channel, note, velocity); | ||||
| } | } | ||||
| #endif | |||||
| static void setSizeCallback(void* ptr, uint width, uint height) | static void setSizeCallback(void* ptr, uint width, uint height) | ||||
| { | { | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
| @@ -61,12 +61,12 @@ struct UI::PrivateData { | |||||
| #endif | #endif | ||||
| // Callbacks | // Callbacks | ||||
| void* callbacksPtr; | |||||
| editParamFunc editParamCallbackFunc; | editParamFunc editParamCallbackFunc; | ||||
| setParamFunc setParamCallbackFunc; | setParamFunc setParamCallbackFunc; | ||||
| setStateFunc setStateCallbackFunc; | setStateFunc setStateCallbackFunc; | ||||
| sendNoteFunc sendNoteCallbackFunc; | sendNoteFunc sendNoteCallbackFunc; | ||||
| setSizeFunc setSizeCallbackFunc; | setSizeFunc setSizeCallbackFunc; | ||||
| void* ptr; | |||||
| PrivateData() noexcept | PrivateData() noexcept | ||||
| : sampleRate(d_lastUiSampleRate), | : sampleRate(d_lastUiSampleRate), | ||||
| @@ -74,12 +74,12 @@ struct UI::PrivateData { | |||||
| #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| dspPtr(d_lastUiDspPtr), | dspPtr(d_lastUiDspPtr), | ||||
| #endif | #endif | ||||
| callbacksPtr(nullptr), | |||||
| editParamCallbackFunc(nullptr), | editParamCallbackFunc(nullptr), | ||||
| setParamCallbackFunc(nullptr), | setParamCallbackFunc(nullptr), | ||||
| setStateCallbackFunc(nullptr), | setStateCallbackFunc(nullptr), | ||||
| sendNoteCallbackFunc(nullptr), | sendNoteCallbackFunc(nullptr), | ||||
| setSizeCallbackFunc(nullptr), | |||||
| ptr(nullptr) | |||||
| setSizeCallbackFunc(nullptr) | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate)); | DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate)); | ||||
| @@ -103,31 +103,31 @@ struct UI::PrivateData { | |||||
| void editParamCallback(const uint32_t rindex, const bool started) | void editParamCallback(const uint32_t rindex, const bool started) | ||||
| { | { | ||||
| if (editParamCallbackFunc != nullptr) | if (editParamCallbackFunc != nullptr) | ||||
| editParamCallbackFunc(ptr, rindex, started); | |||||
| editParamCallbackFunc(callbacksPtr, rindex, started); | |||||
| } | } | ||||
| void setParamCallback(const uint32_t rindex, const float value) | void setParamCallback(const uint32_t rindex, const float value) | ||||
| { | { | ||||
| if (setParamCallbackFunc != nullptr) | if (setParamCallbackFunc != nullptr) | ||||
| setParamCallbackFunc(ptr, rindex, value); | |||||
| setParamCallbackFunc(callbacksPtr, rindex, value); | |||||
| } | } | ||||
| void setStateCallback(const char* const key, const char* const value) | void setStateCallback(const char* const key, const char* const value) | ||||
| { | { | ||||
| if (setStateCallbackFunc != nullptr) | 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) | void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity) | ||||
| { | { | ||||
| if (sendNoteCallbackFunc != nullptr) | if (sendNoteCallbackFunc != nullptr) | ||||
| sendNoteCallbackFunc(ptr, channel, note, velocity); | |||||
| sendNoteCallbackFunc(callbacksPtr, channel, note, velocity); | |||||
| } | } | ||||
| void setSizeCallback(const uint width, const uint height) | void setSizeCallback(const uint width, const uint height) | ||||
| { | { | ||||
| if (setSizeCallbackFunc != nullptr) | 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 | class UIExporter | ||||
| { | { | ||||
| public: | 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, | void* const dspPtr = nullptr, | ||||
| const char* const bundlePath = nullptr) | const char* const bundlePath = nullptr) | ||||
| #ifdef HAVE_DGL | #ifdef HAVE_DGL | ||||
| @@ -238,7 +243,7 @@ public: | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | ||||
| fData->ptr = ptr; | |||||
| fData->callbacksPtr = callbacksPtr; | |||||
| fData->editParamCallbackFunc = editParamCall; | fData->editParamCallbackFunc = editParamCall; | ||||
| fData->setParamCallbackFunc = setParamCall; | fData->setParamCallbackFunc = setParamCall; | ||||
| fData->setStateCallbackFunc = setStateCall; | fData->setStateCallbackFunc = setStateCall; | ||||
| @@ -22,6 +22,7 @@ | |||||
| #include "lv2/atom-util.h" | #include "lv2/atom-util.h" | ||||
| #include "lv2/data-access.h" | #include "lv2/data-access.h" | ||||
| #include "lv2/instance-access.h" | #include "lv2/instance-access.h" | ||||
| #include "lv2/midi.h" | |||||
| #include "lv2/options.h" | #include "lv2/options.h" | ||||
| #include "lv2/parameters.h" | #include "lv2/parameters.h" | ||||
| #include "lv2/ui.h" | #include "lv2/ui.h" | ||||
| @@ -35,6 +36,15 @@ | |||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| typedef struct _LV2_Atom_MidiEvent { | |||||
| LV2_Atom atom; /**< Atom header. */ | |||||
| uint8_t data[3]; /**< MIDI data (body). */ | |||||
| } LV2_Atom_MidiEvent; | |||||
| #if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| static const sendNoteFunc sendNoteCallback = nullptr; | |||||
| #endif | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| class UiLv2 | class UiLv2 | ||||
| @@ -51,6 +61,7 @@ public: | |||||
| fController(controller), | fController(controller), | ||||
| fWriteFunction(writeFunc), | fWriteFunction(writeFunc), | ||||
| fEventTransferURID(uridMap->map(uridMap->handle, LV2_ATOM__eventTransfer)), | fEventTransferURID(uridMap->map(uridMap->handle, LV2_ATOM__eventTransfer)), | ||||
| fMidiEventURID(uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent)), | |||||
| fKeyValueURID(uridMap->map(uridMap->handle, DISTRHO_PLUGIN_LV2_STATE_PREFIX "KeyValueState")), | fKeyValueURID(uridMap->map(uridMap->handle, DISTRHO_PLUGIN_LV2_STATE_PREFIX "KeyValueState")), | ||||
| fWinIdWasNull(winId == 0) | fWinIdWasNull(winId == 0) | ||||
| { | { | ||||
| @@ -256,9 +267,28 @@ protected: | |||||
| fWriteFunction(fController, eventInPortIndex, atomSize, fEventTransferURID, atom); | fWriteFunction(fController, eventInPortIndex, atomSize, fEventTransferURID, atom); | ||||
| } | } | ||||
| void sendNote(const uint8_t /*channel*/, const uint8_t /*note*/, const uint8_t /*velocity*/) | |||||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fWriteFunction != nullptr,); | |||||
| if (channel > 0xF) | |||||
| return; | |||||
| const uint32_t eventInPortIndex(DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS); | |||||
| LV2_Atom_MidiEvent atomMidiEvent; | |||||
| atomMidiEvent.atom.size = 3; | |||||
| atomMidiEvent.atom.type = fMidiEventURID; | |||||
| atomMidiEvent.data[0] = channel + (velocity != 0 ? 0x90 : 0x80); | |||||
| atomMidiEvent.data[1] = note; | |||||
| atomMidiEvent.data[2] = velocity; | |||||
| // send to DSP side | |||||
| fWriteFunction(fController, eventInPortIndex, sizeof(LV2_Atom_MidiEvent), fEventTransferURID, &atomMidiEvent); | |||||
| } | } | ||||
| #endif | |||||
| void setSize(const uint width, const uint height) | void setSize(const uint width, const uint height) | ||||
| { | { | ||||
| @@ -282,6 +312,7 @@ private: | |||||
| // Need to save this | // Need to save this | ||||
| const LV2_URID fEventTransferURID; | const LV2_URID fEventTransferURID; | ||||
| const LV2_URID fMidiEventURID; | |||||
| const LV2_URID fKeyValueURID; | const LV2_URID fKeyValueURID; | ||||
| // using ui:showInterface if true | // using ui:showInterface if true | ||||
| @@ -307,10 +338,12 @@ private: | |||||
| uiPtr->setState(key, value); | uiPtr->setState(key, value); | ||||
| } | } | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) | static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) | ||||
| { | { | ||||
| uiPtr->sendNote(channel, note, velocity); | uiPtr->sendNote(channel, note, velocity); | ||||
| } | } | ||||
| #endif | |||||
| static void setSizeCallback(void* ptr, uint width, uint height) | static void setSizeCallback(void* ptr, uint width, uint height) | ||||
| { | { | ||||
| @@ -1,9 +1,18 @@ | |||||
| /* | /* | ||||
| * aeffectx.h - simple header to allow VeSTige compilation and eventually work | |||||
| * IMPORTANT: The author of DPF has no connection with the | |||||
| * author of the VeSTige VST-compatibility header, has had no | |||||
| * involvement in its creation. | |||||
| * | |||||
| * The VeSTige header is included in this package in the good-faith | |||||
| * belief that it has been cleanly and legally reverse engineered | |||||
| * without reference to the official VST SDK and without its | |||||
| * developer(s) having agreed to the VST SDK license agreement. | |||||
| */ | |||||
| /* | |||||
| * simple header to allow VeSTige compilation and eventually work | |||||
| * | * | ||||
| * Copyright (c) 2006 Javier Serrano Polo <jasp00/at/users.sourceforge.net> | * Copyright (c) 2006 Javier Serrano Polo <jasp00/at/users.sourceforge.net> | ||||
| * | |||||
| * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public | * modify it under the terms of the GNU General Public | ||||
| @@ -22,8 +31,8 @@ | |||||
| * | * | ||||
| */ | */ | ||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #ifndef _AEFFECTX_H | |||||
| #define _AEFFECTX_H | |||||
| #ifndef _VESTIGE_H | |||||
| #define _VESTIGE_H | |||||
| #define CCONST(a, b, c, d)( ( ( (int) a ) << 24 ) | \ | #define CCONST(a, b, c, d)( ( ( (int) a ) << 24 ) | \ | ||||
| ( ( (int) b ) << 16 ) | \ | ( ( (int) b ) << 16 ) | \ | ||||
| @@ -87,11 +96,11 @@ | |||||
| #define effFlagsIsSynth (1 << 8) // currently unused | #define effFlagsIsSynth (1 << 8) // currently unused | ||||
| #define effOpen 0 | #define effOpen 0 | ||||
| #define effClose 1 // currently unused | |||||
| #define effSetProgram 2 // currently unused | |||||
| #define effGetProgram 3 // currently unused | |||||
| #define effGetProgramName 5 // currently unused | |||||
| #define effGetParamName 8 // currently unused | |||||
| #define effClose 1 | |||||
| #define effSetProgram 2 | |||||
| #define effGetProgram 3 | |||||
| #define effGetProgramName 5 | |||||
| #define effGetParamName 8 | |||||
| #define effSetSampleRate 10 | #define effSetSampleRate 10 | ||||
| #define effSetBlockSize 11 | #define effSetBlockSize 11 | ||||
| #define effMainsChanged 12 | #define effMainsChanged 12 | ||||
| @@ -101,22 +110,42 @@ | |||||
| #define effEditIdle 19 | #define effEditIdle 19 | ||||
| #define effEditTop 20 | #define effEditTop 20 | ||||
| #define effProcessEvents 25 | #define effProcessEvents 25 | ||||
| #define effGetPlugCategory 35 | |||||
| #define effGetEffectName 45 | #define effGetEffectName 45 | ||||
| #define effGetVendorString 47 | #define effGetVendorString 47 | ||||
| #define effGetProductString 48 | #define effGetProductString 48 | ||||
| #define effGetVendorVersion 49 | #define effGetVendorVersion 49 | ||||
| #define effCanDo 51 // currently unused | |||||
| /* from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ | |||||
| #define effCanDo 51 | |||||
| #define effIdle 53 | |||||
| #define effGetParameterProperties 56 | #define effGetParameterProperties 56 | ||||
| #define effGetVstVersion 58 // currently unused | |||||
| #define effGetVstVersion 58 | |||||
| #define effShellGetNextPlugin 70 | |||||
| #define effStartProcess 71 | |||||
| #define effStopProcess 72 | |||||
| #define effBeginSetProgram 67 | |||||
| #define effEndSetProgram 68 | |||||
| #ifdef WORDS_BIGENDIAN | |||||
| // "VstP" | |||||
| #define kEffectMagic 0x50747356 | |||||
| #else | |||||
| // "PtsV" | |||||
| #define kEffectMagic 0x56737450 | |||||
| #endif | |||||
| #define kEffectMagic (CCONST( 'V', 's', 't', 'P' )) | |||||
| #define kVstLangEnglish 1 | #define kVstLangEnglish 1 | ||||
| #define kVstMidiType 1 | #define kVstMidiType 1 | ||||
| struct RemoteVstPlugin; | struct RemoteVstPlugin; | ||||
| #define kVstTransportChanged 1 | |||||
| #define kVstTransportPlaying (1 << 1) | #define kVstTransportPlaying (1 << 1) | ||||
| #define kVstTransportCycleActive (1 << 2) | |||||
| #define kVstTransportRecording (1 << 3) | |||||
| #define kVstAutomationWriting (1 << 6) | |||||
| #define kVstAutomationReading (1 << 7) | |||||
| #define kVstNanosValid (1 << 8) | #define kVstNanosValid (1 << 8) | ||||
| #define kVstPpqPosValid (1 << 9) | #define kVstPpqPosValid (1 << 9) | ||||
| @@ -174,26 +203,57 @@ struct _VstEvents | |||||
| VstEvent * events[2]; | VstEvent * events[2]; | ||||
| }; | }; | ||||
| enum Vestige2StringConstants | |||||
| { | |||||
| VestigeMaxNameLen = 64, | |||||
| VestigeMaxLabelLen = 64, | |||||
| VestigeMaxShortLabelLen = 8, | |||||
| VestigeMaxCategLabelLen = 24, | |||||
| VestigeMaxFileNameLen = 100 | |||||
| }; | |||||
| enum VstPlugCategory | |||||
| { | |||||
| kPlugCategUnknown = 0, | |||||
| kPlugCategEffect, | |||||
| kPlugCategSynth, | |||||
| kPlugCategAnalysis, | |||||
| kPlugCategMastering, | |||||
| kPlugCategSpacializer, | |||||
| kPlugCategRoomFx, | |||||
| kPlugSurroundFx, | |||||
| kPlugCategRestoration, | |||||
| kPlugCategOfflineProcess, | |||||
| kPlugCategShell, | |||||
| kPlugCategGenerator, | |||||
| kPlugCategMaxCount | |||||
| }; | |||||
| typedef struct _VstEvents VstEvents; | typedef struct _VstEvents VstEvents; | ||||
| /* this struct taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ | |||||
| struct _VstParameterProperties | struct _VstParameterProperties | ||||
| { | { | ||||
| float stepFloat; | |||||
| float smallStepFloat; | |||||
| float largeStepFloat; | |||||
| char label[64]; | |||||
| int32_t flags; | |||||
| int32_t minInteger; | |||||
| int32_t maxInteger; | |||||
| int32_t stepInteger; | |||||
| int32_t largeStepInteger; | |||||
| char shortLabel[8]; | |||||
| float stepFloat; /* float step */ | |||||
| float smallStepFloat; /* small float step */ | |||||
| float largeStepFloat; /* large float step */ | |||||
| char label[VestigeMaxLabelLen]; /* parameter label */ | |||||
| int32_t flags; /* @see VstParameterFlags */ | |||||
| int32_t minInteger; /* integer minimum */ | |||||
| int32_t maxInteger; /* integer maximum */ | |||||
| int32_t stepInteger; /* integer step */ | |||||
| int32_t largeStepInteger; /* large integer step */ | |||||
| char shortLabel[VestigeMaxShortLabelLen]; /* short label, recommended: 6 + delimiter */ | |||||
| int16_t displayIndex; /* index where this parameter should be displayed (starting with 0) */ | |||||
| int16_t category; /* 0: no category, else group index + 1 */ | |||||
| int16_t numParametersInCategory; /* number of parameters in category */ | |||||
| int16_t reserved; /* zero */ | |||||
| char categoryLabel[VestigeMaxCategLabelLen]; /* category label, e.g. "Osc 1" */ | |||||
| char future[16]; /* reserved for future use */ | |||||
| }; | }; | ||||
| typedef struct _VstParameterProperties VstParameterProperties; | typedef struct _VstParameterProperties VstParameterProperties; | ||||
| /* this enum taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ | |||||
| enum VstParameterFlags | enum VstParameterFlags | ||||
| { | { | ||||
| kVstParameterIsSwitch = 1 << 0, /* parameter is a switch (on/off) */ | kVstParameterIsSwitch = 1 << 0, /* parameter is a switch (on/off) */ | ||||
| @@ -231,18 +291,19 @@ struct _AEffect | |||||
| // Fill somewhere 28-2b | // Fill somewhere 28-2b | ||||
| void *ptr1; | void *ptr1; | ||||
| void *ptr2; | void *ptr2; | ||||
| // Zeroes 2c-2f 30-33 34-37 38-3b | |||||
| char empty3[4 + 4 + 4]; | |||||
| int initialDelay; | |||||
| // Zeroes 30-33 34-37 38-3b | |||||
| char empty2[4 + 4]; | |||||
| // 1.0f 3c-3f | // 1.0f 3c-3f | ||||
| float unkown_float; | float unkown_float; | ||||
| // An object? pointer 40-43 | // An object? pointer 40-43 | ||||
| void *ptr3; | |||||
| void *object; | |||||
| // Zeroes 44-47 | // Zeroes 44-47 | ||||
| void *user; | void *user; | ||||
| // Id 48-4b | // Id 48-4b | ||||
| int32_t uniqueID; | int32_t uniqueID; | ||||
| // Don't know 4c-4f | |||||
| char unknown1[4]; | |||||
| // plugin version 4c-4f | |||||
| int32_t version; | |||||
| // processReplacing 50-53 | // processReplacing 50-53 | ||||
| void (* processReplacing) (struct _AEffect *, float **, float **, int); | void (* processReplacing) (struct _AEffect *, float **, float **, int); | ||||
| }; | }; | ||||
| @@ -9,13 +9,13 @@ else | |||||
| exit | exit | ||||
| fi | fi | ||||
| PWD=`dirname $0` | |||||
| PWD="$(dirname "$0")" | |||||
| if [ -f $PWD/lv2_ttl_generator.exe ]; then | |||||
| GEN=$PWD/lv2_ttl_generator.exe | |||||
| if [ -f "$PWD/lv2_ttl_generator.exe" ]; then | |||||
| GEN="$PWD/lv2_ttl_generator.exe" | |||||
| EXT=dll | EXT=dll | ||||
| else | else | ||||
| GEN=$PWD/lv2_ttl_generator | |||||
| GEN="$PWD/lv2_ttl_generator" | |||||
| if [ -d /Library/Audio ]; then | if [ -d /Library/Audio ]; then | ||||
| EXT=dylib | EXT=dylib | ||||
| else | else | ||||
| @@ -27,7 +27,7 @@ FOLDERS=`find . -type d -name \*.lv2` | |||||
| for i in $FOLDERS; do | for i in $FOLDERS; do | ||||
| cd $i | cd $i | ||||
| FILE=`ls *.$EXT | sort | head -n 1` | |||||
| $GEN ./$FILE | |||||
| FILE="$(ls *.$EXT | sort | head -n 1)" | |||||
| "$GEN" "./$FILE" | |||||
| cd .. | cd .. | ||||
| done | done | ||||