From 53f1321b37ee2ca0dd52cfcca3a4982601a5339a Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 16 Jul 2011 14:23:29 +0100 Subject: [PATCH] Add new stuff from VST wrapper; Basic processing works --- demo/Build/plugin.pro | 2 +- demo/JuceLibraryCode/JucePluginCharacteristics.h | 2 +- juce-dssi.cpp | 10 + .../audio/plugin_client/LV2/juce_LV2_Wrapper.cpp | 245 +++++++++++++++------ .../audio/plugin_client/VST/juce_VST_Wrapper.cpp | 2 + 5 files changed, 196 insertions(+), 65 deletions(-) diff --git a/demo/Build/plugin.pro b/demo/Build/plugin.pro index f317a25..15143f4 100644 --- a/demo/Build/plugin.pro +++ b/demo/Build/plugin.pro @@ -34,4 +34,4 @@ HEADERS = \ ../Source/PluginEditor.h \ ../Source/PluginProcessor.h -LIBS = -g -L../.. -lfreetype -lpthread -lrt -lX11 -lGL -ljuce +LIBS = -L../.. -lfreetype -lpthread -lrt -lX11 -lGL -ljuce_debug diff --git a/demo/JuceLibraryCode/JucePluginCharacteristics.h b/demo/JuceLibraryCode/JucePluginCharacteristics.h index 190dcda..bbac891 100644 --- a/demo/JuceLibraryCode/JucePluginCharacteristics.h +++ b/demo/JuceLibraryCode/JucePluginCharacteristics.h @@ -11,7 +11,7 @@ #ifndef __PLUGINCHARACTERISTICS_D4EFFF1A__ #define __PLUGINCHARACTERISTICS_D4EFFF1A__ -#define JucePlugin_Build_VST 0 // (If you change this value, you'll also need to re-export the projects using the Jucer) +#define JucePlugin_Build_VST 1 // (If you change this value, you'll also need to re-export the projects using the Jucer) #define JucePlugin_Build_AU 0 // (If you change this value, you'll also need to re-export the projects using the Jucer) #define JucePlugin_Build_RTAS 0 // (If you change this value, you'll also need to re-export the projects using the Jucer) #define JucePlugin_Build_LV2 1 diff --git a/juce-dssi.cpp b/juce-dssi.cpp index 8c6dba7..fb8864d 100644 --- a/juce-dssi.cpp +++ b/juce-dssi.cpp @@ -110,6 +110,12 @@ juce_ImplementSingleton (DssiSharedMessageThread); + + + + + + class JuceDSSIWrapper; class DssiEditorCompWrapper : public DocumentWindow @@ -293,6 +299,10 @@ #endif + + + + static Array activePlugins; extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); 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 140058f..0cd0df3 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 @@ -11,8 +11,6 @@ // LV2 includes #include "lv2.h" -extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); - /* Same as juce_lv2_gen.cpp */ String get_uri() { @@ -56,16 +54,30 @@ int get_parameters_padding() return padding; } +//============================================================================== +/** 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 +class JuceLV2Wrapper : private Timer { 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) : + numInChans (JucePlugin_MaxNumInputChannels), + numOutChans (JucePlugin_MaxNumOutputChannels), + isProcessing (false), + hasShutdown (false), + firstProcessCallback (true), + shouldDeleteEditor (false) { printf("JuceLV2Wrapper()\n"); filter = createPluginFilter(); - filter->setPlayConfigDetails(JucePlugin_MaxNumInputChannels, JucePlugin_MaxNumOutputChannels, 0, 0); + filter->setPlayConfigDetails(numInChans, numOutChans, 0, 0); descriptor = _descriptor; //features = _features; @@ -83,18 +95,18 @@ public: port_count += 1; #endif - port_count += JucePlugin_MaxNumInputChannels; - port_count += JucePlugin_MaxNumOutputChannels; + port_count += numInChans; + port_count += numOutChans; port_count += filter->getNumParameters(); ports_ctrl.insertMultiple(0, nullptr, filter->getNumParameters()); ports_ctrl_last.insertMultiple(0, 0.0f, filter->getNumParameters()); - for (int i=0; i < JucePlugin_MaxNumInputChannels; i++) { + for (int i=0; i < numInChans; i++) { ports_ain[i] = nullptr; } - for (int i=0; i < JucePlugin_MaxNumOutputChannels; i++) { + for (int i=0; i < numOutChans; i++) { ports_aout[i] = nullptr; } @@ -102,9 +114,9 @@ public: ports_ctrl_last.set(i, filter->getParameter(i)); } -#if JucePlugin_WantsMidiInput || JucePlugin_ProducesMidiOutput midi_uri_id = 0; // TODO URI-Map Extension -#endif + + activePlugins.add (this); } ~JuceLV2Wrapper() @@ -116,9 +128,12 @@ public: deleteAndZero(filter); } + //============================================================================== + // LV2 Descriptor Calls void do_connect_port(uint32_t port, void* data_location) { if (port < port_count) { + int i; uint32_t index = 0; #if JucePlugin_WantsMidiInput @@ -137,23 +152,26 @@ public: index += 1; #endif - for (int i=0; i < JucePlugin_MaxNumInputChannels; i++) { + for (i=0; i < numInChans; i++) { if (port == index) { ports_ain[i] = (float*)data_location; + return; } index += 1; } - for (int i=0; i < JucePlugin_MaxNumOutputChannels; i++) { + for (i=0; i < numOutChans; i++) { if (port == index) { ports_aout[i] = (float*)data_location; + return; } index += 1; } - for (int i=0; i < filter->getNumParameters(); i++) { + for (i=0; i < filter->getNumParameters(); i++) { if (port == index) { ports_ctrl.set(i, (float*)data_location); + return; } index += 1; } @@ -163,34 +181,60 @@ public: void do_activate() { if (filter != nullptr) { - channels.calloc(JucePlugin_MaxNumInputChannels + JucePlugin_MaxNumOutputChannels); + isProcessing = true; + channels.calloc (numInChans + numOutChans); - filter->setNonRealtime(false); - filter->setPlayConfigDetails(JucePlugin_MaxNumInputChannels, JucePlugin_MaxNumOutputChannels, sample_rate, buffer_size); - filter->prepareToPlay(sample_rate, buffer_size); + jassert (sample_rate > 0); + if (sample_rate <= 0.0) + sample_rate = 44100.0; -#if JucePlugin_WantsMidiInput || JucePlugin_ProducesMidiOutput - midi_buffer.ensureSize(2048); - midi_buffer.clear(); -#endif + jassert (buffer_size > 0); -#if JucePlugin_ProducesMidiOutput - //outgoingEvents.ensureSize (512); -#endif + firstProcessCallback = true; + + filter->setNonRealtime (false); + filter->setPlayConfigDetails (numInChans, numOutChans, sample_rate, buffer_size); + deleteTempChannels(); + + filter->prepareToPlay (sample_rate, buffer_size); + + midiEvents.ensureSize (2048); + midiEvents.clear(); } } void do_run(uint32_t sample_count) { + if (firstProcessCallback) + { + firstProcessCallback = false; + + // if this fails, the host hasn't called resume() before processing + jassert (isProcessing); + + // (tragically, some hosts actually need this, although it's stupid to have + // to do it here..) + if (! isProcessing) + do_activate(); + + filter->setNonRealtime (false); + + #if JUCE_WINDOWS + if (GetThreadPriority (GetCurrentThread()) <= THREAD_PRIORITY_NORMAL + && GetThreadPriority (GetCurrentThread()) >= THREAD_PRIORITY_LOWEST) + filter->setNonRealtime (true); + #endif + } + // Change buffer size if needed if (buffer_size != sample_count) { buffer_size = sample_count; - filter->setPlayConfigDetails(JucePlugin_MaxNumInputChannels, JucePlugin_MaxNumOutputChannels, sample_rate, buffer_size); + filter->setPlayConfigDetails(numInChans, numOutChans, sample_rate, buffer_size); filter->prepareToPlay(sample_rate, buffer_size); } - /* Check for updated parameters */ + // Check for updated parameters int ctrl_pad = get_parameters_padding(); for (int i = 0; i < ports_ctrl.size(); i++) { @@ -202,24 +246,62 @@ public: } } - int k = 0; - for (; k < JucePlugin_MaxNumInputChannels; k++) { - channels[k] = ports_ain[k]; - } + jassert (activePlugins.contains (this)); - for (int j=0; k < JucePlugin_MaxNumOutputChannels; j++, k++) { - channels[k] = ports_ain[j]; - } + { + const ScopedLock sl (filter->getCallbackLock()); - //const ScopedLock sl(filter->getCallbackLock()); + const int numIn = numInChans; + const int numOut = numOutChans; - if (filter->isSuspended()) { - for (int i = 0; i < JucePlugin_MaxNumOutputChannels; i++) { - zeromem(ports_aout[i], sizeof(float) * sample_count); + if (filter->isSuspended()) + { + for (int i = 0; i < numOut; ++i) + zeromem (ports_aout[i], sizeof (float) * sample_count); } - } else { - AudioSampleBuffer chans(channels, jmax(JucePlugin_MaxNumInputChannels, JucePlugin_MaxNumOutputChannels), sample_count); - filter->processBlock(chans, midi_buffer); + else + { + int i; + for (i = 0; i < numOut; ++i) + { + float* chan = tempChannels.getUnchecked(i); + + if (chan == 0) + { + chan = ports_aout[i]; + + // if some output channels are disabled, some hosts supply the same buffer + // for multiple channels - this buggers up our method of copying the + // inputs over the outputs, so we need to create unique temp buffers in this case.. + for (int j = i; --j >= 0;) + { + if (ports_aout[j] == chan) + { + chan = new float [buffer_size * 2]; + tempChannels.set (i, chan); + break; + } + } + } + + if (i < numIn && chan != ports_ain[i]) + memcpy (chan, ports_ain[i], sizeof (float) * sample_count); + + channels[i] = chan; + } + + for (; i < numIn; ++i) + channels[i] = ports_ain[i]; + + AudioSampleBuffer chans (channels, jmax (numIn, numOut), sample_count); + + filter->processBlock (chans, midiEvents); + } + } + + if (! midiEvents.isEmpty()) + { + midiEvents.clear(); } } @@ -228,79 +310,97 @@ public: if (filter != nullptr) { filter->releaseResources(); - //outgoingEvents.freeEvents(); + + isProcessing = false; channels.free(); + + deleteTempChannels(); + } + } + + //============================================================================== + // JUCE Stuff + void timerCallback() + { + if (shouldDeleteEditor) + { + shouldDeleteEditor = false; + //deleteEditor (true); } } + //============================================================================== private: + MidiBuffer midiEvents; + int numInChans, numOutChans; + bool isProcessing, hasShutdown, firstProcessCallback, shouldDeleteEditor; + HeapBlock channels; + Array tempChannels; // see note in processReplacing() + AudioProcessor* filter; const LV2_Descriptor* descriptor; double sample_rate; int buffer_size; + uint16_t midi_uri_id; uint32_t port_count; -#if JucePlugin_WantsMidiInput void* port_min; -#endif -#if JucePlugin_ProducesMidiOutput void* port_mout; -#endif - float* ports_ain[JucePlugin_MaxNumInputChannels]; float* ports_aout[JucePlugin_MaxNumOutputChannels]; - Array ports_ctrl; Array ports_ctrl_last; - HeapBlock channels; + //============================================================================== + void deleteTempChannels() + { + for (int i = tempChannels.size(); --i >= 0;) + delete[] (tempChannels.getUnchecked(i)); -#if JucePlugin_WantsMidiInput || JucePlugin_ProducesMidiOutput - uint16_t midi_uri_id; - MidiBuffer midi_buffer; -#endif + tempChannels.clear(); + + if (filter != nullptr) + tempChannels.insertMultiple (0, 0, filter->getNumInputChannels() + filter->getNumOutputChannels()); + } + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceLV2Wrapper); }; -/* LV2 descriptor functions */ +//============================================================================== +// LV2 descriptor functions LV2_Handle juce_lv2_instantiate(const LV2_Descriptor* descriptor, double sample_rate, const char* bundle_path, const LV2_Feature* const* features) { - printf("juce_lv2_instantiate()\n"); JuceLV2Wrapper* wrapper = new JuceLV2Wrapper(descriptor, sample_rate, features); return wrapper; } void juce_lv2_connect_port(LV2_Handle instance, uint32_t port, void* data_location) { - printf("juce_lv2_connect_port()\n"); JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance; wrapper->do_connect_port(port, data_location); } void juce_lv2_activate(LV2_Handle instance) { - printf("juce_lv2_activate()\n"); JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance; wrapper->do_activate(); } void juce_lv2_run(LV2_Handle instance, uint32_t sample_count) { - printf("juce_lv2_run()\n"); JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance; wrapper->do_run(sample_count); } void juce_lv2_deactivate(LV2_Handle instance) { - printf("juce_lv2_deactivate()\n"); JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance; wrapper->do_deactivate(); } void juce_lv2_cleanup(LV2_Handle instance) { - printf("juce_lv2_cleanup()\n"); JuceLV2Wrapper* wrapper = (JuceLV2Wrapper*)instance; //free((void*)wrapper->descriptor->URI); //delete wrapper->descriptor; @@ -313,10 +413,11 @@ const void* juce_lv2_extension_data(const char* uri) return nullptr; } -/* Create a new LV2 Plugin object */ +//============================================================================== +// Create a new LV2 Plugin object LV2_Descriptor* getNewLv2Plugin() { - LV2_Descriptor* const Lv2Plugin = new LV2_Descriptor; + LV2_Descriptor* Lv2Plugin = new LV2_Descriptor; Lv2Plugin->URI = strdup((const char*)get_uri().toUTF8()); Lv2Plugin->instantiate = juce_lv2_instantiate; Lv2Plugin->connect_port = juce_lv2_connect_port; @@ -328,13 +429,31 @@ LV2_Descriptor* getNewLv2Plugin() return Lv2Plugin; } -#if JUCE_MAC || JUCE_LINUX +//============================================================================== +// Mac startup code.. +#if JUCE_MAC extern "C" __attribute__ ((visibility("default"))) const LV2_Descriptor* lv2_descriptor(uint32_t index) { + initialiseMac(); return (index == 0) ? getNewLv2Plugin() : nullptr; } +//============================================================================== +// Linux startup code.. +#elif JUCE_LINUX + + extern "C" __attribute__ ((visibility("default"))) const LV2_Descriptor* lv2_descriptor(uint32_t index) + { + return (index == 0) ? getNewLv2Plugin() : nullptr; + } + + // don't put initialiseJuce_GUI or shutdownJuce_GUI in these... it will crash! + __attribute__((constructor)) void myPluginInit() {} + __attribute__((destructor)) void myPluginFini() {} + +//============================================================================== +// Win32 startup code.. #else extern "C" __declspec (dllexport) const LV2_Descriptor* lv2_descriptor(uint32_t index) 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 c6f9cee..50857b0 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,6 +23,8 @@ ============================================================================== */ +#define LINUX 1 + #ifdef _MSC_VER #pragma warning (disable : 4996 4100) #endif -- 2.11.4.GIT