From c457ed32ace2fb304a94d444673b2ad31a9b38e8 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 16 Jul 2011 21:17:48 +0100 Subject: [PATCH] Massive work, add extensions, UI almost working --- demo/Build/plugin.pro | 2 +- juce-dssi.cpp | 2 +- .../plugin_client/LV2/includes/lv2_data_access.h | 56 --- .../audio/plugin_client/LV2/juce_LV2_Wrapper.cpp | 375 ++++++++------------- .../LV2/{includes/lv2_event.h => lv2/event.h} | 0 .../lv2_event_helpers.h => lv2/event_helpers.h} | 2 +- .../instance_access.h} | 0 .../src/audio/plugin_client/LV2/{ => lv2}/lv2.h | 0 .../LV2/{includes => lv2}/lv2_external_ui.h | 0 .../audio/plugin_client/LV2/{lv2_ui.h => lv2/ui.h} | 0 .../LV2/{includes/lv2_uri_map.h => lv2/uri_map.h} | 0 .../audio/plugin_client/VST/juce_VST_Wrapper.cpp | 2 - 12 files changed, 146 insertions(+), 293 deletions(-) delete mode 100644 juce/source/src/audio/plugin_client/LV2/includes/lv2_data_access.h rename juce/source/src/audio/plugin_client/LV2/{includes/lv2_event.h => lv2/event.h} (100%) rename juce/source/src/audio/plugin_client/LV2/{includes/lv2_event_helpers.h => lv2/event_helpers.h} (99%) rename juce/source/src/audio/plugin_client/LV2/{lv2_instance_access.h => lv2/instance_access.h} (100%) rename juce/source/src/audio/plugin_client/LV2/{ => lv2}/lv2.h (100%) rename juce/source/src/audio/plugin_client/LV2/{includes => lv2}/lv2_external_ui.h (100%) rename juce/source/src/audio/plugin_client/LV2/{lv2_ui.h => lv2/ui.h} (100%) rename juce/source/src/audio/plugin_client/LV2/{includes/lv2_uri_map.h => lv2/uri_map.h} (100%) diff --git a/demo/Build/plugin.pro b/demo/Build/plugin.pro index 15143f4..18b1ff1 100644 --- a/demo/Build/plugin.pro +++ b/demo/Build/plugin.pro @@ -12,7 +12,7 @@ CONFIG += warn_off CONFIG += debug #CONFIG += release -DEFINES = JucePlugin_Build_LV2 +DEFINES = LINUX JucePlugin_Build_LV2 #DEFINES += _NDEBUG NDEBUG DEFINES += DEBUG _DEBUG diff --git a/juce-dssi.cpp b/juce-dssi.cpp index fb8864d..bae69b9 100644 --- a/juce-dssi.cpp +++ b/juce-dssi.cpp @@ -51,7 +51,7 @@ #include "JucePluginCharacteristics.h" #include - //#define USING_LIBLO + #define USING_LIBLO #ifdef USING_LIBLO #include #else diff --git a/juce/source/src/audio/plugin_client/LV2/includes/lv2_data_access.h b/juce/source/src/audio/plugin_client/LV2/includes/lv2_data_access.h deleted file mode 100644 index fac6974..0000000 --- a/juce/source/src/audio/plugin_client/LV2/includes/lv2_data_access.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - LV2 Data Access Extension - Copyright 2008-2011 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/** - @file data-access.h - C header for the LV2 Extension Data extension - . - - This extension defines a method for (e.g.) plugin UIs to have (possibly - marshalled) access to the extension_data function on a plugin instance. -*/ - -#ifndef LV2_DATA_ACCESS_H -#define LV2_DATA_ACCESS_H - -#define LV2_DATA_ACCESS_URI "http://lv2plug.in/ns/ext/data-access" - -/** - The data field of the LV2_Feature for this extension. - - To support this feature the host must pass an LV2_Feature struct to the - instantiate method with URI "http://lv2plug.in/ns/ext/data-access" - and data pointed to an instance of this struct. -*/ -typedef struct { - /** - A pointer to a method the UI can call to get data (of a type specified - by some other extension) from the plugin. - - This call never is never guaranteed to return anything, UIs should - degrade gracefully if direct access to the plugin data is not possible - (in which case this function will return NULL). - - This is for access to large data that can only possibly work if the UI - and plugin are running in the same process. For all other things, use - the normal LV2 UI communication system. - */ - const void* (*data_access)(const char* uri); - -} LV2_Extension_Data_Feature; - -#endif /* LV2_DATA_ACCESS_H */ diff --git a/juce/source/src/audio/plugin_client/LV2/juce_LV2_Wrapper.cpp b/juce/source/src/audio/plugin_client/LV2/juce_LV2_Wrapper.cpp index 301613e..24c73a1 100644 --- a/juce/source/src/audio/plugin_client/LV2/juce_LV2_Wrapper.cpp +++ b/juce/source/src/audio/plugin_client/LV2/juce_LV2_Wrapper.cpp @@ -6,26 +6,27 @@ #if JucePlugin_Build_LV2 -#include "juce.h" - -// LV2 includes -#include "lv2.h" -#include "lv2_instance_access.h" -#include "lv2_ui.h" - -#undef MemoryBlock +// LV2 includes.. +#include "lv2/lv2.h" +#include "lv2/event.h" +#include "lv2/event_helpers.h" +#include "lv2/instance_access.h" +#include "lv2/uri_map.h" +#include "lv2/ui.h" +#include "lv2/lv2_external_ui.h" + +#include "../juce_PluginHeaders.h" +#include "../juce_PluginHostType.h" static bool recursionCheck = false; -static JUCE_NAMESPACE::uint32 lastMasterIdleCall = 0; BEGIN_JUCE_NAMESPACE extern void juce_callAnyTimersSynchronously(); +END_JUCE_NAMESPACE - #if JUCE_MAC - extern void initialiseMac(); - #endif +extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); -END_JUCE_NAMESPACE +static Array activePlugins; //============================================================================== // Same as juce_lv2_gen.cpp @@ -44,82 +45,48 @@ String get_external_ui_uri() return String("urn:" JucePlugin_Manufacturer ":" JucePlugin_Name ":JUCE-External-UI").replace(" ", "_"); } -#if 0 -enum JuceLv2PortType { - JUCE_LV2_PORT_TYPE_NONE, - JUCE_LV2_PORT_TYPE_MIDI, - JUCE_LV2_PORT_TYPE_AUDIO, - JUCE_LV2_PORT_TYPE_CONTROL -}; - -struct JuceLv2Port { - JuceLv2PortType type; - uint32_t index; - void* data; -}; - -int get_parameters_padding() -{ - int padding = 0; -#if JucePlugin_WantsMidiInput - padding += 1; -#endif -#if JucePlugin_ProducesMidiOutput - padding += 1; -#endif - padding += JucePlugin_MaxNumInputChannels; - padding += JucePlugin_MaxNumOutputChannels; - return padding; -} -#endif - //============================================================================== -/** Somewhere in the codebase of your plugin, you need to implement this function - and make it create an instance of the filter subclass that you're building. -*/ -extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); - -static Array activePlugins; - -/* Create a new JUCE LV2 Plugin */ -class JuceLV2Wrapper : private Timer +// Create a new JUCE LV2 Plugin +class JuceLV2Wrapper : private Timer, public AudioProcessorListener { public: - JuceLV2Wrapper(const LV2_Descriptor* _descriptor, double _sample_rate, const LV2_Feature* const* _features) : + JuceLV2Wrapper(const LV2_Descriptor* descriptor_, double sample_rate_, const LV2_Feature* const* features) : chunkMemoryTime (0), + editor (nullptr), numInChans (JucePlugin_MaxNumInputChannels), numOutChans (JucePlugin_MaxNumOutputChannels), isProcessing (false), hasShutdown (false), firstProcessCallback (true), - shouldDeleteEditor (false) + shouldDeleteEditor (false), + descriptor (descriptor_), + ui_descriptor (nullptr), + ui_controller (nullptr), + ui_write_func (nullptr), + sample_rate (sample_rate_), + buffer_size (512), + midi_uri_id (0), + port_count (0) { printf("JuceLV2Wrapper()\n"); filter = createPluginFilter(); - filter->setPlayConfigDetails(numInChans, numOutChans, 0, 0); + filter->addListener (this); - descriptor = _descriptor; - ui_descriptor = nullptr; - //features = _features; - - sample_rate = _sample_rate; - buffer_size = 512; - port_count = 0; - + // Port count #if JucePlugin_WantsMidiInput - port_min = nullptr; port_count += 1; #endif #if JucePlugin_ProducesMidiOutput - port_mout = nullptr; port_count += 1; #endif - port_count += numInChans; port_count += numOutChans; port_count += filter->getNumParameters(); + // Set Port data + port_min = nullptr; + port_mout = nullptr; ports_ctrl.insertMultiple(0, nullptr, filter->getNumParameters()); ports_ctrl_last.insertMultiple(0, 0.0f, filter->getNumParameters()); @@ -135,7 +102,16 @@ public: ports_ctrl_last.set(i, filter->getParameter(i)); } - midi_uri_id = 0; // TODO URI-Map Extension + // Get MIDI URI Id + uint16_t j = 0; + while(features[j]) { + if (strcmp(features[j]->URI, LV2_URI_MAP_URI) == 0) { + LV2_URI_Map_Feature* uri_feature = (LV2_URI_Map_Feature*)features[j]->data; + midi_uri_id = uri_feature->uri_to_id(uri_feature->callback_data, LV2_EVENT_URI, "http://lv2plug.in/ns/ext/midi#MidiEvent"); + break; + } + j++; + } activePlugins.add (this); } @@ -146,7 +122,7 @@ public: { #if JUCE_LINUX - //MessageManagerLock mmLock; + MessageManagerLock mmLock; #endif stopTimer(); deleteEditor (false); @@ -156,7 +132,7 @@ public: delete filter; filter = 0; - jassert (editorComp == 0); + jassert (editor == 0); channels.free(); deleteTempChannels(); @@ -170,9 +146,6 @@ public: if (activePlugins.size() == 0) { - #if JUCE_LINUX - //SharedMessageThread::deleteInstance(); - #endif shutdownJuce_GUI(); } } @@ -276,7 +249,7 @@ public: #endif } - // Change buffer size if needed + // Change if buffer size changed if (buffer_size != sample_count) { buffer_size = sample_count; filter->setPlayConfigDetails(numInChans, numOutChans, sample_rate, buffer_size); @@ -285,7 +258,6 @@ public: // Check for updated parameters float cur_value; - for (int i = 0; i < ports_ctrl.size(); i++) { if (ports_ctrl[i] != nullptr) { cur_value = *(float*)ports_ctrl[i]; @@ -340,6 +312,8 @@ public: channels[i] = chan; } + // TODO - MIDI Input + for (; i < numIn; ++i) channels[i] = ports_ain[i]; @@ -351,6 +325,7 @@ public: if (! midiEvents.isEmpty()) { + // TODO - MIDI Output midiEvents.clear(); } } @@ -368,6 +343,69 @@ public: } } + //============================================================================== + static void do_ui_external_run(lv2_external_ui* _this_) + { + printf("do_ui_external_run()\n"); + //doIdleCallback(); + + } + + static void do_ui_external_show(lv2_external_ui* _this_) + { + printf("do_ui_external_show()\n"); + //editorComp->setVisible(true); + + } + + static void do_ui_external_hide(lv2_external_ui* _this_) + { + printf("do_ui_external_hide()\n"); + //editorComp->setVisible(false); + } + + void do_ui_instantiate(const char* UiURI, LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget* widget, const LV2_Feature* const* features) + { + ui_write_func = write_function; + ui_controller = controller; + + //checkWhetherMessageThreadIsCorrect(); + const MessageManagerLock mmLock; + jassert (! recursionCheck); + + startTimer (1000 / 4); // performs misc housekeeping chores + + deleteEditor (true); + createEditor(); + + if (get_external_ui_uri().compare(UiURI) == 0) + { + ui_external_host = nullptr; + + uint16_t i = 0; + while(features[i]) { + if (strcmp(features[i]->URI, LV2_EXTERNAL_UI_URI) == 0) { + ui_external_host = (lv2_external_ui_host*)features[i]->data; + break; + } + i++; + } + + ui_external_widget.run = do_ui_external_run; + ui_external_widget.show = do_ui_external_show; + ui_external_widget.hide = do_ui_external_hide; + + *widget = &ui_external_widget; + + printf("External UI initiated\n"); + } + else // JUCE UI + { + + } + + } + void do_ui_cleanup() { // TODO @@ -375,12 +413,27 @@ public: void do_ui_port_event(uint32_t port_index, float value) { - if (port_index < filter->getNumParameters()) - filter->setParameter(port_index, value); + //int index = + //if (port_index < filter->getNumParameters()) + // filter->setParameter(port_index, value); } + // TODO - set/get chunk + //============================================================================== // JUCE Stuff + void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) + { + //int ctrl_pad = 0; + //if (ui_controller && ui_write_func) + // ui_write_func(ui_controller, ctrl_pad + index, sizeof(float), 0, &newValue); + } + + void audioProcessorChanged (AudioProcessor*) + { + //updateDisplay(); + } + void timerCallback() { if (shouldDeleteEditor) @@ -396,25 +449,6 @@ public: chunkMemoryTime = 0; chunkMemory.setSize (0); } - - tryMasterIdle(); - } - - void tryMasterIdle() - { - if (Component::isMouseButtonDownAnywhere() && ! recursionCheck) - { - const JUCE_NAMESPACE::uint32 now = JUCE_NAMESPACE::Time::getMillisecondCounter(); - - if (now > lastMasterIdleCall + 20 && editorComp != nullptr) - { - lastMasterIdleCall = now; - - recursionCheck = true; - //masterIdle(); //FIXME - recursionCheck = false; - } - } } void doIdleCallback() @@ -435,26 +469,19 @@ public: } } - void createEditorComp() + void createEditor() { if (hasShutdown || filter == nullptr) return; - if (editorComp == nullptr) + if (editor == nullptr) { - AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); - - if (ed != nullptr) - { - //cEffect.flags |= effFlagsHasEditor; - ed->setOpaque (true); - ed->setVisible (true); + editor = filter->createEditorIfNeeded(); - editorComp = new EditorCompWrapper (*this, ed); - } - else + if (editor != nullptr) { - //cEffect.flags &= ~effFlagsHasEditor; + editor->setOpaque (true); + editor->setVisible (true); } } @@ -469,7 +496,7 @@ public: jassert (! recursionCheck); recursionCheck = true; - if (editorComp != nullptr) + if (editor != nullptr) { Component* const modalComponent = Component::getCurrentlyModalComponent(); if (modalComponent != nullptr) @@ -484,17 +511,7 @@ public: } } - #if JUCE_MAC - if (hostWindow != 0) - { - detachComponentFromWindowRef (editorComp, hostWindow); - hostWindow = 0; - } - #endif - - filter->editorBeingDeleted (editorComp->getEditorComp()); - - editorComp = nullptr; + filter->editorBeingDeleted (editor); // there's some kind of component currently modal, but the host // is trying to delete our plugin. You should try to avoid this happening.. @@ -505,129 +522,23 @@ public: } //============================================================================== - // A component to hold the AudioProcessorEditor, and cope with some housekeeping - // chores when it changes or repaints. - class EditorCompWrapper : public Component, - public AsyncUpdater - { - public: - EditorCompWrapper (JuceLV2Wrapper& wrapper_, AudioProcessorEditor* editor) - : wrapper (wrapper_) - { - setOpaque (true); - editor->setOpaque (true); - - setBounds (editor->getBounds()); - editor->setTopLeftPosition (0, 0); - addAndMakeVisible (editor); - - #if JUCE_WINDOWS - if (! getHostType().isReceptor()) - addMouseListener (this, true); - - registerMouseWheelHook(); - #endif - } - - ~EditorCompWrapper() - { - #if JUCE_WINDOWS - unregisterMouseWheelHook(); - #endif - - deleteAllChildren(); // note that we can't use a ScopedPointer because the editor may - // have been transferred to another parent which takes over ownership. - } - - void paint (Graphics&) {} - - void paintOverChildren (Graphics&) - { - // this causes an async call to masterIdle() to help - // creaky old DAWs like Nuendo repaint themselves while we're - // repainting. Otherwise they just seem to give up and sit there - // waiting. - triggerAsyncUpdate(); - } - - #if JUCE_MAC - bool keyPressed (const KeyPress& kp) - { - // If we have an unused keypress, move the key-focus to a host window - // and re-inject the event.. - forwardCurrentKeyEventToHost (this); - return true; - } - #endif - - AudioProcessorEditor* getEditorComp() const - { - return dynamic_cast (getChildComponent (0)); - } - - void resized() - { - Component* const editor = getChildComponent(0); - - if (editor != nullptr) - editor->setBounds (getLocalBounds()); - } - - void childBoundsChanged (Component* child) - { - child->setTopLeftPosition (0, 0); - - const int cw = child->getWidth(); - const int ch = child->getHeight(); - - //wrapper.resizeHostWindow (cw, ch); - } - - void handleAsyncUpdate() - { - wrapper.tryMasterIdle(); - } - - #if JUCE_WINDOWS - void mouseDown (const MouseEvent&) - { - broughtToFront(); - } - - void broughtToFront() - { - // for hosts like nuendo, need to also pop the MDI container to the - // front when our comp is clicked on. - HWND parent = findMDIParentOf ((HWND) getWindowHandle()); - - if (parent != 0) - SetWindowPos (parent, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - } - #endif - - private: - //============================================================================== - JuceLV2Wrapper& wrapper; - //FakeMouseMoveGenerator fakeMouseGenerator; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EditorCompWrapper); - }; - - //============================================================================== private: AudioProcessor* filter; JUCE_NAMESPACE::MemoryBlock chunkMemory; JUCE_NAMESPACE::uint32 chunkMemoryTime; - ScopedPointer editorComp; + AudioProcessorEditor* editor; MidiBuffer midiEvents; int numInChans, numOutChans; bool isProcessing, hasShutdown, firstProcessCallback, shouldDeleteEditor; HeapBlock channels; - Array tempChannels; // see note in processReplacing() - + Array tempChannels; // see note in do_run() const LV2_Descriptor* descriptor; const LV2UI_Descriptor* ui_descriptor; + LV2UI_Controller ui_controller; + LV2UI_Write_Function ui_write_func; + lv2_external_ui ui_external_widget; + lv2_external_ui_host* ui_external_host; double sample_rate; int buffer_size; @@ -715,7 +626,7 @@ LV2UI_Handle juce_lv2ui_instantiate(const LV2UI_Descriptor* descriptor, const ch { if (strcmp(features[i]->URI, LV2_INSTANCE_ACCESS_URI) == 0 && features[i]->data) { JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)features[i]->data; - //wrapper->ui_descriptor = descriptor; + //wrapper->do_ui_instantiate(descriptor->URI, write_function, controller, widget, features); return wrapper; } i++; diff --git a/juce/source/src/audio/plugin_client/LV2/includes/lv2_event.h b/juce/source/src/audio/plugin_client/LV2/lv2/event.h similarity index 100% rename from juce/source/src/audio/plugin_client/LV2/includes/lv2_event.h rename to juce/source/src/audio/plugin_client/LV2/lv2/event.h diff --git a/juce/source/src/audio/plugin_client/LV2/includes/lv2_event_helpers.h b/juce/source/src/audio/plugin_client/LV2/lv2/event_helpers.h similarity index 99% rename from juce/source/src/audio/plugin_client/LV2/includes/lv2_event_helpers.h rename to juce/source/src/audio/plugin_client/LV2/lv2/event_helpers.h index fb7de65..b14f7d9 100644 --- a/juce/source/src/audio/plugin_client/LV2/includes/lv2_event_helpers.h +++ b/juce/source/src/audio/plugin_client/LV2/lv2/event_helpers.h @@ -25,7 +25,7 @@ #include #include #include -#include "lv2_event.h" +#include "event.h" /** @file * Helper functions for the LV2 Event extension diff --git a/juce/source/src/audio/plugin_client/LV2/lv2_instance_access.h b/juce/source/src/audio/plugin_client/LV2/lv2/instance_access.h similarity index 100% rename from juce/source/src/audio/plugin_client/LV2/lv2_instance_access.h rename to juce/source/src/audio/plugin_client/LV2/lv2/instance_access.h diff --git a/juce/source/src/audio/plugin_client/LV2/lv2.h b/juce/source/src/audio/plugin_client/LV2/lv2/lv2.h similarity index 100% rename from juce/source/src/audio/plugin_client/LV2/lv2.h rename to juce/source/src/audio/plugin_client/LV2/lv2/lv2.h diff --git a/juce/source/src/audio/plugin_client/LV2/includes/lv2_external_ui.h b/juce/source/src/audio/plugin_client/LV2/lv2/lv2_external_ui.h similarity index 100% rename from juce/source/src/audio/plugin_client/LV2/includes/lv2_external_ui.h rename to juce/source/src/audio/plugin_client/LV2/lv2/lv2_external_ui.h diff --git a/juce/source/src/audio/plugin_client/LV2/lv2_ui.h b/juce/source/src/audio/plugin_client/LV2/lv2/ui.h similarity index 100% rename from juce/source/src/audio/plugin_client/LV2/lv2_ui.h rename to juce/source/src/audio/plugin_client/LV2/lv2/ui.h diff --git a/juce/source/src/audio/plugin_client/LV2/includes/lv2_uri_map.h b/juce/source/src/audio/plugin_client/LV2/lv2/uri_map.h similarity index 100% rename from juce/source/src/audio/plugin_client/LV2/includes/lv2_uri_map.h rename to juce/source/src/audio/plugin_client/LV2/lv2/uri_map.h diff --git a/juce/source/src/audio/plugin_client/VST/juce_VST_Wrapper.cpp b/juce/source/src/audio/plugin_client/VST/juce_VST_Wrapper.cpp index 50857b0..c6f9cee 100644 --- a/juce/source/src/audio/plugin_client/VST/juce_VST_Wrapper.cpp +++ b/juce/source/src/audio/plugin_client/VST/juce_VST_Wrapper.cpp @@ -23,8 +23,6 @@ ============================================================================== */ -#define LINUX 1 - #ifdef _MSC_VER #pragma warning (disable : 4996 4100) #endif -- 2.11.4.GIT