From 54243ef0c0c528ed5c8de805cde0ecf8a72ae5a2 Mon Sep 17 00:00:00 2001 From: hogliux Date: Mon, 23 May 2016 15:41:45 +0100 Subject: [PATCH] Support hosting your own VST bundles on iOS --- .../jucer_ProjectExport_XCode.h | 2 +- .../VST/juce_VST_Wrapper.cpp | 35 ++++++++--- .../VST/juce_VST_Wrapper.mm | 3 + .../format/juce_AudioPluginFormatManager.cpp | 4 +- .../format_types/juce_VSTPluginFormat.cpp | 58 +++++++++++++++---- .../format_types/juce_VSTPluginFormat.h | 2 +- .../scanning/juce_PluginListComponent.cpp | 2 + 7 files changed, 84 insertions(+), 22 deletions(-) diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h index d95b22aa6b..632b520fce 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h @@ -124,7 +124,7 @@ public: bool isOSX() const override { return ! iOS; } bool isiOS() const override { return iOS; } - bool supportsVST() const override { return ! iOS; } + bool supportsVST() const override { return true; } bool supportsVST3() const override { return ! iOS; } bool supportsAAX() const override { return ! iOS; } bool supportsRTAS() const override { return ! iOS; } diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp index e526d204aa..d5060d8c7a 100644 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp @@ -272,11 +272,13 @@ public: firstProcessCallback (true), shouldDeleteEditor (false), #if JUCE_64BIT - useNSView (true), + useNSView (true) #else - useNSView (false), + useNSView (false) + #endif + #if ! JUCE_IOS + , hostWindow (0) #endif - hostWindow (0) { busUtils.init(); @@ -343,7 +345,9 @@ public: delete filter; filter = nullptr; + #if ! JUCE_IOS jassert (editorComp == 0); + #endif deleteTempChannels(); @@ -1331,6 +1335,7 @@ public: void createEditorComp() { + #if ! JUCE_IOS if (hasShutdown || filter == nullptr) return; @@ -1349,12 +1354,16 @@ public: cEffect.flags &= ~effFlagsHasEditor; } } + #endif shouldDeleteEditor = false; } void deleteEditor (bool canDeleteLaterIfModal) { + #if JUCE_IOS + ignoreUnused (canDeleteLaterIfModal); + #else JUCE_AUTORELEASEPOOL { PopupMenu::dismissAllActiveMenus(); @@ -1396,6 +1405,7 @@ public: hostWindow = 0; #endif } + #endif } VstIntPtr dispatcher (VstInt32 opCode, VstInt32 index, VstIntPtr value, void* ptr, float opt) override @@ -1403,6 +1413,7 @@ public: if (hasShutdown) return 0; + #if ! JUCE_IOS if (opCode == effEditIdle) { doIdleCallback(); @@ -1432,7 +1443,7 @@ public: hostWindow = (Window) ptr; Window editorWnd = (Window) editorComp->getWindowHandle(); XReparentWindow (display, editorWnd, hostWindow, 0, 0); - #else + #elif JUCE_MAC hostWindow = attachComponentToWindowRefVST (editorComp, ptr, useNSView); #endif editorComp->setVisible (true); @@ -1467,10 +1478,11 @@ public: return 0; } - + #endif return AudioEffectX::dispatcher (opCode, index, value, ptr, opt); } + #if ! JUCE_IOS void resizeHostWindow (int newWidth, int newHeight) { if (editorComp != nullptr) @@ -1659,6 +1671,7 @@ public: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EditorCompWrapper) }; + #endif //============================================================================== private: @@ -1666,8 +1679,10 @@ private: PluginBusUtilities busUtils; juce::MemoryBlock chunkMemory; juce::uint32 chunkMemoryTime; + #if ! JUCE_IOS ScopedPointer editorComp; ERect editorSize; + #endif MidiBuffer midiEvents; VSTMidiEventList outgoingEvents; bool isProcessing, isBypassed, hasShutdown, isInSizeWindow, firstProcessCallback; @@ -1680,7 +1695,7 @@ private: void* hostWindow; #elif JUCE_LINUX Window hostWindow; - #else + #elif JUCE_WINDOWS HWND hostWindow; #endif @@ -1974,14 +1989,17 @@ namespace //============================================================================== // Mac startup code.. -#if JUCE_MAC +#if JUCE_MAC || JUCE_IOS JUCE_EXPORTED_FUNCTION AEffect* VSTPluginMain (audioMasterCallback audioMaster); JUCE_EXPORTED_FUNCTION AEffect* VSTPluginMain (audioMasterCallback audioMaster) { JUCE_DECLARE_WRAPPER_TYPE (wrapperType_VST); + #if JUCE_MAC initialiseMacVST(); + #endif + return pluginEntryPoint (audioMaster); } @@ -1990,7 +2008,10 @@ namespace { JUCE_DECLARE_WRAPPER_TYPE (wrapperType_VST); + #if JUCE_MAC initialiseMacVST(); + #endif + return pluginEntryPoint (audioMaster); } diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm index 55370bc924..7584303b91 100644 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm +++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm @@ -22,6 +22,8 @@ ============================================================================== */ +#if JUCE_MAC + #include "../../juce_core/system/juce_TargetPlatform.h" #include "../utility/juce_CheckSettingMacros.h" @@ -311,3 +313,4 @@ bool forwardCurrentKeyEventToHostVST (Component* comp, bool isNSView) } // (juce namespace) #endif +#endif diff --git a/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.cpp b/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.cpp index 1235e0608b..a6f8f1e3b2 100644 --- a/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.cpp +++ b/modules/juce_audio_processors/format/juce_AudioPluginFormatManager.cpp @@ -65,7 +65,7 @@ void AudioPluginFormatManager::addDefaultFormats() // you should only call this method once! for (int i = formats.size(); --i >= 0;) { - #if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX) + #if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_IOS) jassert (dynamic_cast (formats[i]) == nullptr); #endif @@ -87,7 +87,7 @@ void AudioPluginFormatManager::addDefaultFormats() formats.add (new AudioUnitPluginFormat()); #endif - #if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX) + #if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_IOS) formats.add (new VSTPluginFormat()); #endif diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index 450780cbb4..aa730ffd07 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -22,7 +22,7 @@ ============================================================================== */ -#if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX) +#if JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_IOS) //============================================================================== #if JUCE_MAC && JUCE_SUPPORT_CARBON @@ -165,7 +165,7 @@ namespace { #if JUCE_WINDOWS return timeGetTime() * 1000000.0; - #elif JUCE_LINUX + #elif JUCE_LINUX || JUCE_IOS timeval micro; gettimeofday (µ, 0); return micro.tv_usec * 1000.0; @@ -378,7 +378,7 @@ public: { getActiveModules().add (this); - #if JUCE_WINDOWS || JUCE_LINUX + #if JUCE_WINDOWS || JUCE_LINUX || JUCE_IOS fullParentDirectoryPathName = f.getParentDirectory().getFullPathName(); #elif JUCE_MAC FSRef ref; @@ -394,9 +394,12 @@ public: } //============================================================================== -#if JUCE_WINDOWS || JUCE_LINUX - DynamicLibrary module; + #if ! JUCE_MAC String fullParentDirectoryPathName; + #endif + + #if JUCE_WINDOWS || JUCE_LINUX + DynamicLibrary module; bool open() { @@ -457,11 +460,14 @@ public: return String(); } #endif -#else + #else Handle resHandle; CFBundleRef bundleRef; + + #if JUCE_MAC + CFBundleRefNum resFileId; FSSpec parentDirFSSpec; - ResFileRefNum resFileId; + #endif bool open() { @@ -504,13 +510,18 @@ public: if (pluginName.isEmpty()) pluginName = file.getFileNameWithoutExtension(); + #if JUCE_MAC resFileId = CFBundleOpenBundleResourceMap (bundleRef); + #endif ok = true; Array vstXmlFiles; - file.getChildFile ("Contents") + file + #if JUCE_MAC + .getChildFile ("Contents") .getChildFile ("Resources") + #endif .findChildFiles (vstXmlFiles, File::findFiles, false, "*.vstxml"); if (vstXmlFiles.size() > 0) @@ -535,7 +546,9 @@ public: { if (bundleRef != 0) { + #if JUCE_MAC CFBundleCloseBundleResourceMap (bundleRef, resFileId); + #endif if (CFGetRetainCount (bundleRef) == 1) CFBundleUnloadExecutable (bundleRef); @@ -550,7 +563,7 @@ public: eff->dispatcher (eff, effClose, 0, 0, 0, 0); } -#endif + #endif private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModuleHandle) @@ -856,7 +869,12 @@ public: } //============================================================================== + #if JUCE_IOS + bool hasEditor() const override { return false; } + #else bool hasEditor() const override { return effect != nullptr && (effect->flags & effFlagsHasEditor) != 0; } + #endif + AudioProcessorEditor* createEditor() override; //============================================================================== @@ -1787,6 +1805,7 @@ private: }; //============================================================================== +#if ! JUCE_IOS class VSTPluginWindow; static Array activeVSTWindows; @@ -2525,7 +2544,7 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VSTPluginWindow) }; - +#endif #if JUCE_MSVC #pragma warning (pop) #endif @@ -2533,8 +2552,12 @@ private: //============================================================================== AudioProcessorEditor* VSTPluginInstance::createEditor() { + #if JUCE_IOS + return nullptr; + #else return hasEditor() ? new VSTPluginWindow (*this) : nullptr; + #endif } //============================================================================== @@ -2676,7 +2699,7 @@ bool VSTPluginFormat::fileMightContainThisPluginType (const String& fileOrIdenti { const File f (File::createFileWithoutCheckingPath (fileOrIdentifier)); - #if JUCE_MAC + #if JUCE_MAC || JUCE_IOS return f.isDirectory() && f.hasFileExtension (".vst"); #elif JUCE_WINDOWS return f.existsAsFile() && f.hasFileExtension (".dll"); @@ -2751,6 +2774,19 @@ FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() paths.add (WindowsRegistry::getValue ("HKEY_LOCAL_MACHINE\\Software\\VST\\VSTPluginsPath", programFiles + "\\VstPlugins")); return paths; + #elif JUCE_IOS + // on iOS you can only load plug-ins inside the hosts bundle folder + CFURLRef relativePluginDir = CFBundleCopyBuiltInPlugInsURL (CFBundleGetMainBundle()); + CFURLRef pluginDir = CFURLCopyAbsoluteURL (relativePluginDir); + CFRelease (relativePluginDir); + + CFStringRef path = CFURLCopyFileSystemPath (pluginDir, kCFURLPOSIXPathStyle); + CFRelease (pluginDir); + + FileSearchPath retval (String (CFStringGetCStringPtr (path, kCFStringEncodingUTF8))); + CFRelease (path); + + return retval; #endif } diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h index f37dbb1857..c0007c207f 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h @@ -22,7 +22,7 @@ ============================================================================== */ -#if (JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX)) || DOXYGEN +#if (JUCE_PLUGINHOST_VST && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_IOS)) || DOXYGEN //============================================================================== /** diff --git a/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp b/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp index 37adaa376c..a321a5da30 100644 --- a/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp +++ b/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp @@ -348,8 +348,10 @@ public: if (path.getNumPaths() > 0) // if the path is empty, then paths aren't used for this format. { + #if ! JUCE_IOS if (propertiesToUse != nullptr) path = getLastSearchPath (*propertiesToUse, formatToScan); + #endif pathList.setSize (500, 300); pathList.setPath (path);