From e1ab54abb319d76c33e20b5f968eac21555ea919 Mon Sep 17 00:00:00 2001 From: =?utf8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Sat, 10 Feb 2018 22:07:57 +0100 Subject: [PATCH] refreshed LV2 sources --- .../LV2}/includes/lv2_external_ui.h | 0 .../LV2}/includes/lv2_programs.h | 0 .../LV2}/juce_LV2_Wrapper.cpp | 154 ++++++++++++------ .../juce_audio_plugin_client_LV2.cpp | 27 +++ debian/patches/LV2-audioprocessor.patch | 67 ++++++++ debian/patches/series | 1 + 6 files changed, 202 insertions(+), 47 deletions(-) rename debian/extra/{ => juce_audio_plugin_client/LV2}/includes/lv2_external_ui.h (100%) rename debian/extra/{ => juce_audio_plugin_client/LV2}/includes/lv2_programs.h (100%) rename debian/extra/{ => juce_audio_plugin_client/LV2}/juce_LV2_Wrapper.cpp (95%) create mode 100644 debian/extra/juce_audio_plugin_client/juce_audio_plugin_client_LV2.cpp create mode 100644 debian/patches/LV2-audioprocessor.patch diff --git a/debian/extra/includes/lv2_external_ui.h b/debian/extra/juce_audio_plugin_client/LV2/includes/lv2_external_ui.h similarity index 100% rename from debian/extra/includes/lv2_external_ui.h rename to debian/extra/juce_audio_plugin_client/LV2/includes/lv2_external_ui.h diff --git a/debian/extra/includes/lv2_programs.h b/debian/extra/juce_audio_plugin_client/LV2/includes/lv2_programs.h similarity index 100% rename from debian/extra/includes/lv2_programs.h rename to debian/extra/juce_audio_plugin_client/LV2/includes/lv2_programs.h diff --git a/debian/extra/juce_LV2_Wrapper.cpp b/debian/extra/juce_audio_plugin_client/LV2/juce_LV2_Wrapper.cpp similarity index 95% rename from debian/extra/juce_LV2_Wrapper.cpp rename to debian/extra/juce_audio_plugin_client/LV2/juce_LV2_Wrapper.cpp index f8441adf..1c1f6162 100644 --- a/debian/extra/juce_LV2_Wrapper.cpp +++ b/debian/extra/juce_audio_plugin_client/LV2/juce_LV2_Wrapper.cpp @@ -13,6 +13,7 @@ #include "juce_audio_plugin_client/utility/juce_CheckSettingMacros.h" #include "juce_core/system/juce_TargetPlatform.h" // for JUCE_LINUX + #if JucePlugin_Build_LV2 /** Plugin requires processing with a fixed/constant block size */ @@ -20,6 +21,11 @@ #define JucePlugin_WantsLV2FixedBlockSize 0 #endif +/** Enable latency port */ +#ifndef JucePlugin_WantsLV2Latency + #define JucePlugin_WantsLV2Latency 1 +#endif + /** Use non-parameter states */ #ifndef JucePlugin_WantsLV2State #define JucePlugin_WantsLV2State 1 @@ -46,7 +52,7 @@ #define JucePlugin_WantsLV2State 1 #endif -#if JUCE_LINUX +#if JUCE_LINUX && ! JUCE_AUDIOPROCESSOR_NO_GUI #include #undef KeyPress #endif @@ -71,23 +77,11 @@ #include "includes/lv2_external_ui.h" #include "includes/lv2_programs.h" -#include "juce_audio_plugin_client/utility/juce_IncludeModuleHeaders.h" - -namespace juce -{ - #if JUCE_LINUX - extern Display* display; - #endif -} +#include "../utility/juce_IncludeModuleHeaders.h" #define JUCE_LV2_STATE_STRING_URI "urn:juce:stateString" #define JUCE_LV2_STATE_BINARY_URI "urn:juce:stateBinary" -#if JucePlugin_WantsLV2State && ! JucePlugin_WantsLV2StateString - // FIXME - juce base64 algorithm does not conform to RFC used in LV2 - #include "base64/Base64.cpp" -#endif - //============================================================================== // Various helper functions for creating the ttl files @@ -99,6 +93,8 @@ namespace juce #define PLUGIN_EXT ".dll" #endif +using namespace juce; + /** Returns plugin type, defined in AppConfig.h or JucePluginCharacteristics.h */ const String getPluginType() { @@ -199,6 +195,7 @@ const String makeManifestFile (AudioProcessor* const filter, const String& binar text += " rdfs:seeAlso <" + binary + ".ttl> .\n"; text += "\n"; +#if ! JUCE_AUDIOPROCESSOR_NO_GUI // UIs if (filter->hasEditor()) { @@ -210,19 +207,20 @@ const String makeManifestFile (AudioProcessor* const filter, const String& binar text += "\n"; text += "<" + pluginURI + "#ParentUI>\n"; -#if JUCE_MAC + #if JUCE_MAC text += " a ui:CocoaUI ;\n"; -#elif JUCE_LINUX + #elif JUCE_LINUX text += " a ui:X11UI ;\n"; -#elif JUCE_WINDOWS + #elif JUCE_WINDOWS text += " a ui:WindowsUI ;\n"; -#endif + #endif text += " ui:binary <" + binary + PLUGIN_EXT "> ;\n"; text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> ;\n"; text += " lv2:optionalFeature ui:noUserResize ;\n"; text += " lv2:extensionData <" LV2_PROGRAMS__UIInterface "> .\n"; text += "\n"; } +#endif #if JucePlugin_WantsLV2Presets const String presetSeparator(pluginURI.contains("#") ? ":" : "#"); @@ -243,7 +241,7 @@ const String makeManifestFile (AudioProcessor* const filter, const String& binar } /** Create the -plugin-.ttl file contents */ -const String makePluginFile (AudioProcessor* const filter) +const String makePluginFile (AudioProcessor* const filter, const int maxNumInputChannels, const int maxNumOutputChannels) { const String& pluginURI(getPluginURI()); String text; @@ -272,6 +270,7 @@ const String makePluginFile (AudioProcessor* const filter) text += " <" LV2_PROGRAMS__Interface "> ;\n"; text += "\n"; +#if ! JUCE_AUDIOPROCESSOR_NO_GUI // UIs if (filter->hasEditor()) { @@ -279,6 +278,7 @@ const String makePluginFile (AudioProcessor* const filter) text += " <" + pluginURI + "#ParentUI> ;\n"; text += "\n"; } +#endif uint32 portIndex = 0; @@ -317,7 +317,7 @@ const String makePluginFile (AudioProcessor* const filter) text += "\n"; #endif - // Freewheel and latency ports + // Freewheel port text += " lv2:port [\n"; text += " a lv2:InputPort, lv2:ControlPort ;\n"; text += " lv2:index " + String(portIndex++) + " ;\n"; @@ -328,8 +328,12 @@ const String makePluginFile (AudioProcessor* const filter) text += " lv2:maximum 1.0 ;\n"; text += " lv2:designation <" LV2_CORE__freeWheeling "> ;\n"; text += " lv2:portProperty lv2:toggled, <" LV2_PORT_PROPS__notOnGUI "> ;\n"; - text += " ] ,\n"; - text += " [\n"; + text += " ] ;\n"; + text += "\n"; + +#if JucePlugin_WantsLV2Latency + // Latency port + text += " lv2:port [\n"; text += " a lv2:OutputPort, lv2:ControlPort ;\n"; text += " lv2:index " + String(portIndex++) + " ;\n"; text += " lv2:symbol \"lv2_latency\" ;\n"; @@ -338,9 +342,10 @@ const String makePluginFile (AudioProcessor* const filter) text += " lv2:portProperty lv2:reportsLatency, lv2:integer ;\n"; text += " ] ;\n"; text += "\n"; +#endif // Audio inputs - for (int i=0; i < JucePlugin_MaxNumInputChannels; ++i) + for (int i=0; i < maxNumInputChannels; ++i) { if (i == 0) text += " lv2:port [\n"; @@ -352,14 +357,14 @@ const String makePluginFile (AudioProcessor* const filter) text += " lv2:symbol \"lv2_audio_in_" + String(i+1) + "\" ;\n"; text += " lv2:name \"Audio Input " + String(i+1) + "\" ;\n"; - if (i+1 == JucePlugin_MaxNumInputChannels) + if (i+1 == maxNumInputChannels) text += " ] ;\n\n"; else text += " ] ,\n"; } // Audio outputs - for (int i=0; i < JucePlugin_MaxNumOutputChannels; ++i) + for (int i=0; i < maxNumOutputChannels; ++i) { if (i == 0) text += " lv2:port [\n"; @@ -371,7 +376,7 @@ const String makePluginFile (AudioProcessor* const filter) text += " lv2:symbol \"lv2_audio_out_" + String(i+1) + "\" ;\n"; text += " lv2:name \"Audio Output " + String(i+1) + "\" ;\n"; - if (i+1 == JucePlugin_MaxNumOutputChannels) + if (i+1 == maxNumOutputChannels) text += " ] ;\n\n"; else text += " ] ,\n"; @@ -455,7 +460,7 @@ const String makePresetsFile (AudioProcessor* const filter) #else MemoryBlock chunkMemory; filter->getCurrentProgramStateInformation(chunkMemory); - const String chunkString(Base64Encode(chunkMemory)); + const String chunkString(Base64::toBase64(chunkMemory.getData(), chunkMemory.getSize())); preset += " <" JUCE_LV2_STATE_BINARY_URI "> [\n"; preset += " a atom:Chunk ;\n"; @@ -501,7 +506,7 @@ const String makePresetsFile (AudioProcessor* const filter) void createLv2Files(const char* basename) { const ScopedJuceInitialiser_GUI juceInitialiser; - ScopedPointer filter (createPluginFilterOfType (AudioProcessor::wrapperType_VST)); // FIXME + ScopedPointer filter (createPluginFilterOfType (AudioProcessor::wrapperType_LV2)); String binary(basename); String binaryTTL(binary + ".ttl"); @@ -514,7 +519,7 @@ void createLv2Files(const char* basename) std::cout << "Writing " << binary << ".ttl..."; std::cout.flush(); std::fstream plugin(binaryTTL.toUTF8(), std::ios::out); - plugin << makePluginFile(filter) << std::endl; + plugin << makePluginFile(filter, JucePlugin_MaxNumInputChannels, JucePlugin_MaxNumOutputChannels) << std::endl; plugin.close(); std::cout << " done!" << std::endl; @@ -560,10 +565,11 @@ public: } private: - bool initialised; + volatile bool initialised; }; #endif +#if ! JUCE_AUDIOPROCESSOR_NO_GUI //============================================================================== /** Lightweight DocumentWindow subclass for external ui @@ -754,7 +760,7 @@ public: const int ch = child->getHeight(); #if JUCE_LINUX - XResizeWindow (display, (Window) getWindowHandle(), cw, ch); + XResizeWindow (display.display, (Window) getWindowHandle(), cw, ch); #else setSize (cw, ch); #endif @@ -774,6 +780,9 @@ public: private: //============================================================================== const LV2UI_Resize* uiResize; +#if JUCE_LINUX + ScopedXDisplay display; +#endif JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceLv2ParentContainer); }; @@ -860,7 +869,10 @@ public: #if JucePlugin_ProducesMidiOutput controlPortOffset += 1; #endif - controlPortOffset += 2; // freewheel and latency + controlPortOffset += 1; // freewheel +#if JucePlugin_WantsLV2Latency + controlPortOffset += 1; +#endif controlPortOffset += JucePlugin_MaxNumInputChannels; controlPortOffset += JucePlugin_MaxNumOutputChannels; @@ -906,8 +918,12 @@ public: } else { - if (parentContainer != nullptr && parentContainer->isOnDesktop()) - parentContainer->removeFromDesktop(); + if (parentContainer) + { + parentContainer->setVisible (false); + if (parentContainer->isOnDesktop()) + parentContainer->removeFromDesktop(); + } } } @@ -1023,6 +1039,10 @@ private: ScopedPointer parentContainer; const LV2UI_Resize* uiResize; +#if JUCE_LINUX + ScopedXDisplay display; +#endif + //============================================================================== void resetExternalUI (const LV2_Feature* const* features) { @@ -1081,7 +1101,7 @@ private: #if JUCE_LINUX Window hostWindow = (Window) parent; Window editorWnd = (Window) parentContainer->getWindowHandle(); - XReparentWindow (display, editorWnd, hostWindow, 0, 0); + XReparentWindow (display.display, editorWnd, hostWindow, 0, 0); #endif parentContainer->reset (uiResize); @@ -1092,6 +1112,8 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceLv2UIWrapper) }; +#endif /* JUCE_AUDIOPROCESSOR_NO_GUI */ + //============================================================================== /** Juce LV2 handle @@ -1124,7 +1146,10 @@ public: uridTimeSpeed (0), usingNominalBlockLength (false) { - filter = createPluginFilterOfType (AudioProcessor::wrapperType_VST); // FIXME + { + const MessageManagerLock mmLock; + filter = createPluginFilterOfType (AudioProcessor::wrapperType_LV2); + } jassert (filter != nullptr); filter->setPlayConfigDetails (numInChans, numOutChans, 0, 0); @@ -1138,7 +1163,10 @@ public: #endif portFreewheel = nullptr; - portLatency = nullptr; + +#if JucePlugin_WantsLV2Latency + portLatency = nullptr; +#endif for (int i=0; i < numInChans; ++i) portAudioIns[i] = nullptr; @@ -1230,7 +1258,9 @@ public: { const MessageManagerLock mmLock; +#if ! JUCE_AUDIOPROCESSOR_NO_GUI ui = nullptr; +#endif filter = nullptr; if (progDesc.name != nullptr) @@ -1269,11 +1299,13 @@ public: return; } +#if JucePlugin_WantsLV2Latency if (portId == index++) { portLatency = (float*)dataLocation; return; } +#endif for (int i=0; i < numInChans; ++i) { @@ -1331,8 +1363,10 @@ public: { jassert (filter != nullptr); +#if JucePlugin_WantsLV2Latency if (portLatency != nullptr) *portLatency = filter->getLatencySamples(); +#endif if (portFreewheel != nullptr) filter->setNonRealtime (*portFreewheel >= 0.5f); @@ -1611,10 +1645,17 @@ public: } #endif - if (! midiEvents.isEmpty()) - { #if JucePlugin_ProducesMidiOutput - if (portMidiOut != nullptr) + if (portMidiOut != nullptr) + { + const uint32_t capacity = portMidiOut->atom.size; + + portMidiOut->atom.size = sizeof(LV2_Atom_Sequence_Body); + portMidiOut->atom.type = uridAtomSequence; + portMidiOut->body.unit = 0; + portMidiOut->body.pad = 0; + + if (! midiEvents.isEmpty()) { const uint8* midiEventData; int midiEventSize, midiEventPosition; @@ -1623,13 +1664,6 @@ public: uint32_t size, offset = 0; LV2_Atom_Event* aev; - const uint32_t capacity = portMidiOut->atom.size; - - portMidiOut->atom.size = 0; - portMidiOut->atom.type = uridAtomSequence; - portMidiOut->body.unit = 0; - portMidiOut->body.pad = 0; - while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) { jassert (midiEventPosition >= 0 && midiEventPosition < (int)sampleCount); @@ -1647,8 +1681,13 @@ public: offset += size; portMidiOut->atom.size += size; } + + midiEvents.clear(); } + } else #endif + if (! midiEvents.isEmpty()) + { midiEvents.clear(); } } @@ -1659,6 +1698,8 @@ public: uint32_t lv2GetOptions (LV2_Options_Option* options) { // currently unused + ignoreUnused(options); + return LV2_OPTIONS_SUCCESS; } @@ -1788,8 +1829,10 @@ public: String stateData (CharPointer_UTF8(static_cast(data))); filter->setStateInformationString (stateData); + #if ! JUCE_AUDIOPROCESSOR_NO_GUI if (ui != nullptr) ui->repaint(); + #endif return LV2_STATE_SUCCESS; } @@ -1798,8 +1841,10 @@ public: { filter->setCurrentProgramStateInformation (data, size); + #if ! JUCE_AUDIOPROCESSOR_NO_GUI if (ui != nullptr) ui->repaint(); + #endif return LV2_STATE_SUCCESS; } @@ -1817,10 +1862,12 @@ public: info = curPosInfo; return true; #else + ignoreUnused(info); return false; #endif } +#if ! JUCE_AUDIOPROCESSOR_NO_GUI //============================================================================== JuceLv2UIWrapper* getUI (LV2UI_Write_Function writeFunction, LV2UI_Controller controller, LV2UI_Widget* widget, const LV2_Feature* const* features, bool isExternal) @@ -1834,6 +1881,7 @@ public: return ui; } +#endif private: #if JUCE_LINUX @@ -1843,7 +1891,9 @@ private: #endif ScopedPointer filter; +#if ! JUCE_AUDIOPROCESSOR_NO_GUI ScopedPointer ui; +#endif HeapBlock channels; MidiBuffer midiEvents; int numInChans, numOutChans; @@ -1855,7 +1905,9 @@ private: LV2_Atom_Sequence* portMidiOut; #endif float* portFreewheel; +#if JucePlugin_WantsLV2Latency float* portLatency; +#endif float* portAudioIns[JucePlugin_MaxNumInputChannels]; float* portAudioOuts[JucePlugin_MaxNumOutputChannels]; Array portControls; @@ -2000,6 +2052,7 @@ static const void* juceLV2_ExtensionData (const char* uri) return nullptr; } +#if ! JUCE_AUDIOPROCESSOR_NO_GUI //============================================================================== // LV2 UI descriptor functions @@ -2035,6 +2088,7 @@ static void juceLV2UI_Cleanup (LV2UI_Handle handle) { ((JuceLv2UIWrapper*)handle)->lv2Cleanup(); } +#endif //============================================================================== // static LV2 Descriptor objects @@ -2050,6 +2104,7 @@ static const LV2_Descriptor JuceLv2Plugin = { juceLV2_ExtensionData }; +#if ! JUCE_AUDIOPROCESSOR_NO_GUI static const LV2UI_Descriptor JuceLv2UI_External = { strdup(String(getPluginURI() + "#ExternalUI").toRawUTF8()), juceLV2UI_InstantiateExternal, @@ -2065,14 +2120,17 @@ static const LV2UI_Descriptor JuceLv2UI_Parent = { nullptr, nullptr }; +#endif static const struct DescriptorCleanup { DescriptorCleanup() {} ~DescriptorCleanup() { free((void*)JuceLv2Plugin.URI); +#if ! JUCE_AUDIOPROCESSOR_NO_GUI free((void*)JuceLv2UI_External.URI); free((void*)JuceLv2UI_Parent.URI); +#endif } } _descCleanup; @@ -2097,6 +2155,7 @@ JUCE_EXPORTED_FUNCTION const LV2_Descriptor* lv2_descriptor (uint32 index) return (index == 0) ? &JuceLv2Plugin : nullptr; } +#if ! JUCE_AUDIOPROCESSOR_NO_GUI JUCE_EXPORTED_FUNCTION const LV2UI_Descriptor* lv2ui_descriptor (uint32 index); JUCE_EXPORTED_FUNCTION const LV2UI_Descriptor* lv2ui_descriptor (uint32 index) { @@ -2110,5 +2169,6 @@ JUCE_EXPORTED_FUNCTION const LV2UI_Descriptor* lv2ui_descriptor (uint32 index) return nullptr; } } +#endif #endif diff --git a/debian/extra/juce_audio_plugin_client/juce_audio_plugin_client_LV2.cpp b/debian/extra/juce_audio_plugin_client/juce_audio_plugin_client_LV2.cpp new file mode 100644 index 00000000..dc507e12 --- /dev/null +++ b/debian/extra/juce_audio_plugin_client/juce_audio_plugin_client_LV2.cpp @@ -0,0 +1,27 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2017 - ROLI Ltd. + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 5 End-User License + Agreement and JUCE 5 Privacy Policy (both updated and effective as of the + 27th April 2017). + + End User License Agreement: www.juce.com/juce-5-licence + Privacy Policy: www.juce.com/juce-5-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "LV2/juce_LV2_Wrapper.cpp" diff --git a/debian/patches/LV2-audioprocessor.patch b/debian/patches/LV2-audioprocessor.patch new file mode 100644 index 00000000..c4511e9e --- /dev/null +++ b/debian/patches/LV2-audioprocessor.patch @@ -0,0 +1,67 @@ +Description: LV2 fixes for autiodprocessor +Author: Filipe Coelho +Origin: https://github.com/DISTRHO/juce/tree/9f6cdc3659df13169285464ee1d13ef14357f833 +Reviewed-by: IOhannes m zmölnig +Last-Update: 2018-02-10 +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +--- juce.orig/modules/juce_audio_processors/processors/juce_AudioProcessor.h ++++ juce/modules/juce_audio_processors/processors/juce_AudioProcessor.h +@@ -908,6 +908,7 @@ + */ + virtual void setNonRealtime (bool isNonRealtime) noexcept; + ++ #if ! JUCE_AUDIOPROCESSOR_NO_GUI + //============================================================================== + /** Creates the processor's GUI. + +@@ -954,6 +955,7 @@ + This may call createEditor() internally to create the component. + */ + AudioProcessorEditor* createEditorIfNeeded(); ++ #endif + + //============================================================================== + /** This must return the correct value immediately after the object has been +@@ -1278,6 +1280,11 @@ + virtual void processorLayoutsChanged(); + + //============================================================================== ++ /** LV2 specific calls, saving/restore as string. */ ++ virtual String getStateInformationString () { return String(); } ++ virtual void setStateInformationString (const String&) {} ++ ++ //============================================================================== + /** Adds a listener that will be called when an aspect of this processor changes. */ + virtual void addListener (AudioProcessorListener* newListener); + +@@ -1319,9 +1326,11 @@ + const AudioChannelSet& mainOutputLayout, + bool idForAudioSuite) const; + ++ #if ! JUCE_AUDIOPROCESSOR_NO_GUI + //============================================================================== + /** Not for public use - this is called before deleting an editor component. */ + void editorBeingDeleted (AudioProcessorEditor*) noexcept; ++ #endif + + /** Flags to indicate the type of plugin context in which a processor is being used. */ + enum WrapperType +@@ -1333,6 +1342,7 @@ + wrapperType_AudioUnitv3, + wrapperType_RTAS, + wrapperType_AAX, ++ wrapperType_LV2, + wrapperType_Standalone + }; + +@@ -1581,7 +1591,9 @@ + + //============================================================================== + Array listeners; ++ #if ! JUCE_AUDIOPROCESSOR_NO_GUI + Component::SafePointer activeEditor; ++ #endif + double currentSampleRate = 0; + int blockSize = 0, latencySamples = 0; + bool suspended = false, nonRealtime = false; diff --git a/debian/patches/series b/debian/patches/series index 31adb158..f147bd8d 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,4 +1,5 @@ reproducible-date.patch +LV2-audioprocessor.patch debian_fixed-defines.patch debian_gpl_variant.patch debian_no-update-check.patch -- 2.30.2