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.