From 6fe090f2cb4571c4b524464ade43bba74d7ebf79 Mon Sep 17 00:00:00 2001 From: jules Date: Thu, 16 Jul 2009 15:41:42 +0000 Subject: [PATCH] Added code to make the mac detect its executable file, removing the need for the juce_setCurrentExecutable function, and removed this function from the codebase. --- .../juce_linux_Files.cpp | 25 +- .../platform_specific_code/juce_mac_Files.mm | 27 +- .../juce_mac_NativeIncludes.h | 1 + .../juce_posix_SharedCode.h | 7 + .../juce_win32_Files.cpp | 6 - .../wrapper/AU/juce_AU_Wrapper.mm | 8 - .../wrapper/RTAS/juce_RTAS_MacUtilities.mm | 246 +- .../wrapper/VST/juce_VST_Wrapper.cpp | 3089 ++++++++--------- juce_amalgamated.cpp | 73 +- .../application/juce_Application.cpp | 3 - 10 files changed, 1696 insertions(+), 1789 deletions(-) diff --git a/build/linux/platform_specific_code/juce_linux_Files.cpp b/build/linux/platform_specific_code/juce_linux_Files.cpp index ff1d102990..95c592fc02 100644 --- a/build/linux/platform_specific_code/juce_linux_Files.cpp +++ b/build/linux/platform_specific_code/juce_linux_Files.cpp @@ -70,10 +70,6 @@ BEGIN_JUCE_NAMESPACE #include "../../macosx/platform_specific_code/juce_posix_SharedCode.h" -//============================================================================== -static File executableFile; - - //============================================================================== void juce_getFileTimes (const String& fileName, int64& modificationTime, @@ -262,21 +258,7 @@ const File File::getSpecialLocation (const SpecialLocationType type) case currentExecutableFile: case currentApplicationFile: - if (! executableFile.exists()) - { - Dl_info executableInfo; - dladdr ((const void*) juce_getFileTimes, &executableInfo); - - if (executableInfo.dli_fname != 0) - executableFile = File (String (executableInfo.dli_fname)); - } - - // if this fails, it's probably because juce_setCurrentExecutableFileName() - // was never called to set the filename - this should be done by the juce - // main() function, so maybe you've hacked it to use your own custom main()? - jassert (executableFile.exists()); - - return executableFile; + return juce_getExecutableFile(); default: jassertfalse // unknown type? @@ -286,11 +268,6 @@ const File File::getSpecialLocation (const SpecialLocationType type) return File::nonexistent; } -//============================================================================== -void juce_setCurrentExecutableFileName (const String& filename) throw() -{ - executableFile = File::getCurrentWorkingDirectory().getChildFile (filename); -} //============================================================================== const File File::getCurrentWorkingDirectory() throw() diff --git a/build/macosx/platform_specific_code/juce_mac_Files.mm b/build/macosx/platform_specific_code/juce_mac_Files.mm index 2bd683d16c..b193a3ed43 100644 --- a/build/macosx/platform_specific_code/juce_mac_Files.mm +++ b/build/macosx/platform_specific_code/juce_mac_Files.mm @@ -39,8 +39,6 @@ */ //============================================================================== -static File executableFile; - const unsigned int macTimeToUnixTimeDiff = 0x7c25be90; static uint64 utcDateTimeToUnixTime (const UTCDateTime& d) throw() @@ -281,22 +279,23 @@ const File File::getSpecialLocation (const SpecialLocationType type) case tempDirectory: { - File tmp (T("~/Library/Caches/") + executableFile.getFileNameWithoutExtension()); + File tmp (T("~/Library/Caches/") + juce_getExecutableFile().getFileNameWithoutExtension()); tmp.createDirectory(); return tmp.getFullPathName(); } case currentExecutableFile: - return executableFile; + return juce_getExecutableFile(); case currentApplicationFile: { - const File parent (executableFile.getParentDirectory()); + const File exe (juce_getExecutableFile()); + const File parent (exe.getParentDirectory()); return parent.getFullPathName().endsWithIgnoreCase (T("Contents/MacOS")) ? parent.getParentDirectory().getParentDirectory() - : executableFile; + : exe; } default: @@ -310,22 +309,6 @@ const File File::getSpecialLocation (const SpecialLocationType type) return File::nonexistent; } -void juce_setCurrentExecutableFileName (const String& filename) throw() -{ - executableFile = File::getCurrentWorkingDirectory() - .getChildFile (PlatformUtilities::convertToPrecomposedUnicode (filename)); -} - -void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw() -{ - const ScopedAutoReleasePool pool; - - NSBundle* b = [NSBundle bundleWithIdentifier: juceStringToNS (bundleId)]; - - if (b != nil) - executableFile = nsStringToJuce ([b executablePath]); -} - //============================================================================== const File File::getCurrentWorkingDirectory() throw() { diff --git a/build/macosx/platform_specific_code/juce_mac_NativeIncludes.h b/build/macosx/platform_specific_code/juce_mac_NativeIncludes.h index 6ef6cfdc80..62aa280bf3 100644 --- a/build/macosx/platform_specific_code/juce_mac_NativeIncludes.h +++ b/build/macosx/platform_specific_code/juce_mac_NativeIncludes.h @@ -64,6 +64,7 @@ #include #include #include +#include #if MACOS_10_4_OR_EARLIER #include diff --git a/build/macosx/platform_specific_code/juce_posix_SharedCode.h b/build/macosx/platform_specific_code/juce_posix_SharedCode.h index e879f8ce44..5f7c91be3f 100644 --- a/build/macosx/platform_specific_code/juce_posix_SharedCode.h +++ b/build/macosx/platform_specific_code/juce_posix_SharedCode.h @@ -320,6 +320,13 @@ void juce_fileFlush (void* handle) throw() fsync ((int) (pointer_sized_int) handle); } +const File juce_getExecutableFile() +{ + Dl_info exeInfo; + dladdr ((const void*) juce_getExecutableFile, &exeInfo); + return File (exeInfo.dli_fname); +} + //============================================================================== // if this file doesn't exist, find a parent of it that does.. static bool doStatFS (const File* file, struct statfs& result) throw() diff --git a/build/win32/platform_specific_code/juce_win32_Files.cpp b/build/win32/platform_specific_code/juce_win32_Files.cpp index 65886419e1..b6af68d04e 100644 --- a/build/win32/platform_specific_code/juce_win32_Files.cpp +++ b/build/win32/platform_specific_code/juce_win32_Files.cpp @@ -512,12 +512,6 @@ const File JUCE_CALLTYPE File::getSpecialLocation (const SpecialLocationType typ return juce_getSpecialFolderPath (csidlType); } - -void juce_setCurrentExecutableFileName (const String&) throw() -{ - // n/a on windows -} - //============================================================================== const File File::getCurrentWorkingDirectory() throw() { diff --git a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm index eeea235489..8cab830368 100644 --- a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm +++ b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm @@ -60,10 +60,6 @@ static VoidArray activePlugins; static const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; static const int numChannelConfigs = numElementsInArray (channelConfigs); -BEGIN_JUCE_NAMESPACE -extern void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw(); -END_JUCE_NAMESPACE - #if JucePlugin_IsSynth #define JuceAUBaseClass MusicDeviceBase #else @@ -119,10 +115,6 @@ public: #endif initialiseJuce_GUI(); - -#ifdef JucePlugin_CFBundleIdentifier - juce_setCurrentExecutableFileNameFromBundleId (JucePlugin_CFBundleIdentifier); -#endif } juceFilter = createPluginFilter(); diff --git a/extras/audio plugins/wrapper/RTAS/juce_RTAS_MacUtilities.mm b/extras/audio plugins/wrapper/RTAS/juce_RTAS_MacUtilities.mm index 373f614b9b..63b3357b0b 100644 --- a/extras/audio plugins/wrapper/RTAS/juce_RTAS_MacUtilities.mm +++ b/extras/audio plugins/wrapper/RTAS/juce_RTAS_MacUtilities.mm @@ -1,127 +1,119 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the - GNU General Public License, as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - JUCE 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. - - You should have received a copy of the GNU General Public License - along with JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -// If you get an error here, you might need to make sure that -// your build config files don't specify "C++" as one of the -// flags in OTHER_CFLAGS, because that stops the compiler building -// obj-c files correctly. -@class dummyclassname; - -// Horrible carbon-based fix for a cocoa bug, where an NSWindow that wraps a carbon -// window fails to keep its position updated when the user drags the window around.. -#define WINDOWPOSITON_BODGE 1 - -#if WINDOWPOSITON_BODGE - #include -#endif - -#include -#include "../juce_PluginHeaders.h" - -#if JucePlugin_Build_RTAS - -BEGIN_JUCE_NAMESPACE - extern void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw(); -END_JUCE_NAMESPACE - -//============================================================================== -void initialiseMacRTAS() -{ - NSApplicationLoad(); - -#if defined (JucePlugin_CFBundleIdentifier) - juce_setCurrentExecutableFileNameFromBundleId (JucePlugin_CFBundleIdentifier); -#endif -} - -void* attachSubWindow (void* hostWindowRef, Component* comp) -{ - const ScopedAutoReleasePool pool; - - NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: hostWindowRef]; - [hostWindow retain]; - [hostWindow setCanHide: YES]; - [hostWindow setReleasedWhenClosed: YES]; - - NSView* content = [hostWindow contentView]; - NSRect f = [content frame]; - f.size.width = comp->getWidth(); - f.size.height = comp->getHeight(); - [content setFrame: f]; - -#if WINDOWPOSITON_BODGE - { - Rect winBounds; - GetWindowBounds ((WindowRef) hostWindowRef, kWindowContentRgn, &winBounds); - NSRect w = [hostWindow frame]; - w.origin.x = winBounds.left; - w.origin.y = [[NSScreen mainScreen] frame].size.height - winBounds.bottom; - [hostWindow setFrame: w display: NO animate: NO]; - } -#endif - - NSPoint windowPos = [hostWindow convertBaseToScreen: f.origin]; - windowPos.y = [[NSScreen mainScreen] frame].size.height - (windowPos.y + f.size.height); - - comp->setTopLeftPosition ((int) windowPos.x, (int) windowPos.y); - -#if ! JucePlugin_EditorRequiresKeyboardFocus - comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses); -#else - comp->addToDesktop (ComponentPeer::windowIsTemporary); -#endif - - comp->setVisible (true); - - NSView* pluginView = (NSView*) comp->getWindowHandle(); - NSWindow* pluginWindow = [pluginView window]; - - [hostWindow addChildWindow: pluginWindow - ordered: NSWindowAbove]; - [hostWindow orderFront: nil]; - [pluginWindow orderFront: nil]; - return hostWindow; -} - -void removeSubWindow (void* nsWindow, Component* comp) -{ - const ScopedAutoReleasePool pool; - - NSView* pluginView = (NSView*) comp->getWindowHandle(); - NSWindow* hostWindow = (NSWindow*) nsWindow; - NSWindow* pluginWindow = [pluginView window]; - - [hostWindow removeChildWindow: pluginWindow]; - comp->removeFromDesktop(); - [hostWindow release]; -} - -#endif +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + JUCE 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. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +// If you get an error here, you might need to make sure that +// your build config files don't specify "C++" as one of the +// flags in OTHER_CFLAGS, because that stops the compiler building +// obj-c files correctly. +@class dummyclassname; + +// Horrible carbon-based fix for a cocoa bug, where an NSWindow that wraps a carbon +// window fails to keep its position updated when the user drags the window around.. +#define WINDOWPOSITON_BODGE 1 + +#if WINDOWPOSITON_BODGE + #include +#endif + +#include +#include "../juce_PluginHeaders.h" + +#if JucePlugin_Build_RTAS + +//============================================================================== +void initialiseMacRTAS() +{ + NSApplicationLoad(); +} + +void* attachSubWindow (void* hostWindowRef, Component* comp) +{ + const ScopedAutoReleasePool pool; + + NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: hostWindowRef]; + [hostWindow retain]; + [hostWindow setCanHide: YES]; + [hostWindow setReleasedWhenClosed: YES]; + + NSView* content = [hostWindow contentView]; + NSRect f = [content frame]; + f.size.width = comp->getWidth(); + f.size.height = comp->getHeight(); + [content setFrame: f]; + +#if WINDOWPOSITON_BODGE + { + Rect winBounds; + GetWindowBounds ((WindowRef) hostWindowRef, kWindowContentRgn, &winBounds); + NSRect w = [hostWindow frame]; + w.origin.x = winBounds.left; + w.origin.y = [[NSScreen mainScreen] frame].size.height - winBounds.bottom; + [hostWindow setFrame: w display: NO animate: NO]; + } +#endif + + NSPoint windowPos = [hostWindow convertBaseToScreen: f.origin]; + windowPos.y = [[NSScreen mainScreen] frame].size.height - (windowPos.y + f.size.height); + + comp->setTopLeftPosition ((int) windowPos.x, (int) windowPos.y); + +#if ! JucePlugin_EditorRequiresKeyboardFocus + comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses); +#else + comp->addToDesktop (ComponentPeer::windowIsTemporary); +#endif + + comp->setVisible (true); + + NSView* pluginView = (NSView*) comp->getWindowHandle(); + NSWindow* pluginWindow = [pluginView window]; + + [hostWindow addChildWindow: pluginWindow + ordered: NSWindowAbove]; + [hostWindow orderFront: nil]; + [pluginWindow orderFront: nil]; + return hostWindow; +} + +void removeSubWindow (void* nsWindow, Component* comp) +{ + const ScopedAutoReleasePool pool; + + NSView* pluginView = (NSView*) comp->getWindowHandle(); + NSWindow* hostWindow = (NSWindow*) nsWindow; + NSWindow* pluginWindow = [pluginView window]; + + [hostWindow removeChildWindow: pluginWindow]; + comp->removeFromDesktop(); + [hostWindow release]; +} + +#endif diff --git a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp index 5f0dee8a2b..935c57216e 100644 --- a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp +++ b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp @@ -1,1547 +1,1542 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the - GNU General Public License, as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - JUCE 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. - - You should have received a copy of the GNU General Public License - along with JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -#ifdef _MSC_VER - #pragma warning (disable : 4996) -#endif - -#ifdef _WIN32 - #include -#elif defined (LINUX) - #include - #include - #include - #undef KeyPress -#else - #include -#endif - -#ifdef PRAGMA_ALIGN_SUPPORTED - #undef PRAGMA_ALIGN_SUPPORTED - #define PRAGMA_ALIGN_SUPPORTED 1 -#endif - -#include "../juce_IncludeCharacteristics.h" - -#if JucePlugin_Build_VST - -//============================================================================== -/* These files come with the Steinberg VST SDK - to get them, you'll need to - visit the Steinberg website and jump through some hoops to sign up as a - VST developer. - - Then, you'll need to make sure your include path contains your "vstsdk2.3" or - "vstsdk2.4" directory. - - Note that the JUCE_USE_VSTSDK_2_4 macro should be defined in JucePluginCharacteristics.h -*/ -#if JUCE_USE_VSTSDK_2_4 - #ifdef __GNUC__ - #define __cdecl - #endif - - // VSTSDK V2.4 includes.. - #include "public.sdk/source/vst2.x/audioeffectx.h" - #include "public.sdk/source/vst2.x/aeffeditor.h" - #include "public.sdk/source/vst2.x/audioeffectx.cpp" - #include "public.sdk/source/vst2.x/audioeffect.cpp" - - #if ! VST_2_4_EXTENSIONS - #error // You're probably trying to include the wrong VSTSDK version - make sure your include path matches the JUCE_USE_VSTSDK_2_4 flag - #endif - -#else - // VSTSDK V2.3 includes.. - #include "source/common/audioeffectx.h" - #include "source/common/AEffEditor.hpp" - #include "source/common/audioeffectx.cpp" - #include "source/common/AudioEffect.cpp" - - #if (! VST_2_3_EXTENSIONS) || VST_2_4_EXTENSIONS - #error // You're probably trying to include the wrong VSTSDK version - make sure your include path matches the JUCE_USE_VSTSDK_2_4 flag - #endif - - #define __aeffect__ // (needed for juce_VSTMidiEventList.h to work) - - typedef long VstInt32; - typedef long VstIntPtr; - enum Vst2StringConstants - { - kVstMaxNameLen = 64, - kVstMaxLabelLen = 64, - kVstMaxShortLabelLen = 8, - kVstMaxCategLabelLen = 24, - kVstMaxFileNameLen = 100 - }; - - enum VstSmpteFrameRate - { - kVstSmpte24fps = 0, ///< 24 fps - kVstSmpte25fps = 1, ///< 25 fps - kVstSmpte2997fps = 2, ///< 29.97 fps - kVstSmpte30fps = 3, ///< 30 fps - kVstSmpte2997dfps = 4, ///< 29.97 drop - kVstSmpte30dfps = 5, ///< 30 drop - kVstSmpteFilm16mm = 6, ///< Film 16mm - kVstSmpteFilm35mm = 7, ///< Film 35mm - kVstSmpte239fps = 10, ///< HDTV: 23.976 fps - kVstSmpte249fps = 11, ///< HDTV: 24.976 fps - kVstSmpte599fps = 12, ///< HDTV: 59.94 fps - kVstSmpte60fps = 13 ///< HDTV: 60 fps - }; - - struct VstMidiSysexEvent - { - VstInt32 type; ///< #kVstSysexType - VstInt32 byteSize; ///< sizeof (VstMidiSysexEvent) - VstInt32 deltaFrames; ///< sample frames related to the current block start sample position - VstInt32 flags; ///< none defined yet (should be zero) - VstInt32 dumpBytes; ///< byte size of sysexDump - VstIntPtr resvd1; ///< zero (Reserved for future use) - char* sysexDump; ///< sysex dump - VstIntPtr resvd2; ///< zero (Reserved for future use) - }; - - typedef int VstSpeakerArrangementType; -#endif - -//============================================================================== -#ifdef _MSC_VER - #pragma pack (push, 8) -#endif - -#include "../juce_PluginHeaders.h" - - -#ifdef _MSC_VER - #pragma pack (pop) -#endif - -#undef MemoryBlock - -class JuceVSTWrapper; -static bool recursionCheck = false; -static JUCE_NAMESPACE::uint32 lastMasterIdleCall = 0; - -BEGIN_JUCE_NAMESPACE - extern void juce_callAnyTimersSynchronously(); - - #if JUCE_MAC - extern void initialiseMac(); - extern void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw(); - extern void* attachComponentToWindowRef (Component* component, void* windowRef); - extern void detachComponentFromWindowRef (Component* component, void* nsWindow); - extern void setNativeHostWindowSize (void* nsWindow, Component* editorComp, int newWidth, int newHeight); - extern void checkWindowVisibility (void* nsWindow, Component* component); - #endif - - #if JUCE_LINUX - extern Display* display; - extern bool juce_postMessageToSystemQueue (void* message); - #endif -END_JUCE_NAMESPACE - - -//============================================================================== -#if JUCE_WIN32 - -static HWND findMDIParentOf (HWND w) -{ - const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); - - while (w != 0) - { - HWND parent = GetParent (w); - - if (parent == 0) - break; - - TCHAR windowType [32]; - zeromem (windowType, sizeof (windowType)); - GetClassName (parent, windowType, 31); - - if (String (windowType).equalsIgnoreCase (T("MDIClient"))) - { - w = parent; - break; - } - - RECT windowPos; - GetWindowRect (w, &windowPos); - - RECT parentPos; - GetWindowRect (parent, &parentPos); - - const int dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); - const int dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); - - if (dw > 100 || dh > 100) - break; - - w = parent; - - if (dw == 2 * frameThickness) - break; - } - - return w; -} - -//============================================================================== -#elif JUCE_LINUX - -class SharedMessageThread : public Thread -{ -public: - SharedMessageThread() - : Thread (T("VstMessageThread")) - { - startThread (7); - } - - ~SharedMessageThread() - { - signalThreadShouldExit(); - JUCEApplication::quit(); - waitForThreadToExit (5000); - clearSingletonInstance(); - } - - void run() - { - MessageManager* const messageManager = MessageManager::getInstance(); - - const Thread::ThreadID originalThreadId = messageManager->getCurrentMessageThread(); - messageManager->setCurrentMessageThread (Thread::getCurrentThreadId()); - - while ((! threadShouldExit()) && messageManager->runDispatchLoopUntil (250)) - { - } - - messageManager->setCurrentMessageThread (originalThreadId); - } - - juce_DeclareSingleton (SharedMessageThread, false) -}; - - -#endif - -//============================================================================== -// A component to hold the AudioProcessorEditor, and cope with some housekeeping -// chores when it changes or repaints. -class EditorCompWrapper : public Component, - public AsyncUpdater -{ - JuceVSTWrapper* wrapper; - -public: - EditorCompWrapper (JuceVSTWrapper* const wrapper_, - AudioProcessorEditor* const editor) - : wrapper (wrapper_) - { - setOpaque (true); - editor->setOpaque (true); - - setBounds (editor->getBounds()); - editor->setTopLeftPosition (0, 0); - addAndMakeVisible (editor); - -#if JUCE_WIN32 - addMouseListener (this, true); -#endif - } - - ~EditorCompWrapper() - { - deleteAllChildren(); - } - - void paint (Graphics& g) - { - } - - void paintOverChildren (Graphics& g) - { - // 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(); - } - - AudioProcessorEditor* getEditorComp() const - { - return dynamic_cast (getChildComponent (0)); - } - - void resized() - { - Component* const c = getChildComponent (0); - - if (c != 0) - c->setBounds (0, 0, getWidth(), getHeight()); - } - - void childBoundsChanged (Component* child); - void handleAsyncUpdate(); - -#if JUCE_WIN32 - 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 - - //============================================================================== - juce_UseDebuggingNewOperator -}; - -static VoidArray activePlugins; - - -//============================================================================== -/** - This wraps an AudioProcessor as an AudioEffectX... -*/ -class JuceVSTWrapper : public AudioEffectX, - private Timer, - public AudioProcessorListener, - public AudioPlayHead -{ -public: - //============================================================================== - JuceVSTWrapper (audioMasterCallback audioMaster, - AudioProcessor* const filter_) - : AudioEffectX (audioMaster, - filter_->getNumPrograms(), - filter_->getNumParameters()), - filter (filter_) - { - editorComp = 0; - chunkMemoryTime = 0; - isProcessing = false; - hasShutdown = false; - firstProcessCallback = true; - shouldDeleteEditor = false; - channels = 0; - speakerIn = kSpeakerArrEmpty; - speakerOut = kSpeakerArrEmpty; - speakerInChans = 0; - speakerOutChans = 0; - numInChans = JucePlugin_MaxNumInputChannels; - numOutChans = JucePlugin_MaxNumOutputChannels; - -#if JUCE_MAC || JUCE_LINUX - hostWindow = 0; -#endif - - filter->setPlayConfigDetails (numInChans, numOutChans, 0, 0); - - filter_->setPlayHead (this); - filter_->addListener (this); - - cEffect.flags |= effFlagsHasEditor; - cEffect.version = (long) (JucePlugin_VersionCode); - - setUniqueID ((int) (JucePlugin_VSTUniqueID)); - -#if JucePlugin_WantsMidiInput && ! JUCE_USE_VSTSDK_2_4 - wantEvents(); -#endif - - setNumInputs (numInChans); - setNumOutputs (numOutChans); - - canProcessReplacing (true); - -#if ! JUCE_USE_VSTSDK_2_4 - hasVu (false); - hasClip (false); -#endif - - isSynth ((JucePlugin_IsSynth) != 0); - noTail ((JucePlugin_SilenceInProducesSilenceOut) != 0); - setInitialDelay (filter->getLatencySamples()); - programsAreChunks (true); - - activePlugins.add (this); - } - - ~JuceVSTWrapper() - { - stopTimer(); - deleteEditor (false); - - hasShutdown = true; - - delete filter; - filter = 0; - - jassert (editorComp == 0); - - juce_free (channels); - channels = 0; - deleteTempChannels(); - - jassert (activePlugins.contains (this)); - activePlugins.removeValue (this); - - if (activePlugins.size() == 0) - { -#if JUCE_LINUX - SharedMessageThread::deleteInstance(); -#endif - shutdownJuce_GUI(); - } - } - - void open() - { - if (editorComp == 0) - { - AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); - - if (ed != 0) - cEffect.flags |= effFlagsHasEditor; - else - cEffect.flags &= ~effFlagsHasEditor; - - filter->editorBeingDeleted (ed); - delete ed; - } - - startTimer (1000 / 4); - } - - void close() - { - jassert (! recursionCheck); - - stopTimer(); - deleteEditor (false); - } - - //============================================================================== - bool getEffectName (char* name) - { - String (JucePlugin_Name).copyToBuffer (name, 64); - return true; - } - - bool getVendorString (char* text) - { - String (JucePlugin_Manufacturer).copyToBuffer (text, 64); - return true; - } - - bool getProductString (char* text) - { - return getEffectName (text); - } - - VstInt32 getVendorVersion() - { - return JucePlugin_VersionCode; - } - - VstPlugCategory getPlugCategory() - { - return JucePlugin_VSTCategory; - } - - VstInt32 canDo (char* text) - { - VstInt32 result = 0; - - if (strcmp (text, "receiveVstEvents") == 0 - || strcmp (text, "receiveVstMidiEvent") == 0 - || strcmp (text, "receiveVstMidiEvents") == 0) - { -#if JucePlugin_WantsMidiInput - result = 1; -#else - result = -1; -#endif - } - else if (strcmp (text, "sendVstEvents") == 0 - || strcmp (text, "sendVstMidiEvent") == 0 - || strcmp (text, "sendVstMidiEvents") == 0) - { -#if JucePlugin_ProducesMidiOutput - result = 1; -#else - result = -1; -#endif - } - else if (strcmp (text, "receiveVstTimeInfo") == 0 - || strcmp (text, "conformsToWindowRules") == 0) - { - result = 1; - } - - return result; - } - - bool keysRequired() - { - return (JucePlugin_EditorRequiresKeyboardFocus) != 0; - } - - bool getInputProperties (VstInt32 index, VstPinProperties* properties) - { - if (filter == 0 || index >= JucePlugin_MaxNumInputChannels) - return false; - - const String name (filter->getInputChannelName ((int) index)); - - name.copyToBuffer (properties->label, kVstMaxLabelLen - 1); - name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1); - - if (speakerIn != kSpeakerArrEmpty) - { - properties->flags = kVstPinUseSpeaker; - properties->arrangementType = speakerIn; - } - else - { - properties->flags = kVstPinIsActive; - - if (filter->isInputChannelStereoPair ((int) index)) - properties->flags |= kVstPinIsStereo; - - properties->arrangementType = 0; - } - - return true; - } - - bool getOutputProperties (VstInt32 index, VstPinProperties* properties) - { - if (filter == 0 || index >= JucePlugin_MaxNumOutputChannels) - return false; - - const String name (filter->getOutputChannelName ((int) index)); - - name.copyToBuffer (properties->label, kVstMaxLabelLen - 1); - name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1); - - if (speakerOut != kSpeakerArrEmpty) - { - properties->flags = kVstPinUseSpeaker; - properties->arrangementType = speakerOut; - } - else - { - properties->flags = kVstPinIsActive; - - if (filter->isOutputChannelStereoPair ((int) index)) - properties->flags |= kVstPinIsStereo; - - properties->arrangementType = 0; - } - - return true; - } - - //============================================================================== - VstInt32 processEvents (VstEvents* events) - { -#if JucePlugin_WantsMidiInput - VSTMidiEventList::addEventsToMidiBuffer (events, midiEvents); - return 1; -#else - return 0; -#endif - } - - void process (float** inputs, float** outputs, VstInt32 numSamples) - { - const int numIn = numInChans; - const int numOut = numOutChans; - - AudioSampleBuffer temp (numIn, numSamples); - int i; - for (i = numIn; --i >= 0;) - memcpy (temp.getSampleData (i), outputs[i], sizeof (float) * numSamples); - - processReplacing (inputs, outputs, numSamples); - - AudioSampleBuffer dest (outputs, numOut, numSamples); - - for (i = jmin (numIn, numOut); --i >= 0;) - dest.addFrom (i, 0, temp, i, 0, numSamples); - } - - void processReplacing (float** inputs, float** outputs, VstInt32 numSamples) - { - 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) - resume(); - - filter->setNonRealtime (getCurrentProcessLevel() == 4 /* kVstProcessLevelOffline */); - -#if JUCE_WIN32 - if (GetThreadPriority (GetCurrentThread()) <= THREAD_PRIORITY_NORMAL - && GetThreadPriority (GetCurrentThread()) >= THREAD_PRIORITY_LOWEST) - filter->setNonRealtime (true); -#endif - } - -#if JUCE_DEBUG && ! JucePlugin_ProducesMidiOutput - const int numMidiEventsComingIn = midiEvents.getNumEvents(); -#endif - - jassert (activePlugins.contains (this)); - - { - const ScopedLock sl (filter->getCallbackLock()); - - const int numIn = numInChans; - const int numOut = numOutChans; - - if (filter->isSuspended()) - { - for (int i = 0; i < numOut; ++i) - zeromem (outputs[i], sizeof (float) * numSamples); - } - else - { - int i; - for (i = 0; i < numOut; ++i) - { - float* chan = (float*) tempChannels.getUnchecked(i); - - if (chan == 0) - { - chan = outputs[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 (outputs[j] == chan) - { - chan = (float*) juce_malloc (sizeof (float) * blockSize * 2); - tempChannels.set (i, chan); - break; - } - } - } - - if (i < numIn && chan != inputs[i]) - memcpy (chan, inputs[i], sizeof (float) * numSamples); - - channels[i] = chan; - } - - for (; i < numIn; ++i) - channels[i] = inputs[i]; - - AudioSampleBuffer chans (channels, jmax (numIn, numOut), numSamples); - - filter->processBlock (chans, midiEvents); - } - } - - if (! midiEvents.isEmpty()) - { -#if JucePlugin_ProducesMidiOutput - const int numEvents = midiEvents.getNumEvents(); - - outgoingEvents.ensureSize (numEvents); - outgoingEvents.clear(); - - const JUCE_NAMESPACE::uint8* midiEventData; - int midiEventSize, midiEventPosition; - MidiBuffer::Iterator i (midiEvents); - - while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) - { - jassert (midiEventPosition >= 0 && midiEventPosition < numSamples); - - outgoingEvents.addEvent (midiEventData, midiEventSize, midiEventPosition); - } - - sendVstEventsToHost (outgoingEvents.events); -#else - /* This assertion is caused when you've added some events to the - midiMessages array in your processBlock() method, which usually means - that you're trying to send them somewhere. But in this case they're - getting thrown away. - - If your plugin does want to send midi messages, you'll need to set - the JucePlugin_ProducesMidiOutput macro to 1 in your - JucePluginCharacteristics.h file. - - If you don't want to produce any midi output, then you should clear the - midiMessages array at the end of your processBlock() method, to - indicate that you don't want any of the events to be passed through - to the output. - */ - jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn); -#endif - - midiEvents.clear(); - } - } - - //============================================================================== - VstInt32 startProcess () { return 0; } - VstInt32 stopProcess () { return 0;} - - void resume() - { - if (filter == 0) - return; - - isProcessing = true; - juce_free (channels); - channels = (float**) juce_calloc (sizeof (float*) * (numInChans + numOutChans)); - - double rate = getSampleRate(); - jassert (rate > 0); - if (rate <= 0.0) - rate = 44100.0; - - const int blockSize = getBlockSize(); - jassert (blockSize > 0); - - firstProcessCallback = true; - - filter->setNonRealtime (getCurrentProcessLevel() == 4 /* kVstProcessLevelOffline */); - - filter->setPlayConfigDetails (numInChans, numOutChans, - rate, blockSize); - - deleteTempChannels(); - - filter->prepareToPlay (rate, blockSize); - midiEvents.clear(); - - setInitialDelay (filter->getLatencySamples()); - - AudioEffectX::resume(); - -#if JucePlugin_ProducesMidiOutput - outgoingEvents.ensureSize (64); -#endif - -#if JucePlugin_WantsMidiInput && ! JUCE_USE_VSTSDK_2_4 - wantEvents(); -#endif - } - - void suspend() - { - if (filter == 0) - return; - - AudioEffectX::suspend(); - - filter->releaseResources(); - outgoingEvents.freeEvents(); - - isProcessing = false; - juce_free (channels); - channels = 0; - - deleteTempChannels(); - } - - bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo& info) - { - const VstTimeInfo* const ti = getTimeInfo (kVstPpqPosValid - | kVstTempoValid - | kVstBarsValid - //| kVstCyclePosValid - | kVstTimeSigValid - | kVstSmpteValid - | kVstClockValid); - - if (ti == 0 || ti->sampleRate <= 0) - return false; - - if ((ti->flags & kVstTempoValid) != 0) - info.bpm = ti->tempo; - else - info.bpm = 0.0; - - if ((ti->flags & kVstTimeSigValid) != 0) - { - info.timeSigNumerator = ti->timeSigNumerator; - info.timeSigDenominator = ti->timeSigDenominator; - } - else - { - info.timeSigNumerator = 4; - info.timeSigDenominator = 4; - } - - info.timeInSeconds = ti->samplePos / ti->sampleRate; - - if ((ti->flags & kVstPpqPosValid) != 0) - info.ppqPosition = ti->ppqPos; - else - info.ppqPosition = 0.0; - - if ((ti->flags & kVstBarsValid) != 0) - info.ppqPositionOfLastBarStart = ti->barStartPos; - else - info.ppqPositionOfLastBarStart = 0.0; - - if ((ti->flags & kVstSmpteValid) != 0) - { - AudioPlayHead::FrameRateType rate = AudioPlayHead::fpsUnknown; - double fps = 1.0; - - switch (ti->smpteFrameRate) - { - case kVstSmpte24fps: - rate = AudioPlayHead::fps24; - fps = 24.0; - break; - - case kVstSmpte25fps: - rate = AudioPlayHead::fps25; - fps = 25.0; - break; - - case kVstSmpte2997fps: - rate = AudioPlayHead::fps2997; - fps = 29.97; - break; - - case kVstSmpte30fps: - rate = AudioPlayHead::fps30; - fps = 30.0; - break; - - case kVstSmpte2997dfps: - rate = AudioPlayHead::fps2997drop; - fps = 29.97; - break; - - case kVstSmpte30dfps: - rate = AudioPlayHead::fps30drop; - fps = 30.0; - break; - - case kVstSmpteFilm16mm: - case kVstSmpteFilm35mm: - fps = 24.0; - break; - - case kVstSmpte239fps: fps = 23.976; break; - case kVstSmpte249fps: fps = 24.976; break; - case kVstSmpte599fps: fps = 59.94; break; - case kVstSmpte60fps: fps = 60; break; - - default: - jassertfalse // unknown frame-rate.. - } - - info.frameRate = rate; - info.editOriginTime = ti->smpteOffset / (80.0 * fps); - } - else - { - info.frameRate = AudioPlayHead::fpsUnknown; - info.editOriginTime = 0; - } - - info.isRecording = (ti->flags & kVstTransportRecording) != 0; - info.isPlaying = (ti->flags & kVstTransportPlaying) != 0 || info.isRecording; - - return true; - } - - //============================================================================== - VstInt32 getProgram() - { - return filter != 0 ? filter->getCurrentProgram() : 0; - } - - void setProgram (VstInt32 program) - { - if (filter != 0) - filter->setCurrentProgram (program); - } - - void setProgramName (char* name) - { - if (filter != 0) - filter->changeProgramName (filter->getCurrentProgram(), name); - } - - void getProgramName (char* name) - { - if (filter != 0) - filter->getProgramName (filter->getCurrentProgram()).copyToBuffer (name, 24); - } - - bool getProgramNameIndexed (VstInt32 category, VstInt32 index, char* text) - { - if (filter != 0 && ((unsigned int) index) < (unsigned int) filter->getNumPrograms()) - { - filter->getProgramName (index).copyToBuffer (text, 24); - return true; - } - - return false; - } - - //============================================================================== - float getParameter (VstInt32 index) - { - if (filter == 0) - return 0.0f; - - jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); - return filter->getParameter (index); - } - - void setParameter (VstInt32 index, float value) - { - if (filter != 0) - { - jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); - filter->setParameter (index, value); - } - } - - void getParameterDisplay (VstInt32 index, char* text) - { - if (filter != 0) - { - jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); - filter->getParameterText (index).copyToBuffer (text, 24); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. - } - } - - void getParameterName (VstInt32 index, char* text) - { - if (filter != 0) - { - jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); - filter->getParameterName (index).copyToBuffer (text, 16); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. - } - } - - void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) - { - setParameterAutomated (index, newValue); - } - - void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) - { - beginEdit (index); - } - - void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) - { - endEdit (index); - } - - void audioProcessorChanged (AudioProcessor*) - { - updateDisplay(); - } - - bool canParameterBeAutomated (VstInt32 index) - { - return filter != 0 && filter->isParameterAutomatable ((int) index); - } - - bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput, - VstSpeakerArrangement* pluginOutput) - { - const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; - - for (int i = 0; i < numElementsInArray (channelConfigs); ++i) - { - bool configMono = (channelConfigs[i][1] == 1) && (pluginOutput->type == kSpeakerArrMono); - bool configStereo = (channelConfigs[i][1] == 2) && (pluginOutput->type == kSpeakerArrStereo); - bool inCountMatches = (channelConfigs[i][0] == pluginInput->numChannels); - bool outCountMatches = (channelConfigs[i][1] == pluginOutput->numChannels); - - if ((configMono || configStereo) && inCountMatches && outCountMatches) - { - speakerIn = (VstSpeakerArrangementType) pluginInput->type; - speakerOut = (VstSpeakerArrangementType) pluginOutput->type; - speakerInChans = pluginInput->numChannels; - speakerOutChans = pluginOutput->numChannels; - - filter->setPlayConfigDetails (speakerInChans, speakerOutChans, - filter->getSampleRate(), - filter->getBlockSize()); - return true; - } - } - - return false; - } - - //============================================================================== - VstInt32 getChunk (void** data, bool onlyStoreCurrentProgramData) - { - if (filter == 0) - return 0; - - chunkMemory.setSize (0); - if (onlyStoreCurrentProgramData) - filter->getCurrentProgramStateInformation (chunkMemory); - else - filter->getStateInformation (chunkMemory); - - *data = (void*) chunkMemory; - - // because the chunk is only needed temporarily by the host (or at least you'd - // hope so) we'll give it a while and then free it in the timer callback. - chunkMemoryTime = JUCE_NAMESPACE::Time::getApproximateMillisecondCounter(); - - return chunkMemory.getSize(); - } - - VstInt32 setChunk (void* data, VstInt32 byteSize, bool onlyRestoreCurrentProgramData) - { - if (filter == 0) - return 0; - - chunkMemory.setSize (0); - chunkMemoryTime = 0; - - if (byteSize > 0 && data != 0) - { - if (onlyRestoreCurrentProgramData) - filter->setCurrentProgramStateInformation (data, byteSize); - else - filter->setStateInformation (data, byteSize); - } - - return 0; - } - - void timerCallback() - { - if (shouldDeleteEditor) - { - shouldDeleteEditor = false; - deleteEditor (true); - } - - if (chunkMemoryTime > 0 - && chunkMemoryTime < JUCE_NAMESPACE::Time::getApproximateMillisecondCounter() - 2000 - && ! recursionCheck) - { - chunkMemoryTime = 0; - chunkMemory.setSize (0); - } - -#if JUCE_MAC - if (hostWindow != 0) - checkWindowVisibility (hostWindow, editorComp); -#endif - - tryMasterIdle(); - } - - void tryMasterIdle() - { - if (Component::isMouseButtonDownAnywhere() - && ! recursionCheck) - { - const JUCE_NAMESPACE::uint32 now = JUCE_NAMESPACE::Time::getMillisecondCounter(); - - if (now > lastMasterIdleCall + 20 && editorComp != 0) - { - lastMasterIdleCall = now; - - recursionCheck = true; - masterIdle(); - recursionCheck = false; - } - } - } - - void doIdleCallback() - { - // (wavelab calls this on a separate thread and causes a deadlock).. - if (MessageManager::getInstance()->isThisTheMessageThread() - && ! recursionCheck) - { - recursionCheck = true; - - juce_callAnyTimersSynchronously(); - - for (int i = ComponentPeer::getNumPeers(); --i >= 0;) - ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow(); - - recursionCheck = false; - } - } - - void createEditorComp() - { - if (hasShutdown || filter == 0) - return; - - if (editorComp == 0) - { - AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); - - if (ed != 0) - { - cEffect.flags |= effFlagsHasEditor; - ed->setOpaque (true); - ed->setVisible (true); - - editorComp = new EditorCompWrapper (this, ed); - } - else - { - cEffect.flags &= ~effFlagsHasEditor; - } - } - - shouldDeleteEditor = false; - } - - void deleteEditor (bool canDeleteLaterIfModal) - { - PopupMenu::dismissAllActiveMenus(); - - jassert (! recursionCheck); - recursionCheck = true; - - if (editorComp != 0) - { - Component* const modalComponent = Component::getCurrentlyModalComponent(); - if (modalComponent != 0) - { - modalComponent->exitModalState (0); - - if (canDeleteLaterIfModal) - { - shouldDeleteEditor = true; - return; - } - } - -#if JUCE_MAC - if (hostWindow != 0) - { - detachComponentFromWindowRef (editorComp, hostWindow); - hostWindow = 0; - } -#endif - - filter->editorBeingDeleted (editorComp->getEditorComp()); - - deleteAndZero (editorComp); - - // there's some kind of component currently modal, but the host - // is trying to delete our plugin. You should try to avoid this happening.. - jassert (Component::getCurrentlyModalComponent() == 0); - } - -#if JUCE_LINUX - hostWindow = 0; -#endif - - recursionCheck = false; - } - - VstIntPtr dispatcher (VstInt32 opCode, VstInt32 index, VstIntPtr value, void* ptr, float opt) - { - if (hasShutdown) - return 0; - - if (opCode == effEditIdle) - { - doIdleCallback(); - return 0; - } - else if (opCode == effEditOpen) - { - jassert (! recursionCheck); - - deleteEditor (true); - createEditorComp(); - - if (editorComp != 0) - { - editorComp->setOpaque (true); - editorComp->setVisible (false); - -#if JUCE_WIN32 - editorComp->addToDesktop (0); - hostWindow = (HWND) ptr; - HWND editorWnd = (HWND) editorComp->getWindowHandle(); - SetParent (editorWnd, hostWindow); - - DWORD val = GetWindowLong (editorWnd, GWL_STYLE); - val = (val & ~WS_POPUP) | WS_CHILD; - SetWindowLong (editorWnd, GWL_STYLE, val); -#elif JUCE_LINUX - editorComp->addToDesktop (0); - hostWindow = (Window) ptr; - Window editorWnd = (Window) editorComp->getWindowHandle(); - XReparentWindow (display, editorWnd, hostWindow, 0, 0); -#else - hostWindow = attachComponentToWindowRef (editorComp, (WindowRef) ptr); -#endif - editorComp->setVisible (true); - - return 1; - } - } - else if (opCode == effEditClose) - { - deleteEditor (true); - return 0; - } - else if (opCode == effEditGetRect) - { - createEditorComp(); - - if (editorComp != 0) - { - editorSize.left = 0; - editorSize.top = 0; - editorSize.right = editorComp->getWidth(); - editorSize.bottom = editorComp->getHeight(); - - *((ERect**) ptr) = &editorSize; - - return (VstIntPtr) (pointer_sized_int) &editorSize; - } - else - { - return 0; - } - } - - return AudioEffectX::dispatcher (opCode, index, value, ptr, opt); - } - - void resizeHostWindow (int newWidth, int newHeight) - { - if (editorComp != 0) - { -#if ! JUCE_LINUX // linux hosts shouldn't be trusted! - if (! (canHostDo ("sizeWindow") && sizeWindow (newWidth, newHeight))) -#endif - { - // some hosts don't support the sizeWindow call, so do it manually.. -#if JUCE_MAC - setNativeHostWindowSize (hostWindow, editorComp, newWidth, newHeight); -#elif JUCE_LINUX - Window root; - int x, y; - unsigned int width, height, border, depth; - - XGetGeometry (display, hostWindow, &root, - &x, &y, &width, &height, &border, &depth); - - newWidth += (width + border) - editorComp->getWidth(); - newHeight += (height + border) - editorComp->getHeight(); - - XResizeWindow (display, hostWindow, newWidth, newHeight); -#else - int dw = 0; - int dh = 0; - const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); - - HWND w = (HWND) editorComp->getWindowHandle(); - - while (w != 0) - { - HWND parent = GetParent (w); - - if (parent == 0) - break; - - TCHAR windowType [32]; - zeromem (windowType, sizeof (windowType)); - GetClassName (parent, windowType, 31); - - if (String (windowType).equalsIgnoreCase (T("MDIClient"))) - break; - - RECT windowPos; - GetWindowRect (w, &windowPos); - - RECT parentPos; - GetWindowRect (parent, &parentPos); - - SetWindowPos (w, 0, 0, 0, - newWidth + dw, - newHeight + dh, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); - - dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); - dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); - - w = parent; - - if (dw == 2 * frameThickness) - break; - - if (dw > 100 || dh > 100) - w = 0; - } - - if (w != 0) - SetWindowPos (w, 0, 0, 0, - newWidth + dw, - newHeight + dh, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); -#endif - } - - if (editorComp->getPeer() != 0) - editorComp->getPeer()->handleMovedOrResized(); - } - } - - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - AudioProcessor* filter; - JUCE_NAMESPACE::MemoryBlock chunkMemory; - JUCE_NAMESPACE::uint32 chunkMemoryTime; - EditorCompWrapper* editorComp; - ERect editorSize; - MidiBuffer midiEvents; - VSTMidiEventList outgoingEvents; - bool isProcessing; - bool hasShutdown; - bool firstProcessCallback; - int diffW, diffH; - VstSpeakerArrangementType speakerIn, speakerOut; - int speakerInChans, speakerOutChans; - int numInChans, numOutChans; - float** channels; - VoidArray tempChannels; // see note in processReplacing() - bool hasCreatedTempChannels; - bool shouldDeleteEditor; - - void deleteTempChannels() - { - int i; - for (i = tempChannels.size(); --i >= 0;) - juce_free (tempChannels.getUnchecked(i)); - - tempChannels.clear(); - - if (filter != 0) - tempChannels.insertMultiple (0, 0, filter->getNumInputChannels() + filter->getNumOutputChannels()); - - hasCreatedTempChannels = false; - } - - const String getHostName() - { - char host[256]; - zeromem (host, sizeof (host)); - getHostProductString (host); - return host; - } - -#if JUCE_MAC - void* hostWindow; -#elif JUCE_LINUX - Window hostWindow; -#else - HWND hostWindow; -#endif -}; - -//============================================================================== -void EditorCompWrapper::childBoundsChanged (Component* child) -{ - child->setTopLeftPosition (0, 0); - - const int cw = child->getWidth(); - const int ch = child->getHeight(); - - wrapper->resizeHostWindow (cw, ch); - setSize (cw, ch); - -#if JUCE_MAC - wrapper->resizeHostWindow (cw, ch); // (doing this a second time seems to be necessary in tracktion) -#endif -} - -void EditorCompWrapper::handleAsyncUpdate() -{ - wrapper->tryMasterIdle(); -} - -//============================================================================== -/** 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 AEffect* pluginEntryPoint (audioMasterCallback audioMaster) -{ - initialiseJuce_GUI(); - -#if JUCE_MAC && defined (JucePlugin_CFBundleIdentifier) - juce_setCurrentExecutableFileNameFromBundleId (JucePlugin_CFBundleIdentifier); -#endif - - try - { - if (audioMaster (0, audioMasterVersion, 0, 0, 0, 0) != 0) - { - AudioProcessor* const filter = createPluginFilter(); - - if (filter != 0) - { - JuceVSTWrapper* const wrapper = new JuceVSTWrapper (audioMaster, filter); - return wrapper->getAeffect(); - } - } - } - catch (...) - {} - - return 0; -} - - -//============================================================================== -// Mac startup code.. -#if JUCE_MAC - -extern "C" __attribute__ ((visibility("default"))) AEffect* VSTPluginMain (audioMasterCallback audioMaster) -{ - initialiseMac(); - return pluginEntryPoint (audioMaster); -} - -extern "C" __attribute__ ((visibility("default"))) AEffect* main_macho (audioMasterCallback audioMaster) -{ - initialiseMac(); - return pluginEntryPoint (audioMaster); -} - -//============================================================================== -// Linux startup code.. -#elif JUCE_LINUX - -extern "C" AEffect* VSTPluginMain (audioMasterCallback audioMaster) -{ - initialiseJuce_GUI(); - SharedMessageThread::getInstance(); - - return pluginEntryPoint (audioMaster); -} - -extern "C" __attribute__ ((visibility("default"))) AEffect* main_plugin (audioMasterCallback audioMaster) asm ("main"); - -extern "C" __attribute__ ((visibility("default"))) AEffect* main_plugin (audioMasterCallback audioMaster) -{ - return VSTPluginMain (audioMaster); -} - -__attribute__((constructor)) void myPluginInit() -{ - // don't put initialiseJuce_GUI here... it will crash ! -} - -__attribute__((destructor)) void myPluginFini() -{ - // don't put shutdownJuce_GUI here... it will crash ! -} - -//============================================================================== -// Win32 startup code.. -#else - -extern "C" __declspec (dllexport) AEffect* VSTPluginMain (audioMasterCallback audioMaster) -{ - return pluginEntryPoint (audioMaster); -} - -#ifndef _WIN64 // (can't compile this on win64, but it's not needed anyway with VST2.4) -extern "C" __declspec (dllexport) void* main (audioMasterCallback audioMaster) -{ - return (void*) pluginEntryPoint (audioMaster); -} -#endif - -#if JucePlugin_Build_RTAS -BOOL WINAPI DllMainVST (HINSTANCE instance, DWORD dwReason, LPVOID) -#else -extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD dwReason, LPVOID) -#endif -{ - if (dwReason == DLL_PROCESS_ATTACH) - PlatformUtilities::setCurrentModuleInstanceHandle (instance); - - return TRUE; -} - -#endif - -#endif +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + JUCE 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. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +#ifdef _MSC_VER + #pragma warning (disable : 4996) +#endif + +#ifdef _WIN32 + #include +#elif defined (LINUX) + #include + #include + #include + #undef KeyPress +#else + #include +#endif + +#ifdef PRAGMA_ALIGN_SUPPORTED + #undef PRAGMA_ALIGN_SUPPORTED + #define PRAGMA_ALIGN_SUPPORTED 1 +#endif + +#include "../juce_IncludeCharacteristics.h" + +#if JucePlugin_Build_VST + +//============================================================================== +/* These files come with the Steinberg VST SDK - to get them, you'll need to + visit the Steinberg website and jump through some hoops to sign up as a + VST developer. + + Then, you'll need to make sure your include path contains your "vstsdk2.3" or + "vstsdk2.4" directory. + + Note that the JUCE_USE_VSTSDK_2_4 macro should be defined in JucePluginCharacteristics.h +*/ +#if JUCE_USE_VSTSDK_2_4 + #ifdef __GNUC__ + #define __cdecl + #endif + + // VSTSDK V2.4 includes.. + #include "public.sdk/source/vst2.x/audioeffectx.h" + #include "public.sdk/source/vst2.x/aeffeditor.h" + #include "public.sdk/source/vst2.x/audioeffectx.cpp" + #include "public.sdk/source/vst2.x/audioeffect.cpp" + + #if ! VST_2_4_EXTENSIONS + #error // You're probably trying to include the wrong VSTSDK version - make sure your include path matches the JUCE_USE_VSTSDK_2_4 flag + #endif + +#else + // VSTSDK V2.3 includes.. + #include "source/common/audioeffectx.h" + #include "source/common/AEffEditor.hpp" + #include "source/common/audioeffectx.cpp" + #include "source/common/AudioEffect.cpp" + + #if (! VST_2_3_EXTENSIONS) || VST_2_4_EXTENSIONS + #error // You're probably trying to include the wrong VSTSDK version - make sure your include path matches the JUCE_USE_VSTSDK_2_4 flag + #endif + + #define __aeffect__ // (needed for juce_VSTMidiEventList.h to work) + + typedef long VstInt32; + typedef long VstIntPtr; + enum Vst2StringConstants + { + kVstMaxNameLen = 64, + kVstMaxLabelLen = 64, + kVstMaxShortLabelLen = 8, + kVstMaxCategLabelLen = 24, + kVstMaxFileNameLen = 100 + }; + + enum VstSmpteFrameRate + { + kVstSmpte24fps = 0, ///< 24 fps + kVstSmpte25fps = 1, ///< 25 fps + kVstSmpte2997fps = 2, ///< 29.97 fps + kVstSmpte30fps = 3, ///< 30 fps + kVstSmpte2997dfps = 4, ///< 29.97 drop + kVstSmpte30dfps = 5, ///< 30 drop + kVstSmpteFilm16mm = 6, ///< Film 16mm + kVstSmpteFilm35mm = 7, ///< Film 35mm + kVstSmpte239fps = 10, ///< HDTV: 23.976 fps + kVstSmpte249fps = 11, ///< HDTV: 24.976 fps + kVstSmpte599fps = 12, ///< HDTV: 59.94 fps + kVstSmpte60fps = 13 ///< HDTV: 60 fps + }; + + struct VstMidiSysexEvent + { + VstInt32 type; ///< #kVstSysexType + VstInt32 byteSize; ///< sizeof (VstMidiSysexEvent) + VstInt32 deltaFrames; ///< sample frames related to the current block start sample position + VstInt32 flags; ///< none defined yet (should be zero) + VstInt32 dumpBytes; ///< byte size of sysexDump + VstIntPtr resvd1; ///< zero (Reserved for future use) + char* sysexDump; ///< sysex dump + VstIntPtr resvd2; ///< zero (Reserved for future use) + }; + + typedef int VstSpeakerArrangementType; +#endif + +//============================================================================== +#ifdef _MSC_VER + #pragma pack (push, 8) +#endif + +#include "../juce_PluginHeaders.h" + + +#ifdef _MSC_VER + #pragma pack (pop) +#endif + +#undef MemoryBlock + +class JuceVSTWrapper; +static bool recursionCheck = false; +static JUCE_NAMESPACE::uint32 lastMasterIdleCall = 0; + +BEGIN_JUCE_NAMESPACE + extern void juce_callAnyTimersSynchronously(); + + #if JUCE_MAC + extern void initialiseMac(); + extern void* attachComponentToWindowRef (Component* component, void* windowRef); + extern void detachComponentFromWindowRef (Component* component, void* nsWindow); + extern void setNativeHostWindowSize (void* nsWindow, Component* editorComp, int newWidth, int newHeight); + extern void checkWindowVisibility (void* nsWindow, Component* component); + #endif + + #if JUCE_LINUX + extern Display* display; + extern bool juce_postMessageToSystemQueue (void* message); + #endif +END_JUCE_NAMESPACE + + +//============================================================================== +#if JUCE_WIN32 + +static HWND findMDIParentOf (HWND w) +{ + const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); + + while (w != 0) + { + HWND parent = GetParent (w); + + if (parent == 0) + break; + + TCHAR windowType [32]; + zeromem (windowType, sizeof (windowType)); + GetClassName (parent, windowType, 31); + + if (String (windowType).equalsIgnoreCase (T("MDIClient"))) + { + w = parent; + break; + } + + RECT windowPos; + GetWindowRect (w, &windowPos); + + RECT parentPos; + GetWindowRect (parent, &parentPos); + + const int dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); + const int dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); + + if (dw > 100 || dh > 100) + break; + + w = parent; + + if (dw == 2 * frameThickness) + break; + } + + return w; +} + +//============================================================================== +#elif JUCE_LINUX + +class SharedMessageThread : public Thread +{ +public: + SharedMessageThread() + : Thread (T("VstMessageThread")) + { + startThread (7); + } + + ~SharedMessageThread() + { + signalThreadShouldExit(); + JUCEApplication::quit(); + waitForThreadToExit (5000); + clearSingletonInstance(); + } + + void run() + { + MessageManager* const messageManager = MessageManager::getInstance(); + + const Thread::ThreadID originalThreadId = messageManager->getCurrentMessageThread(); + messageManager->setCurrentMessageThread (Thread::getCurrentThreadId()); + + while ((! threadShouldExit()) && messageManager->runDispatchLoopUntil (250)) + { + } + + messageManager->setCurrentMessageThread (originalThreadId); + } + + juce_DeclareSingleton (SharedMessageThread, false) +}; + + +#endif + +//============================================================================== +// A component to hold the AudioProcessorEditor, and cope with some housekeeping +// chores when it changes or repaints. +class EditorCompWrapper : public Component, + public AsyncUpdater +{ + JuceVSTWrapper* wrapper; + +public: + EditorCompWrapper (JuceVSTWrapper* const wrapper_, + AudioProcessorEditor* const editor) + : wrapper (wrapper_) + { + setOpaque (true); + editor->setOpaque (true); + + setBounds (editor->getBounds()); + editor->setTopLeftPosition (0, 0); + addAndMakeVisible (editor); + +#if JUCE_WIN32 + addMouseListener (this, true); +#endif + } + + ~EditorCompWrapper() + { + deleteAllChildren(); + } + + void paint (Graphics& g) + { + } + + void paintOverChildren (Graphics& g) + { + // 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(); + } + + AudioProcessorEditor* getEditorComp() const + { + return dynamic_cast (getChildComponent (0)); + } + + void resized() + { + Component* const c = getChildComponent (0); + + if (c != 0) + c->setBounds (0, 0, getWidth(), getHeight()); + } + + void childBoundsChanged (Component* child); + void handleAsyncUpdate(); + +#if JUCE_WIN32 + 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 + + //============================================================================== + juce_UseDebuggingNewOperator +}; + +static VoidArray activePlugins; + + +//============================================================================== +/** + This wraps an AudioProcessor as an AudioEffectX... +*/ +class JuceVSTWrapper : public AudioEffectX, + private Timer, + public AudioProcessorListener, + public AudioPlayHead +{ +public: + //============================================================================== + JuceVSTWrapper (audioMasterCallback audioMaster, + AudioProcessor* const filter_) + : AudioEffectX (audioMaster, + filter_->getNumPrograms(), + filter_->getNumParameters()), + filter (filter_) + { + editorComp = 0; + chunkMemoryTime = 0; + isProcessing = false; + hasShutdown = false; + firstProcessCallback = true; + shouldDeleteEditor = false; + channels = 0; + speakerIn = kSpeakerArrEmpty; + speakerOut = kSpeakerArrEmpty; + speakerInChans = 0; + speakerOutChans = 0; + numInChans = JucePlugin_MaxNumInputChannels; + numOutChans = JucePlugin_MaxNumOutputChannels; + +#if JUCE_MAC || JUCE_LINUX + hostWindow = 0; +#endif + + filter->setPlayConfigDetails (numInChans, numOutChans, 0, 0); + + filter_->setPlayHead (this); + filter_->addListener (this); + + cEffect.flags |= effFlagsHasEditor; + cEffect.version = (long) (JucePlugin_VersionCode); + + setUniqueID ((int) (JucePlugin_VSTUniqueID)); + +#if JucePlugin_WantsMidiInput && ! JUCE_USE_VSTSDK_2_4 + wantEvents(); +#endif + + setNumInputs (numInChans); + setNumOutputs (numOutChans); + + canProcessReplacing (true); + +#if ! JUCE_USE_VSTSDK_2_4 + hasVu (false); + hasClip (false); +#endif + + isSynth ((JucePlugin_IsSynth) != 0); + noTail ((JucePlugin_SilenceInProducesSilenceOut) != 0); + setInitialDelay (filter->getLatencySamples()); + programsAreChunks (true); + + activePlugins.add (this); + } + + ~JuceVSTWrapper() + { + stopTimer(); + deleteEditor (false); + + hasShutdown = true; + + delete filter; + filter = 0; + + jassert (editorComp == 0); + + juce_free (channels); + channels = 0; + deleteTempChannels(); + + jassert (activePlugins.contains (this)); + activePlugins.removeValue (this); + + if (activePlugins.size() == 0) + { +#if JUCE_LINUX + SharedMessageThread::deleteInstance(); +#endif + shutdownJuce_GUI(); + } + } + + void open() + { + if (editorComp == 0) + { + AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); + + if (ed != 0) + cEffect.flags |= effFlagsHasEditor; + else + cEffect.flags &= ~effFlagsHasEditor; + + filter->editorBeingDeleted (ed); + delete ed; + } + + startTimer (1000 / 4); + } + + void close() + { + jassert (! recursionCheck); + + stopTimer(); + deleteEditor (false); + } + + //============================================================================== + bool getEffectName (char* name) + { + String (JucePlugin_Name).copyToBuffer (name, 64); + return true; + } + + bool getVendorString (char* text) + { + String (JucePlugin_Manufacturer).copyToBuffer (text, 64); + return true; + } + + bool getProductString (char* text) + { + return getEffectName (text); + } + + VstInt32 getVendorVersion() + { + return JucePlugin_VersionCode; + } + + VstPlugCategory getPlugCategory() + { + return JucePlugin_VSTCategory; + } + + VstInt32 canDo (char* text) + { + VstInt32 result = 0; + + if (strcmp (text, "receiveVstEvents") == 0 + || strcmp (text, "receiveVstMidiEvent") == 0 + || strcmp (text, "receiveVstMidiEvents") == 0) + { +#if JucePlugin_WantsMidiInput + result = 1; +#else + result = -1; +#endif + } + else if (strcmp (text, "sendVstEvents") == 0 + || strcmp (text, "sendVstMidiEvent") == 0 + || strcmp (text, "sendVstMidiEvents") == 0) + { +#if JucePlugin_ProducesMidiOutput + result = 1; +#else + result = -1; +#endif + } + else if (strcmp (text, "receiveVstTimeInfo") == 0 + || strcmp (text, "conformsToWindowRules") == 0) + { + result = 1; + } + + return result; + } + + bool keysRequired() + { + return (JucePlugin_EditorRequiresKeyboardFocus) != 0; + } + + bool getInputProperties (VstInt32 index, VstPinProperties* properties) + { + if (filter == 0 || index >= JucePlugin_MaxNumInputChannels) + return false; + + const String name (filter->getInputChannelName ((int) index)); + + name.copyToBuffer (properties->label, kVstMaxLabelLen - 1); + name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1); + + if (speakerIn != kSpeakerArrEmpty) + { + properties->flags = kVstPinUseSpeaker; + properties->arrangementType = speakerIn; + } + else + { + properties->flags = kVstPinIsActive; + + if (filter->isInputChannelStereoPair ((int) index)) + properties->flags |= kVstPinIsStereo; + + properties->arrangementType = 0; + } + + return true; + } + + bool getOutputProperties (VstInt32 index, VstPinProperties* properties) + { + if (filter == 0 || index >= JucePlugin_MaxNumOutputChannels) + return false; + + const String name (filter->getOutputChannelName ((int) index)); + + name.copyToBuffer (properties->label, kVstMaxLabelLen - 1); + name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1); + + if (speakerOut != kSpeakerArrEmpty) + { + properties->flags = kVstPinUseSpeaker; + properties->arrangementType = speakerOut; + } + else + { + properties->flags = kVstPinIsActive; + + if (filter->isOutputChannelStereoPair ((int) index)) + properties->flags |= kVstPinIsStereo; + + properties->arrangementType = 0; + } + + return true; + } + + //============================================================================== + VstInt32 processEvents (VstEvents* events) + { +#if JucePlugin_WantsMidiInput + VSTMidiEventList::addEventsToMidiBuffer (events, midiEvents); + return 1; +#else + return 0; +#endif + } + + void process (float** inputs, float** outputs, VstInt32 numSamples) + { + const int numIn = numInChans; + const int numOut = numOutChans; + + AudioSampleBuffer temp (numIn, numSamples); + int i; + for (i = numIn; --i >= 0;) + memcpy (temp.getSampleData (i), outputs[i], sizeof (float) * numSamples); + + processReplacing (inputs, outputs, numSamples); + + AudioSampleBuffer dest (outputs, numOut, numSamples); + + for (i = jmin (numIn, numOut); --i >= 0;) + dest.addFrom (i, 0, temp, i, 0, numSamples); + } + + void processReplacing (float** inputs, float** outputs, VstInt32 numSamples) + { + 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) + resume(); + + filter->setNonRealtime (getCurrentProcessLevel() == 4 /* kVstProcessLevelOffline */); + +#if JUCE_WIN32 + if (GetThreadPriority (GetCurrentThread()) <= THREAD_PRIORITY_NORMAL + && GetThreadPriority (GetCurrentThread()) >= THREAD_PRIORITY_LOWEST) + filter->setNonRealtime (true); +#endif + } + +#if JUCE_DEBUG && ! JucePlugin_ProducesMidiOutput + const int numMidiEventsComingIn = midiEvents.getNumEvents(); +#endif + + jassert (activePlugins.contains (this)); + + { + const ScopedLock sl (filter->getCallbackLock()); + + const int numIn = numInChans; + const int numOut = numOutChans; + + if (filter->isSuspended()) + { + for (int i = 0; i < numOut; ++i) + zeromem (outputs[i], sizeof (float) * numSamples); + } + else + { + int i; + for (i = 0; i < numOut; ++i) + { + float* chan = (float*) tempChannels.getUnchecked(i); + + if (chan == 0) + { + chan = outputs[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 (outputs[j] == chan) + { + chan = (float*) juce_malloc (sizeof (float) * blockSize * 2); + tempChannels.set (i, chan); + break; + } + } + } + + if (i < numIn && chan != inputs[i]) + memcpy (chan, inputs[i], sizeof (float) * numSamples); + + channels[i] = chan; + } + + for (; i < numIn; ++i) + channels[i] = inputs[i]; + + AudioSampleBuffer chans (channels, jmax (numIn, numOut), numSamples); + + filter->processBlock (chans, midiEvents); + } + } + + if (! midiEvents.isEmpty()) + { +#if JucePlugin_ProducesMidiOutput + const int numEvents = midiEvents.getNumEvents(); + + outgoingEvents.ensureSize (numEvents); + outgoingEvents.clear(); + + const JUCE_NAMESPACE::uint8* midiEventData; + int midiEventSize, midiEventPosition; + MidiBuffer::Iterator i (midiEvents); + + while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) + { + jassert (midiEventPosition >= 0 && midiEventPosition < numSamples); + + outgoingEvents.addEvent (midiEventData, midiEventSize, midiEventPosition); + } + + sendVstEventsToHost (outgoingEvents.events); +#else + /* This assertion is caused when you've added some events to the + midiMessages array in your processBlock() method, which usually means + that you're trying to send them somewhere. But in this case they're + getting thrown away. + + If your plugin does want to send midi messages, you'll need to set + the JucePlugin_ProducesMidiOutput macro to 1 in your + JucePluginCharacteristics.h file. + + If you don't want to produce any midi output, then you should clear the + midiMessages array at the end of your processBlock() method, to + indicate that you don't want any of the events to be passed through + to the output. + */ + jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn); +#endif + + midiEvents.clear(); + } + } + + //============================================================================== + VstInt32 startProcess () { return 0; } + VstInt32 stopProcess () { return 0;} + + void resume() + { + if (filter == 0) + return; + + isProcessing = true; + juce_free (channels); + channels = (float**) juce_calloc (sizeof (float*) * (numInChans + numOutChans)); + + double rate = getSampleRate(); + jassert (rate > 0); + if (rate <= 0.0) + rate = 44100.0; + + const int blockSize = getBlockSize(); + jassert (blockSize > 0); + + firstProcessCallback = true; + + filter->setNonRealtime (getCurrentProcessLevel() == 4 /* kVstProcessLevelOffline */); + + filter->setPlayConfigDetails (numInChans, numOutChans, + rate, blockSize); + + deleteTempChannels(); + + filter->prepareToPlay (rate, blockSize); + midiEvents.clear(); + + setInitialDelay (filter->getLatencySamples()); + + AudioEffectX::resume(); + +#if JucePlugin_ProducesMidiOutput + outgoingEvents.ensureSize (64); +#endif + +#if JucePlugin_WantsMidiInput && ! JUCE_USE_VSTSDK_2_4 + wantEvents(); +#endif + } + + void suspend() + { + if (filter == 0) + return; + + AudioEffectX::suspend(); + + filter->releaseResources(); + outgoingEvents.freeEvents(); + + isProcessing = false; + juce_free (channels); + channels = 0; + + deleteTempChannels(); + } + + bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo& info) + { + const VstTimeInfo* const ti = getTimeInfo (kVstPpqPosValid + | kVstTempoValid + | kVstBarsValid + //| kVstCyclePosValid + | kVstTimeSigValid + | kVstSmpteValid + | kVstClockValid); + + if (ti == 0 || ti->sampleRate <= 0) + return false; + + if ((ti->flags & kVstTempoValid) != 0) + info.bpm = ti->tempo; + else + info.bpm = 0.0; + + if ((ti->flags & kVstTimeSigValid) != 0) + { + info.timeSigNumerator = ti->timeSigNumerator; + info.timeSigDenominator = ti->timeSigDenominator; + } + else + { + info.timeSigNumerator = 4; + info.timeSigDenominator = 4; + } + + info.timeInSeconds = ti->samplePos / ti->sampleRate; + + if ((ti->flags & kVstPpqPosValid) != 0) + info.ppqPosition = ti->ppqPos; + else + info.ppqPosition = 0.0; + + if ((ti->flags & kVstBarsValid) != 0) + info.ppqPositionOfLastBarStart = ti->barStartPos; + else + info.ppqPositionOfLastBarStart = 0.0; + + if ((ti->flags & kVstSmpteValid) != 0) + { + AudioPlayHead::FrameRateType rate = AudioPlayHead::fpsUnknown; + double fps = 1.0; + + switch (ti->smpteFrameRate) + { + case kVstSmpte24fps: + rate = AudioPlayHead::fps24; + fps = 24.0; + break; + + case kVstSmpte25fps: + rate = AudioPlayHead::fps25; + fps = 25.0; + break; + + case kVstSmpte2997fps: + rate = AudioPlayHead::fps2997; + fps = 29.97; + break; + + case kVstSmpte30fps: + rate = AudioPlayHead::fps30; + fps = 30.0; + break; + + case kVstSmpte2997dfps: + rate = AudioPlayHead::fps2997drop; + fps = 29.97; + break; + + case kVstSmpte30dfps: + rate = AudioPlayHead::fps30drop; + fps = 30.0; + break; + + case kVstSmpteFilm16mm: + case kVstSmpteFilm35mm: + fps = 24.0; + break; + + case kVstSmpte239fps: fps = 23.976; break; + case kVstSmpte249fps: fps = 24.976; break; + case kVstSmpte599fps: fps = 59.94; break; + case kVstSmpte60fps: fps = 60; break; + + default: + jassertfalse // unknown frame-rate.. + } + + info.frameRate = rate; + info.editOriginTime = ti->smpteOffset / (80.0 * fps); + } + else + { + info.frameRate = AudioPlayHead::fpsUnknown; + info.editOriginTime = 0; + } + + info.isRecording = (ti->flags & kVstTransportRecording) != 0; + info.isPlaying = (ti->flags & kVstTransportPlaying) != 0 || info.isRecording; + + return true; + } + + //============================================================================== + VstInt32 getProgram() + { + return filter != 0 ? filter->getCurrentProgram() : 0; + } + + void setProgram (VstInt32 program) + { + if (filter != 0) + filter->setCurrentProgram (program); + } + + void setProgramName (char* name) + { + if (filter != 0) + filter->changeProgramName (filter->getCurrentProgram(), name); + } + + void getProgramName (char* name) + { + if (filter != 0) + filter->getProgramName (filter->getCurrentProgram()).copyToBuffer (name, 24); + } + + bool getProgramNameIndexed (VstInt32 category, VstInt32 index, char* text) + { + if (filter != 0 && ((unsigned int) index) < (unsigned int) filter->getNumPrograms()) + { + filter->getProgramName (index).copyToBuffer (text, 24); + return true; + } + + return false; + } + + //============================================================================== + float getParameter (VstInt32 index) + { + if (filter == 0) + return 0.0f; + + jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); + return filter->getParameter (index); + } + + void setParameter (VstInt32 index, float value) + { + if (filter != 0) + { + jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); + filter->setParameter (index, value); + } + } + + void getParameterDisplay (VstInt32 index, char* text) + { + if (filter != 0) + { + jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); + filter->getParameterText (index).copyToBuffer (text, 24); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. + } + } + + void getParameterName (VstInt32 index, char* text) + { + if (filter != 0) + { + jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); + filter->getParameterName (index).copyToBuffer (text, 16); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. + } + } + + void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) + { + setParameterAutomated (index, newValue); + } + + void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) + { + beginEdit (index); + } + + void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) + { + endEdit (index); + } + + void audioProcessorChanged (AudioProcessor*) + { + updateDisplay(); + } + + bool canParameterBeAutomated (VstInt32 index) + { + return filter != 0 && filter->isParameterAutomatable ((int) index); + } + + bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput, + VstSpeakerArrangement* pluginOutput) + { + const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; + + for (int i = 0; i < numElementsInArray (channelConfigs); ++i) + { + bool configMono = (channelConfigs[i][1] == 1) && (pluginOutput->type == kSpeakerArrMono); + bool configStereo = (channelConfigs[i][1] == 2) && (pluginOutput->type == kSpeakerArrStereo); + bool inCountMatches = (channelConfigs[i][0] == pluginInput->numChannels); + bool outCountMatches = (channelConfigs[i][1] == pluginOutput->numChannels); + + if ((configMono || configStereo) && inCountMatches && outCountMatches) + { + speakerIn = (VstSpeakerArrangementType) pluginInput->type; + speakerOut = (VstSpeakerArrangementType) pluginOutput->type; + speakerInChans = pluginInput->numChannels; + speakerOutChans = pluginOutput->numChannels; + + filter->setPlayConfigDetails (speakerInChans, speakerOutChans, + filter->getSampleRate(), + filter->getBlockSize()); + return true; + } + } + + return false; + } + + //============================================================================== + VstInt32 getChunk (void** data, bool onlyStoreCurrentProgramData) + { + if (filter == 0) + return 0; + + chunkMemory.setSize (0); + if (onlyStoreCurrentProgramData) + filter->getCurrentProgramStateInformation (chunkMemory); + else + filter->getStateInformation (chunkMemory); + + *data = (void*) chunkMemory; + + // because the chunk is only needed temporarily by the host (or at least you'd + // hope so) we'll give it a while and then free it in the timer callback. + chunkMemoryTime = JUCE_NAMESPACE::Time::getApproximateMillisecondCounter(); + + return chunkMemory.getSize(); + } + + VstInt32 setChunk (void* data, VstInt32 byteSize, bool onlyRestoreCurrentProgramData) + { + if (filter == 0) + return 0; + + chunkMemory.setSize (0); + chunkMemoryTime = 0; + + if (byteSize > 0 && data != 0) + { + if (onlyRestoreCurrentProgramData) + filter->setCurrentProgramStateInformation (data, byteSize); + else + filter->setStateInformation (data, byteSize); + } + + return 0; + } + + void timerCallback() + { + if (shouldDeleteEditor) + { + shouldDeleteEditor = false; + deleteEditor (true); + } + + if (chunkMemoryTime > 0 + && chunkMemoryTime < JUCE_NAMESPACE::Time::getApproximateMillisecondCounter() - 2000 + && ! recursionCheck) + { + chunkMemoryTime = 0; + chunkMemory.setSize (0); + } + +#if JUCE_MAC + if (hostWindow != 0) + checkWindowVisibility (hostWindow, editorComp); +#endif + + tryMasterIdle(); + } + + void tryMasterIdle() + { + if (Component::isMouseButtonDownAnywhere() + && ! recursionCheck) + { + const JUCE_NAMESPACE::uint32 now = JUCE_NAMESPACE::Time::getMillisecondCounter(); + + if (now > lastMasterIdleCall + 20 && editorComp != 0) + { + lastMasterIdleCall = now; + + recursionCheck = true; + masterIdle(); + recursionCheck = false; + } + } + } + + void doIdleCallback() + { + // (wavelab calls this on a separate thread and causes a deadlock).. + if (MessageManager::getInstance()->isThisTheMessageThread() + && ! recursionCheck) + { + recursionCheck = true; + + juce_callAnyTimersSynchronously(); + + for (int i = ComponentPeer::getNumPeers(); --i >= 0;) + ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow(); + + recursionCheck = false; + } + } + + void createEditorComp() + { + if (hasShutdown || filter == 0) + return; + + if (editorComp == 0) + { + AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); + + if (ed != 0) + { + cEffect.flags |= effFlagsHasEditor; + ed->setOpaque (true); + ed->setVisible (true); + + editorComp = new EditorCompWrapper (this, ed); + } + else + { + cEffect.flags &= ~effFlagsHasEditor; + } + } + + shouldDeleteEditor = false; + } + + void deleteEditor (bool canDeleteLaterIfModal) + { + PopupMenu::dismissAllActiveMenus(); + + jassert (! recursionCheck); + recursionCheck = true; + + if (editorComp != 0) + { + Component* const modalComponent = Component::getCurrentlyModalComponent(); + if (modalComponent != 0) + { + modalComponent->exitModalState (0); + + if (canDeleteLaterIfModal) + { + shouldDeleteEditor = true; + return; + } + } + +#if JUCE_MAC + if (hostWindow != 0) + { + detachComponentFromWindowRef (editorComp, hostWindow); + hostWindow = 0; + } +#endif + + filter->editorBeingDeleted (editorComp->getEditorComp()); + + deleteAndZero (editorComp); + + // there's some kind of component currently modal, but the host + // is trying to delete our plugin. You should try to avoid this happening.. + jassert (Component::getCurrentlyModalComponent() == 0); + } + +#if JUCE_LINUX + hostWindow = 0; +#endif + + recursionCheck = false; + } + + VstIntPtr dispatcher (VstInt32 opCode, VstInt32 index, VstIntPtr value, void* ptr, float opt) + { + if (hasShutdown) + return 0; + + if (opCode == effEditIdle) + { + doIdleCallback(); + return 0; + } + else if (opCode == effEditOpen) + { + jassert (! recursionCheck); + + deleteEditor (true); + createEditorComp(); + + if (editorComp != 0) + { + editorComp->setOpaque (true); + editorComp->setVisible (false); + +#if JUCE_WIN32 + editorComp->addToDesktop (0); + hostWindow = (HWND) ptr; + HWND editorWnd = (HWND) editorComp->getWindowHandle(); + SetParent (editorWnd, hostWindow); + + DWORD val = GetWindowLong (editorWnd, GWL_STYLE); + val = (val & ~WS_POPUP) | WS_CHILD; + SetWindowLong (editorWnd, GWL_STYLE, val); +#elif JUCE_LINUX + editorComp->addToDesktop (0); + hostWindow = (Window) ptr; + Window editorWnd = (Window) editorComp->getWindowHandle(); + XReparentWindow (display, editorWnd, hostWindow, 0, 0); +#else + hostWindow = attachComponentToWindowRef (editorComp, (WindowRef) ptr); +#endif + editorComp->setVisible (true); + + return 1; + } + } + else if (opCode == effEditClose) + { + deleteEditor (true); + return 0; + } + else if (opCode == effEditGetRect) + { + createEditorComp(); + + if (editorComp != 0) + { + editorSize.left = 0; + editorSize.top = 0; + editorSize.right = editorComp->getWidth(); + editorSize.bottom = editorComp->getHeight(); + + *((ERect**) ptr) = &editorSize; + + return (VstIntPtr) (pointer_sized_int) &editorSize; + } + else + { + return 0; + } + } + + return AudioEffectX::dispatcher (opCode, index, value, ptr, opt); + } + + void resizeHostWindow (int newWidth, int newHeight) + { + if (editorComp != 0) + { +#if ! JUCE_LINUX // linux hosts shouldn't be trusted! + if (! (canHostDo ("sizeWindow") && sizeWindow (newWidth, newHeight))) +#endif + { + // some hosts don't support the sizeWindow call, so do it manually.. +#if JUCE_MAC + setNativeHostWindowSize (hostWindow, editorComp, newWidth, newHeight); +#elif JUCE_LINUX + Window root; + int x, y; + unsigned int width, height, border, depth; + + XGetGeometry (display, hostWindow, &root, + &x, &y, &width, &height, &border, &depth); + + newWidth += (width + border) - editorComp->getWidth(); + newHeight += (height + border) - editorComp->getHeight(); + + XResizeWindow (display, hostWindow, newWidth, newHeight); +#else + int dw = 0; + int dh = 0; + const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); + + HWND w = (HWND) editorComp->getWindowHandle(); + + while (w != 0) + { + HWND parent = GetParent (w); + + if (parent == 0) + break; + + TCHAR windowType [32]; + zeromem (windowType, sizeof (windowType)); + GetClassName (parent, windowType, 31); + + if (String (windowType).equalsIgnoreCase (T("MDIClient"))) + break; + + RECT windowPos; + GetWindowRect (w, &windowPos); + + RECT parentPos; + GetWindowRect (parent, &parentPos); + + SetWindowPos (w, 0, 0, 0, + newWidth + dw, + newHeight + dh, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); + + dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); + dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); + + w = parent; + + if (dw == 2 * frameThickness) + break; + + if (dw > 100 || dh > 100) + w = 0; + } + + if (w != 0) + SetWindowPos (w, 0, 0, 0, + newWidth + dw, + newHeight + dh, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); +#endif + } + + if (editorComp->getPeer() != 0) + editorComp->getPeer()->handleMovedOrResized(); + } + } + + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + AudioProcessor* filter; + JUCE_NAMESPACE::MemoryBlock chunkMemory; + JUCE_NAMESPACE::uint32 chunkMemoryTime; + EditorCompWrapper* editorComp; + ERect editorSize; + MidiBuffer midiEvents; + VSTMidiEventList outgoingEvents; + bool isProcessing; + bool hasShutdown; + bool firstProcessCallback; + int diffW, diffH; + VstSpeakerArrangementType speakerIn, speakerOut; + int speakerInChans, speakerOutChans; + int numInChans, numOutChans; + float** channels; + VoidArray tempChannels; // see note in processReplacing() + bool hasCreatedTempChannels; + bool shouldDeleteEditor; + + void deleteTempChannels() + { + int i; + for (i = tempChannels.size(); --i >= 0;) + juce_free (tempChannels.getUnchecked(i)); + + tempChannels.clear(); + + if (filter != 0) + tempChannels.insertMultiple (0, 0, filter->getNumInputChannels() + filter->getNumOutputChannels()); + + hasCreatedTempChannels = false; + } + + const String getHostName() + { + char host[256]; + zeromem (host, sizeof (host)); + getHostProductString (host); + return host; + } + +#if JUCE_MAC + void* hostWindow; +#elif JUCE_LINUX + Window hostWindow; +#else + HWND hostWindow; +#endif +}; + +//============================================================================== +void EditorCompWrapper::childBoundsChanged (Component* child) +{ + child->setTopLeftPosition (0, 0); + + const int cw = child->getWidth(); + const int ch = child->getHeight(); + + wrapper->resizeHostWindow (cw, ch); + setSize (cw, ch); + +#if JUCE_MAC + wrapper->resizeHostWindow (cw, ch); // (doing this a second time seems to be necessary in tracktion) +#endif +} + +void EditorCompWrapper::handleAsyncUpdate() +{ + wrapper->tryMasterIdle(); +} + +//============================================================================== +/** 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 AEffect* pluginEntryPoint (audioMasterCallback audioMaster) +{ + initialiseJuce_GUI(); + + try + { + if (audioMaster (0, audioMasterVersion, 0, 0, 0, 0) != 0) + { + AudioProcessor* const filter = createPluginFilter(); + + if (filter != 0) + { + JuceVSTWrapper* const wrapper = new JuceVSTWrapper (audioMaster, filter); + return wrapper->getAeffect(); + } + } + } + catch (...) + {} + + return 0; +} + + +//============================================================================== +// Mac startup code.. +#if JUCE_MAC + +extern "C" __attribute__ ((visibility("default"))) AEffect* VSTPluginMain (audioMasterCallback audioMaster) +{ + initialiseMac(); + return pluginEntryPoint (audioMaster); +} + +extern "C" __attribute__ ((visibility("default"))) AEffect* main_macho (audioMasterCallback audioMaster) +{ + initialiseMac(); + return pluginEntryPoint (audioMaster); +} + +//============================================================================== +// Linux startup code.. +#elif JUCE_LINUX + +extern "C" AEffect* VSTPluginMain (audioMasterCallback audioMaster) +{ + initialiseJuce_GUI(); + SharedMessageThread::getInstance(); + + return pluginEntryPoint (audioMaster); +} + +extern "C" __attribute__ ((visibility("default"))) AEffect* main_plugin (audioMasterCallback audioMaster) asm ("main"); + +extern "C" __attribute__ ((visibility("default"))) AEffect* main_plugin (audioMasterCallback audioMaster) +{ + return VSTPluginMain (audioMaster); +} + +__attribute__((constructor)) void myPluginInit() +{ + // don't put initialiseJuce_GUI here... it will crash ! +} + +__attribute__((destructor)) void myPluginFini() +{ + // don't put shutdownJuce_GUI here... it will crash ! +} + +//============================================================================== +// Win32 startup code.. +#else + +extern "C" __declspec (dllexport) AEffect* VSTPluginMain (audioMasterCallback audioMaster) +{ + return pluginEntryPoint (audioMaster); +} + +#ifndef _WIN64 // (can't compile this on win64, but it's not needed anyway with VST2.4) +extern "C" __declspec (dllexport) void* main (audioMasterCallback audioMaster) +{ + return (void*) pluginEntryPoint (audioMaster); +} +#endif + +#if JucePlugin_Build_RTAS +BOOL WINAPI DllMainVST (HINSTANCE instance, DWORD dwReason, LPVOID) +#else +extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD dwReason, LPVOID) +#endif +{ + if (dwReason == DLL_PROCESS_ATTACH) + PlatformUtilities::setCurrentModuleInstanceHandle (instance); + + return TRUE; +} + +#endif + +#endif diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index e1715ac855..a7e38f1cdd 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -679,6 +679,7 @@ public: #include #include #include +#include #if MACOS_10_4_OR_EARLIER #include @@ -16037,7 +16038,6 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE -void juce_setCurrentExecutableFileName (const String& filename) throw(); void juce_setCurrentThreadName (const String& name) throw(); static JUCEApplication* appInstance = 0; @@ -16257,8 +16257,6 @@ int JUCEApplication::main (int argc, char* argv[], const ScopedAutoReleasePool pool; #endif - juce_setCurrentExecutableFileName (String::fromUTF8 ((const uint8*) argv[0])); - String cmd; for (int i = 1; i < argc; ++i) cmd << String::fromUTF8 ((const uint8*) argv[i]) << T(' '); @@ -242340,11 +242338,6 @@ const File JUCE_CALLTYPE File::getSpecialLocation (const SpecialLocationType typ return juce_getSpecialFolderPath (csidlType); } -void juce_setCurrentExecutableFileName (const String&) throw() -{ - // n/a on windows -} - const File File::getCurrentWorkingDirectory() throw() { WCHAR dest [MAX_PATH_CHARS]; @@ -257098,6 +257091,13 @@ void juce_fileFlush (void* handle) throw() fsync ((int) (pointer_sized_int) handle); } +const File juce_getExecutableFile() +{ + Dl_info exeInfo; + dladdr ((const void*) juce_getExecutableFile, &exeInfo); + return File (exeInfo.dli_fname); +} + // if this file doesn't exist, find a parent of it that does.. static bool doStatFS (const File* file, struct statfs& result) throw() { @@ -257282,8 +257282,6 @@ void InterProcessLock::exit() throw() } /********* End of inlined file: juce_posix_SharedCode.h *********/ -static File executableFile; - void juce_getFileTimes (const String& fileName, int64& modificationTime, int64& accessTime, @@ -257469,21 +257467,7 @@ const File File::getSpecialLocation (const SpecialLocationType type) case currentExecutableFile: case currentApplicationFile: - if (! executableFile.exists()) - { - Dl_info executableInfo; - dladdr ((const void*) juce_getFileTimes, &executableInfo); - - if (executableInfo.dli_fname != 0) - executableFile = File (String (executableInfo.dli_fname)); - } - - // if this fails, it's probably because juce_setCurrentExecutableFileName() - // was never called to set the filename - this should be done by the juce - // main() function, so maybe you've hacked it to use your own custom main()? - jassert (executableFile.exists()); - - return executableFile; + return juce_getExecutableFile(); default: jassertfalse // unknown type? @@ -257493,11 +257477,6 @@ const File File::getSpecialLocation (const SpecialLocationType type) return File::nonexistent; } -void juce_setCurrentExecutableFileName (const String& filename) throw() -{ - executableFile = File::getCurrentWorkingDirectory().getChildFile (filename); -} - const File File::getCurrentWorkingDirectory() throw() { char buf [2048]; @@ -267222,6 +267201,13 @@ void juce_fileFlush (void* handle) throw() fsync ((int) (pointer_sized_int) handle); } +const File juce_getExecutableFile() +{ + Dl_info exeInfo; + dladdr ((const void*) juce_getExecutableFile, &exeInfo); + return File (exeInfo.dli_fname); +} + // if this file doesn't exist, find a parent of it that does.. static bool doStatFS (const File* file, struct statfs& result) throw() { @@ -267416,8 +267402,6 @@ void InterProcessLock::exit() throw() live in juce_posix_SharedCode.h! */ -static File executableFile; - const unsigned int macTimeToUnixTimeDiff = 0x7c25be90; static uint64 utcDateTimeToUnixTime (const UTCDateTime& d) throw() @@ -267656,22 +267640,23 @@ const File File::getSpecialLocation (const SpecialLocationType type) case tempDirectory: { - File tmp (T("~/Library/Caches/") + executableFile.getFileNameWithoutExtension()); + File tmp (T("~/Library/Caches/") + juce_getExecutableFile().getFileNameWithoutExtension()); tmp.createDirectory(); return tmp.getFullPathName(); } case currentExecutableFile: - return executableFile; + return juce_getExecutableFile(); case currentApplicationFile: { - const File parent (executableFile.getParentDirectory()); + const File exe (juce_getExecutableFile()); + const File parent (exe.getParentDirectory()); return parent.getFullPathName().endsWithIgnoreCase (T("Contents/MacOS")) ? parent.getParentDirectory().getParentDirectory() - : executableFile; + : exe; } default: @@ -267685,22 +267670,6 @@ const File File::getSpecialLocation (const SpecialLocationType type) return File::nonexistent; } -void juce_setCurrentExecutableFileName (const String& filename) throw() -{ - executableFile = File::getCurrentWorkingDirectory() - .getChildFile (PlatformUtilities::convertToPrecomposedUnicode (filename)); -} - -void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw() -{ - const ScopedAutoReleasePool pool; - - NSBundle* b = [NSBundle bundleWithIdentifier: juceStringToNS (bundleId)]; - - if (b != nil) - executableFile = nsStringToJuce ([b executablePath]); -} - const File File::getCurrentWorkingDirectory() throw() { char buf [2048]; diff --git a/src/juce_appframework/application/juce_Application.cpp b/src/juce_appframework/application/juce_Application.cpp index 3171523f35..81202debd8 100644 --- a/src/juce_appframework/application/juce_Application.cpp +++ b/src/juce_appframework/application/juce_Application.cpp @@ -53,7 +53,6 @@ BEGIN_JUCE_NAMESPACE #include "../../juce_core/threads/juce_InterProcessLock.h" #include "../../juce_core/misc/juce_PlatformUtilities.h" -void juce_setCurrentExecutableFileName (const String& filename) throw(); void juce_setCurrentThreadName (const String& name) throw(); static JUCEApplication* appInstance = 0; @@ -279,8 +278,6 @@ int JUCEApplication::main (int argc, char* argv[], const ScopedAutoReleasePool pool; #endif - juce_setCurrentExecutableFileName (String::fromUTF8 ((const uint8*) argv[0])); - String cmd; for (int i = 1; i < argc; ++i) cmd << String::fromUTF8 ((const uint8*) argv[i]) << T(' ');