diff --git a/distrho/extra/RingBuffer.hpp b/distrho/extra/RingBuffer.hpp index eec5d6e4..d7c03a9c 100644 --- a/distrho/extra/RingBuffer.hpp +++ b/distrho/extra/RingBuffer.hpp @@ -503,7 +503,6 @@ public: // ------------------------------------------------------------------- -protected: /* * Tie this ring buffer control to a ring buffer struct, optionally clearing its data. */ @@ -519,6 +518,7 @@ protected: // ------------------------------------------------------------------- +protected: /** @internal try reading from the buffer, can fail. */ bool tryRead(void* const buf, const uint32_t size) noexcept { diff --git a/distrho/src/DistrhoPluginVST.cpp b/distrho/src/DistrhoPluginVST.cpp index 10fda021..0725bb9c 100644 --- a/distrho/src/DistrhoPluginVST.cpp +++ b/distrho/src/DistrhoPluginVST.cpp @@ -27,6 +27,7 @@ # define DISTRHO_UI_USER_RESIZABLE 0 # define DISTRHO_UI_IS_STANDALONE false # include "DistrhoUIInternal.hpp" +# include "../extra/RingBuffer.hpp" #endif #ifndef __cdecl @@ -110,27 +111,44 @@ void snprintf_iparam(char* const dst, const int32_t value, const size_t size) // ----------------------------------------------------------------------- -struct ParameterCheckHelper +struct ParameterAndNotesHelper { - bool* parameterChecks; float* parameterValues; +#if DISTRHO_PLUGIN_HAS_UI + bool* parameterChecks; +# if DISTRHO_PLUGIN_WANT_MIDI_INPUT + SmallStackBuffer notesRingBuffer; +# endif +#endif - ParameterCheckHelper() - : parameterChecks(nullptr), - parameterValues(nullptr) {} + ParameterAndNotesHelper() + : parameterValues(nullptr) +#if DISTRHO_PLUGIN_HAS_UI + , parameterChecks(nullptr) +# if DISTRHO_PLUGIN_WANT_MIDI_INPUT + , notesRingBuffer(StackBuffer_INIT) +# endif +#endif + { +#ifndef DISTRHO_PROPER_CPP11_SUPPORT + std::memset(¬esRingBuffer, 0, sizeof(notesRingBuffer)); +#endif + } - virtual ~ParameterCheckHelper() + virtual ~ParameterAndNotesHelper() { - if (parameterChecks != nullptr) - { - delete[] parameterChecks; - parameterChecks = nullptr; - } if (parameterValues != nullptr) { delete[] parameterValues; parameterValues = nullptr; } +#if DISTRHO_PLUGIN_HAS_UI + if (parameterChecks != nullptr) + { + delete[] parameterChecks; + parameterChecks = nullptr; + } +#endif } #if DISTRHO_PLUGIN_WANT_STATE @@ -141,12 +159,19 @@ struct ParameterCheckHelper #if DISTRHO_PLUGIN_HAS_UI // ----------------------------------------------------------------------- +#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT +static const sendNoteFunc sendNoteCallback = nullptr; +#endif +#if ! DISTRHO_PLUGIN_WANT_STATE +static const setStateFunc setStateCallback = nullptr; +#endif + class UIVst { public: UIVst(const audioMasterCallback audioMaster, AEffect* const effect, - ParameterCheckHelper* const uiHelper, + ParameterAndNotesHelper* const uiHelper, PluginExporter* const plugin, const intptr_t winId, const float scaleFactor) : fAudioMaster(audioMaster), @@ -162,9 +187,17 @@ public: nullptr, // TODO file request nullptr, plugin->getInstancePointer(), - scaleFactor), - fKeyboardModifiers(0) + scaleFactor) +# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + , fKeyboardModifiers(0) +# endif +# if DISTRHO_PLUGIN_WANT_MIDI_INPUT + , fNotesRingBuffer() +# endif { +# if DISTRHO_PLUGIN_WANT_MIDI_INPUT + fNotesRingBuffer.setRingBuffer(&uiHelper->notesRingBuffer, false); +# endif } // ------------------------------------------------------------------- @@ -352,45 +385,46 @@ protected: hostCallback(audioMasterAutomate, index, 0, nullptr, perValue); } - void setState(const char* const key, const char* const value) + void setSize(const uint width, const uint height) { -# if DISTRHO_PLUGIN_WANT_STATE - fUiHelper->setStateFromUI(key, value); -# else - return; // unused - (void)key; - (void)value; -# endif + fUI.setWindowSize(width, height); + hostCallback(audioMasterSizeWindow, width, height); } +# if DISTRHO_PLUGIN_WANT_MIDI_INPUT void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) { -# if 0 //DISTRHO_PLUGIN_WANT_MIDI_INPUT - // TODO -# else - return; // unused - (void)channel; - (void)note; - (void)velocity; -# endif + uint8_t midiData[3]; + midiData[0] = (velocity != 0 ? 0x90 : 0x80) | channel; + midiData[1] = note; + midiData[2] = velocity; + fNotesRingBuffer.writeCustomData(midiData, 3); + fNotesRingBuffer.commitWrite(); } +# endif - void setSize(const uint width, const uint height) +# if DISTRHO_PLUGIN_WANT_STATE + void setState(const char* const key, const char* const value) { - fUI.setWindowSize(width, height); - hostCallback(audioMasterSizeWindow, width, height); + fUiHelper->setStateFromUI(key, value); } +# endif private: // Vst stuff const audioMasterCallback fAudioMaster; AEffect* const fEffect; - ParameterCheckHelper* const fUiHelper; + ParameterAndNotesHelper* const fUiHelper; PluginExporter* const fPlugin; // Plugin UI UIExporter fUI; +# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI uint16_t fKeyboardModifiers; +# endif +# if DISTRHO_PLUGIN_WANT_MIDI_INPUT + RingBufferControl fNotesRingBuffer; +# endif // ------------------------------------------------------------------- // Callbacks @@ -407,28 +441,32 @@ private: handlePtr->setParameterValue(rindex, value); } - static void setStateCallback(void* ptr, const char* key, const char* value) + static void setSizeCallback(void* ptr, uint width, uint height) { - handlePtr->setState(key, value); + handlePtr->setSize(width, height); } +# if DISTRHO_PLUGIN_WANT_MIDI_INPUT static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) { handlePtr->sendNote(channel, note, velocity); } +# endif - static void setSizeCallback(void* ptr, uint width, uint height) +# if DISTRHO_PLUGIN_WANT_STATE + static void setStateCallback(void* ptr, const char* key, const char* value) { - handlePtr->setSize(width, height); + handlePtr->setState(key, value); } +# endif #undef handlePtr }; -#endif +#endif // DISTRHO_PLUGIN_HAS_UI // ----------------------------------------------------------------------- -class PluginVst : public ParameterCheckHelper +class PluginVst : public ParameterAndNotesHelper { public: PluginVst(const audioMasterCallback audioMaster, AEffect* const effect) @@ -439,6 +477,16 @@ public: std::memset(fProgramName, 0, sizeof(char)*(32+1)); std::strcpy(fProgramName, "Default"); + const uint32_t parameterCount = fPlugin.getParameterCount(); + + if (parameterCount != 0) + { + parameterValues = new float[parameterCount]; + + for (uint32_t i=0; i < parameterCount; ++i) + parameterValues[i] = NAN; + } + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT fMidiEventCount = 0; #endif @@ -451,17 +499,12 @@ public: fVstRect.right = 0; fLastScaleFactor = 1.0f; - if (const uint32_t paramCount = fPlugin.getParameterCount()) + if (parameterCount != 0) { - parameterChecks = new bool[paramCount]; - parameterValues = new float[paramCount]; - - for (uint32_t i=0; i < paramCount; ++i) - { - parameterChecks[i] = false; - parameterValues[i] = NAN; - } + parameterChecks = new bool[parameterCount]; + memset(parameterChecks, 0, sizeof(bool)*parameterCount); } + # if DISTRHO_OS_MAC # ifdef __LP64__ fUsingNsView = true; @@ -472,6 +515,10 @@ public: fUsingNsView = false; # endif # endif // DISTRHO_OS_MAC + +# if DISTRHO_PLUGIN_WANT_MIDI_INPUT + fNotesRingBuffer.setRingBuffer(¬esRingBuffer, true); +# endif #endif // DISTRHO_PLUGIN_HAS_UI #if DISTRHO_PLUGIN_WANT_STATE @@ -1066,6 +1113,28 @@ public: #endif #if DISTRHO_PLUGIN_WANT_MIDI_INPUT +# if DISTRHO_PLUGIN_HAS_UI + if (fMidiEventCount != kMaxMidiEvents && fNotesRingBuffer.isDataAvailableForReading()) + { + uint8_t midiData[3]; + uint32_t frame = fMidiEventCount != 0 ? fMidiEvents[fMidiEventCount-1].frame : 0; + + while (fNotesRingBuffer.isDataAvailableForReading()) + { + if (! fNotesRingBuffer.readCustomData(midiData, 3)) + break; + + MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]); + midiEvent.frame = frame; + midiEvent.size = 3; + std::memcpy(midiEvent.data, midiData, 3); + + if (fMidiEventCount == kMaxMidiEvents) + break; + } + } +# endif + fPlugin.run(inputs, outputs, sampleFrames, fMidiEvents, fMidiEventCount); fMidiEventCount = 0; #else @@ -1107,6 +1176,9 @@ private: # if DISTRHO_OS_MAC bool fUsingNsView; # endif +# if DISTRHO_PLUGIN_WANT_MIDI_INPUT + RingBufferControl fNotesRingBuffer; +# endif #endif #if DISTRHO_PLUGIN_WANT_STATE