| @@ -2300,133 +2300,6 @@ const char* carla_get_host_osc_url_udp() | |||
| #include "CarlaPluginUI.cpp" | |||
| #include "CarlaDssiUtils.cpp" | |||
| #include "CarlaStateUtils.cpp" | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // need to build juce_audio_processors on non-win/mac OSes | |||
| #if ! (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)) | |||
| #undef KeyPress | |||
| #include "juce_audio_processors.h" | |||
| #include "juce_events.h" | |||
| namespace juce { | |||
| #include "juce_events/broadcasters/juce_AsyncUpdater.cpp" | |||
| #include "juce_events/messages/juce_ApplicationBase.cpp" | |||
| #include "juce_events/messages/juce_DeletedAtShutdown.cpp" | |||
| #include "juce_events/messages/juce_MessageManager.cpp" | |||
| #include "juce_audio_processors/processors/juce_AudioProcessor.cpp" | |||
| #include "juce_audio_processors/processors/juce_AudioProcessorGraph.cpp" | |||
| class JuceEventsThread : public Thread | |||
| { | |||
| public: | |||
| JuceEventsThread() | |||
| : Thread("JuceEventsThread"), | |||
| fInitializing(false), | |||
| fLock(), | |||
| fQueue(), | |||
| leakDetector_JuceEventsThread() {} | |||
| ~JuceEventsThread() | |||
| { | |||
| signalThreadShouldExit(); | |||
| stopThread(2000); | |||
| const ScopedLock sl(fLock); | |||
| fQueue.clear(); | |||
| } | |||
| bool postMessage(MessageManager::MessageBase* const msg) | |||
| { | |||
| const ScopedLock sl(fLock); | |||
| fQueue.add(msg); | |||
| return true; | |||
| } | |||
| bool isInitializing() const noexcept | |||
| { | |||
| return fInitializing; | |||
| } | |||
| protected: | |||
| void run() override | |||
| { | |||
| fInitializing = true; | |||
| if (MessageManager* const msgMgr = MessageManager::getInstance()) | |||
| msgMgr->setCurrentThreadAsMessageThread(); | |||
| fInitializing = false; | |||
| for (; ! threadShouldExit();) | |||
| { | |||
| // dispatch messages until no more present, then sleep | |||
| for (; dispatchNextInternalMessage();) {} | |||
| sleep(25); | |||
| } | |||
| } | |||
| private: | |||
| bool fInitializing; | |||
| CriticalSection fLock; | |||
| ReferenceCountedArray<MessageManager::MessageBase> fQueue; | |||
| MessageManager::MessageBase::Ptr popNextMessage() | |||
| { | |||
| const ScopedLock sl(fLock); | |||
| return fQueue.removeAndReturn(0); | |||
| } | |||
| bool dispatchNextInternalMessage() | |||
| { | |||
| if (const MessageManager::MessageBase::Ptr msg = popNextMessage()) | |||
| { | |||
| JUCE_TRY | |||
| { | |||
| msg->messageCallback(); | |||
| return true; | |||
| } | |||
| JUCE_CATCH_EXCEPTION | |||
| } | |||
| return false; | |||
| } | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JuceEventsThread) | |||
| }; | |||
| static JuceEventsThread& getJuceEventsThreadInstance() | |||
| { | |||
| static JuceEventsThread sJuceEventsThread; | |||
| return sJuceEventsThread; | |||
| } | |||
| void MessageManager::doPlatformSpecificInitialisation() | |||
| { | |||
| JuceEventsThread& juceEventsThread(getJuceEventsThreadInstance()); | |||
| if (! juceEventsThread.isInitializing()) | |||
| juceEventsThread.startThread(); | |||
| } | |||
| void MessageManager::doPlatformSpecificShutdown() | |||
| { | |||
| JuceEventsThread& juceEventsThread(getJuceEventsThreadInstance()); | |||
| if (! juceEventsThread.isInitializing()) | |||
| juceEventsThread.stopThread(-1); | |||
| } | |||
| bool MessageManager::postMessageToSystemQueue(MessageManager::MessageBase* const message) | |||
| { | |||
| JuceEventsThread& juceEventsThread(getJuceEventsThreadInstance()); | |||
| return juceEventsThread.postMessage(message); | |||
| } | |||
| } // namespace juce | |||
| #endif | |||
| #include "CarlaJuceEvents.cpp" | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| @@ -565,8 +565,10 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, cons | |||
| ++pData->curPluginCount; | |||
| callback(ENGINE_CALLBACK_PLUGIN_ADDED, id, 0, 0, 0.0f, plugin->getName()); | |||
| #ifndef BUILD_BRIDGE | |||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||
| pData->graph.addPlugin(plugin); | |||
| #endif | |||
| } | |||
| return true; | |||
| @@ -641,8 +643,10 @@ bool CarlaEngine::removeAllPlugins() | |||
| const bool lockWait(isRunning()); | |||
| const ScopedActionLock sal(pData, kEnginePostActionZeroCount, 0, 0, lockWait); | |||
| #ifndef BUILD_BRIDGE | |||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||
| pData->graph.removeAllPlugins(); | |||
| #endif | |||
| callback(ENGINE_CALLBACK_IDLE, 0, 0, 0, 0.0f, nullptr); | |||
| @@ -1023,7 +1023,6 @@ public: | |||
| bool isInputChannelStereoPair(int) const override { return false; } | |||
| bool isOutputChannelStereoPair(int) const override { return false; } | |||
| bool silenceInProducesSilenceOut() const override { return true; } | |||
| bool hasEditor() const override { return false; } | |||
| bool acceptsMidi() const override { return fPlugin->getDefaultEventInPort() != nullptr; } | |||
| bool producesMidi() const override { return fPlugin->getDefaultEventOutPort() != nullptr; } | |||
| @@ -1037,7 +1036,10 @@ public: | |||
| int getNumPrograms() override { return 0; } | |||
| int getCurrentProgram() override { return 0; } | |||
| #if ! JUCE_AUDIO_PROCESSOR_NO_GUI | |||
| bool hasEditor() const override { return false; } | |||
| AudioProcessorEditor* createEditor() override { return nullptr; } | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| @@ -1682,6 +1682,7 @@ CARLA_BACKEND_END_NAMESPACE | |||
| #include "CarlaPluginUI.cpp" | |||
| #include "CarlaDssiUtils.cpp" | |||
| #include "CarlaStateUtils.cpp" | |||
| #include "CarlaJuceEvents.cpp" | |||
| #endif | |||
| @@ -44,9 +44,11 @@ AudioProcessor::AudioProcessor() | |||
| AudioProcessor::~AudioProcessor() | |||
| { | |||
| #if ! JUCE_AUDIO_PROCESSOR_NO_GUI | |||
| // ooh, nasty - the editor should have been deleted before the filter | |||
| // that it refers to is deleted.. | |||
| jassert (activeEditor == nullptr); | |||
| #endif | |||
| #if JUCE_DEBUG | |||
| // This will fail if you've called beginParameterChangeGesture() for one | |||
| @@ -215,6 +217,7 @@ void AudioProcessor::suspendProcessing (const bool shouldBeSuspended) | |||
| void AudioProcessor::reset() {} | |||
| void AudioProcessor::processBlockBypassed (AudioSampleBuffer&, MidiBuffer&) {} | |||
| #if ! JUCE_AUDIO_PROCESSOR_NO_GUI | |||
| //============================================================================== | |||
| void AudioProcessor::editorBeingDeleted (AudioProcessorEditor* const editor) noexcept | |||
| { | |||
| @@ -245,6 +248,7 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded() | |||
| return ed; | |||
| } | |||
| #endif | |||
| //============================================================================== | |||
| void AudioProcessor::getCurrentProgramStateInformation (juce::MemoryBlock& destData) | |||
| @@ -327,6 +327,7 @@ public: | |||
| */ | |||
| virtual void setNonRealtime (bool isNonRealtime) noexcept; | |||
| #if ! JUCE_AUDIO_PROCESSOR_NO_GUI | |||
| //============================================================================== | |||
| /** Creates the filter's UI. | |||
| @@ -372,6 +373,7 @@ public: | |||
| This may call createEditor() internally to create the component. | |||
| */ | |||
| AudioProcessorEditor* createEditorIfNeeded(); | |||
| #endif | |||
| //============================================================================== | |||
| /** This must return the correct value immediately after the object has been | |||
| @@ -600,9 +602,11 @@ public: | |||
| /** This is called by the processor to specify its details before being played. */ | |||
| void setPlayConfigDetails (int numIns, int numOuts, double sampleRate, int blockSize) noexcept; | |||
| #if ! JUCE_AUDIO_PROCESSOR_NO_GUI | |||
| //============================================================================== | |||
| /** Not for public use - this is called before deleting an editor component. */ | |||
| void editorBeingDeleted (AudioProcessorEditor*) noexcept; | |||
| #endif | |||
| /** Not for public use - this is called to initialise the processor before playing. */ | |||
| void setSpeakerArrangement (const String& inputs, const String& outputs); | |||
| @@ -655,7 +659,9 @@ protected: | |||
| private: | |||
| Array<AudioProcessorListener*> listeners; | |||
| #if ! JUCE_AUDIO_PROCESSOR_NO_GUI | |||
| Component::SafePointer<AudioProcessorEditor> activeEditor; | |||
| #endif | |||
| double sampleRate; | |||
| int blockSize, numInputChannels, numOutputChannels, latencySamples; | |||
| bool suspended, nonRealtime; | |||
| @@ -69,6 +69,11 @@ | |||
| #define JUCE_USE_VFORK 1 | |||
| #if ! (JUCE_MAC || JUCE_WINDOWS) | |||
| # define JUCE_MODAL_LOOPS_PERMITTED 0 | |||
| # define JUCE_AUDIO_PROCESSOR_NO_GUI 1 | |||
| #endif | |||
| // always enabled | |||
| #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_audio_formats 1 | |||
| @@ -0,0 +1,148 @@ | |||
| /* | |||
| * Fake juce event thread needed for juce_audio_processors | |||
| * Copyright (C) 2014 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaJuceUtils.hpp" | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| #if ! (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)) | |||
| #undef KeyPress | |||
| #include "juce_audio_processors.h" | |||
| #include "juce_events.h" | |||
| namespace juce { | |||
| #include "juce_events/broadcasters/juce_ActionBroadcaster.cpp" | |||
| #include "juce_events/broadcasters/juce_AsyncUpdater.cpp" | |||
| #include "juce_events/messages/juce_DeletedAtShutdown.cpp" | |||
| #include "juce_events/messages/juce_MessageManager.cpp" | |||
| #include "juce_audio_processors/processors/juce_AudioProcessor.cpp" | |||
| #include "juce_audio_processors/processors/juce_AudioProcessorGraph.cpp" | |||
| class JuceEventsThread : public Thread | |||
| { | |||
| public: | |||
| JuceEventsThread() | |||
| : Thread("JuceEventsThread"), | |||
| fInitializing(false), | |||
| fLock(), | |||
| fQueue(), | |||
| leakDetector_JuceEventsThread() {} | |||
| ~JuceEventsThread() | |||
| { | |||
| signalThreadShouldExit(); | |||
| stopThread(2000); | |||
| const ScopedLock sl(fLock); | |||
| fQueue.clear(); | |||
| } | |||
| bool postMessage(MessageManager::MessageBase* const msg) | |||
| { | |||
| const ScopedLock sl(fLock); | |||
| fQueue.add(msg); | |||
| return true; | |||
| } | |||
| bool isInitializing() const noexcept | |||
| { | |||
| return fInitializing; | |||
| } | |||
| protected: | |||
| void run() override | |||
| { | |||
| fInitializing = true; | |||
| if (MessageManager* const msgMgr = MessageManager::getInstance()) | |||
| msgMgr->setCurrentThreadAsMessageThread(); | |||
| fInitializing = false; | |||
| for (; ! threadShouldExit();) | |||
| { | |||
| // dispatch messages until no more present, then sleep | |||
| for (; dispatchNextInternalMessage();) {} | |||
| sleep(25); | |||
| } | |||
| } | |||
| private: | |||
| bool fInitializing; | |||
| CriticalSection fLock; | |||
| ReferenceCountedArray<MessageManager::MessageBase> fQueue; | |||
| MessageManager::MessageBase::Ptr popNextMessage() | |||
| { | |||
| const ScopedLock sl(fLock); | |||
| return fQueue.removeAndReturn(0); | |||
| } | |||
| bool dispatchNextInternalMessage() | |||
| { | |||
| if (const MessageManager::MessageBase::Ptr msg = popNextMessage()) | |||
| { | |||
| JUCE_TRY | |||
| { | |||
| msg->messageCallback(); | |||
| return true; | |||
| } | |||
| JUCE_CATCH_EXCEPTION | |||
| } | |||
| return false; | |||
| } | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JuceEventsThread) | |||
| }; | |||
| static JuceEventsThread& getJuceEventsThreadInstance() | |||
| { | |||
| static JuceEventsThread sJuceEventsThread; | |||
| return sJuceEventsThread; | |||
| } | |||
| JUCEApplicationBase::CreateInstanceFunction JUCEApplicationBase::createInstance = nullptr; | |||
| void MessageManager::doPlatformSpecificInitialisation() | |||
| { | |||
| JuceEventsThread& juceEventsThread(getJuceEventsThreadInstance()); | |||
| if (! juceEventsThread.isInitializing()) | |||
| juceEventsThread.startThread(); | |||
| } | |||
| void MessageManager::doPlatformSpecificShutdown() | |||
| { | |||
| JuceEventsThread& juceEventsThread(getJuceEventsThreadInstance()); | |||
| if (! juceEventsThread.isInitializing()) | |||
| juceEventsThread.stopThread(-1); | |||
| } | |||
| bool MessageManager::postMessageToSystemQueue(MessageManager::MessageBase* const message) | |||
| { | |||
| JuceEventsThread& juceEventsThread(getJuceEventsThreadInstance()); | |||
| return juceEventsThread.postMessage(message); | |||
| } | |||
| } // namespace juce | |||
| #endif // ! CARLA_OS_MAC || CARLA_OS_WIN | |||