Probably sounds a bit oddball but are AUs on iOS Possible with JUCE?
-Thanks
Probably sounds a bit oddball but are AUs on iOS Possible with JUCE?
-Thanks
AU are not supported in iOS by Apple nor by Juce.
Accessing the AU is being done using Apple’s Component Manager so it probably won’t work in iOs.
On the other hand, since AU is a bundle you can probably manually connect to it, dunno how hard it is.
You should also check that the AU is not relaying on some SDK stuff that is not supported in iOs.
Tell us if you managed to make it work… I’m interested to know
No, they only allow the built-in AUs to be used. I think that’s probably because they don’t want to provide any way for an app to access the music library directly (i.e. to get the actual sample data), and letting you use custom AUs would mean you could write one that streams/saves the content.
interesting… I actually posted this question a little prematurely. I had an idea to use an audio unit plugin as content for an iOS app. So build an AU host then have it load a plugin as its content. Was really looking for a way to just use the host/plugin as a way to update my app dynamically. Is there any other way to archive this?
-Thanks
I was looking into enabling limited AU support on iOS (no loading from files, no UI, no events), and based on my limited testing, this should be really straightforward to get working. I made a really quick preprocessor hack which allows me to use the built in plugins, patch against 3.2.0 below. Jules, would you consider enabling AU on iOS in a similar manner as what I've done?
I wasn't able to upload this patch, so I'm pasting it here:
diff --git a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h index b0738ed..f4b605f 100644 --- a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h +++ b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h @@ -22,7 +22,7 @@ ============================================================================== */ -#if (JUCE_PLUGINHOST_AU && JUCE_MAC) || DOXYGEN +#if (JUCE_PLUGINHOST_AU && (JUCE_MAC || JUCE_IOS)) || DOXYGEN //============================================================================== /** diff --git a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm index 035220d..bc4e306 100644 --- a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -22,26 +22,35 @@ ============================================================================== */ -#if JUCE_PLUGINHOST_AU && JUCE_MAC +#if JUCE_PLUGINHOST_AU && (JUCE_MAC || JUCE_IOS) } // (juce namespace) #include <AudioUnit/AudioUnit.h> +#include <CoreMIDI/MIDIServices.h> + +#if JUCE_MAC + #include <AudioUnit/AUCocoaUIView.h> #include <CoreAudioKit/AUGenericView.h> #include <AudioToolbox/AudioUnitUtilities.h> -#include <CoreMIDI/MIDIServices.h> #if JUCE_SUPPORT_CARBON #include <AudioUnit/AudioUnitCarbonView.h> #endif +#endif // JUCE_MAC + +#if JUCE_IOS // https://developer.apple.com/library/ios/qa/qa1643/_index.html +#define AudioGetCurrentHostTime() mach_absolute_time() +#endif + namespace juce { #include "../../juce_audio_devices/native/juce_MidiDataConcatenator.h" -#if JUCE_SUPPORT_CARBON +#if JUCE_MAC && JUCE_SUPPORT_CARBON #include "../../juce_gui_extra/native/juce_mac_CarbonViewWrapperComponent.h" #endif @@ -172,6 +181,7 @@ namespace AudioUnitFormatHelpers return false; } +#if JUCE_MAC bool getComponentDescFromFile (const String& fileOrIdentifier, AudioComponentDescription& desc, String& name, String& version, String& manufacturer) { @@ -249,6 +259,7 @@ namespace AudioUnitFormatHelpers return desc.componentType != 0 && desc.componentSubType != 0; } +#endif const char* getCategory (OSType type) noexcept { @@ -286,7 +297,9 @@ public: numInputBusses (0), numOutputBusses (0), audioUnit (nullptr), +#if JUCE_MAC eventListenerRef (0), +#endif midiConcatenator (2048) { using namespace AudioUnitFormatHelpers; @@ -298,7 +311,10 @@ public: JUCE_AU_LOG ("Opening AU: " + fileOrIdentifier); if (getComponentDescFromIdentifier (fileOrIdentifier, componentDesc, pluginName, version, manufacturer) - || getComponentDescFromFile (fileOrIdentifier, componentDesc, pluginName, version, manufacturer)) + #if JUCE_MAC + || getComponentDescFromFile (fileOrIdentifier, componentDesc, pluginName, version, manufacturer) + #endif + ) { if (AudioComponent comp = AudioComponentFindNext (0, &componentDesc)) { @@ -324,11 +340,13 @@ public: jassert (AudioUnitFormatHelpers::insideCallback.get() == 0); #endif + #if JUCE_MAC if (eventListenerRef != 0) { AUListenerDispose (eventListenerRef); eventListenerRef = 0; } + #endif if (audioUnit != nullptr) { @@ -656,6 +674,7 @@ public: void sendParameterChangeEvent (int index) { +#if JUCE_MAC jassert (audioUnit != nullptr); const ParamInfo& p = *parameters.getUnchecked (index); @@ -668,10 +687,12 @@ public: ev.mArgument.mParameter.mElement = 0; AUEventListenerNotify (nullptr, nullptr, &ev); +#endif } void sendAllParametersChangedEvents() { +#if JUCE_MAC jassert (audioUnit != nullptr); AudioUnitParameter param; @@ -679,6 +700,7 @@ public: param.mParameterID = kAUParameterListener_AnyParameter; AUParameterListenerNotify (nullptr, nullptr, ¶m); +#endif } const String getParameterName (int index) override @@ -901,7 +923,8 @@ private: friend class AudioUnitPluginWindowCarbon; friend class AudioUnitPluginWindowCocoa; friend class AudioUnitPluginFormat; - + friend class IOSBuiltinPluginFormat; + AudioComponentDescription componentDesc; String pluginName, manufacturer, version; String fileOrIdentifier; @@ -914,7 +937,9 @@ private: AudioUnitElement numInputBusChannels, numOutputBusChannels, numInputBusses, numOutputBusses; AudioUnit audioUnit; +#if JUCE_MAC AUEventListenerRef eventListenerRef; +#endif struct ParamInfo { @@ -946,6 +971,7 @@ private: kAudioUnitScope_Input, i, &info, sizeof (info)); } +#if JUCE_MAC if (producesMidiMessages) { AUMIDIOutputCallbackStruct info; @@ -957,6 +983,7 @@ private: producesMidiMessages = (AudioUnitSetProperty (audioUnit, kAudioUnitProperty_MIDIOutputCallback, kAudioUnitScope_Global, 0, &info, sizeof (info)) == noErr); } +#endif { HostCallbackInfo info; @@ -971,6 +998,7 @@ private: kAudioUnitScope_Global, 0, &info, sizeof (info)); } +#if JUCE_MAC AUEventListenerCreate (eventListenerCallback, this, #if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 CFRunLoopGetMain(), @@ -1006,9 +1034,12 @@ private: event.mEventType = kAudioUnitEvent_PropertyChange; AUEventListenerAddEventType (eventListenerRef, nullptr, &event); + +#endif } } +#if JUCE_MAC void eventCallback (const AudioUnitEvent& event, AudioUnitParameterValue newValue) { switch (event.mEventType) @@ -1047,6 +1078,8 @@ private: jassert (event != nullptr); static_cast<AudioUnitPluginInstance*> (userRef)->eventCallback (*event, value); } + + #endif //============================================================================== OSStatus renderGetInput (AudioUnitRenderActionFlags*, @@ -1304,6 +1337,7 @@ private: bool canProduceMidiOutput() { +#if JUCE_MAC UInt32 dataSize = 0; Boolean isWritable = false; @@ -1321,14 +1355,16 @@ private: return result; } } - +#endif + return false; } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioUnitPluginInstance) }; - + //============================================================================== +#if JUCE_MAC class AudioUnitPluginWindowCocoa : public AudioProcessorEditor { public: @@ -1579,10 +1615,15 @@ private: }; #endif + +#endif // JUCE_MAC //============================================================================== AudioProcessorEditor* AudioUnitPluginInstance::createEditor() { +#if JUCE_IOS + return nullptr; +#else ScopedPointer<AudioProcessorEditor> w (new AudioUnitPluginWindowCocoa (*this, false)); if (! static_cast<AudioUnitPluginWindowCocoa*> (w.get())->isValid()) @@ -1602,6 +1643,7 @@ AudioProcessorEditor* AudioUnitPluginInstance::createEditor() w = new AudioUnitPluginWindowCocoa (*this, true); // use AUGenericView as a fallback return w.release(); +#endif }
We might do something similar, but TBH haven't yet investigated how the new iOS AU APIs work - it may all be completely different to the existing AU stuff.
v3 AU’s will run in a separate process than the host… won’t this mean the (current JUCE) keyboard hooks won’t work?
Cheers,
Rail
Quite possibly.