/* * Fake juce event thread needed for juce_audio_processors * Copyright (C) 2014 Filipe Coelho * * 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 { /* * We need to know when we're initializing because MessageManager::setCurrentThreadAsMessageThread() * calls doPlatformSpecificInitialisation/Shutdown, in which we started this thread previously. * To avoid a deadlock we do not call start/stopThread if still initializing. */ 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: volatile bool fInitializing; CriticalSection fLock; ReferenceCountedArray 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); } bool MessageManager::dispatchNextMessageOnSystemQueue(bool) { carla_stderr2("MessageManager::dispatchNextMessageOnSystemQueue() unsupported"); return false; } } // namespace juce #endif // ! CARLA_OS_MAC || CARLA_OS_WIN