diff --git a/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/Info-Standalone_Plugin.plist b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/Info-Standalone_Plugin.plist
new file mode 100644
index 0000000000..89f52de629
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/Info-Standalone_Plugin.plist
@@ -0,0 +1,62 @@
+
+
+
+
+
+ LSRequiresIPhoneOS
+
+ NSMicrophoneUsageDescription
+ This app requires microphone input.
+ UIViewControllerBasedStatusBarAppearance
+
+ CFBundleExecutable
+ ${EXECUTABLE_NAME}
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleName
+ InterAppAudioEffect
+ CFBundleDisplayName
+ InterAppAudioEffect
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ CFBundleShortVersionString
+ 1.0.0
+ CFBundleVersion
+ 1.0.0
+ NSHumanReadableCopyright
+ ROLI Ltd.
+ NSHighResolutionCapable
+
+ UIRequiresFullScreen
+
+ UIStatusBarHidden
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIBackgroundModes
+
+ audio
+
+ AudioComponents
+
+
+ name
+ ROLI Ltd.: InterAppAudioEffect
+ manufacturer
+ ROLI
+ type
+ aurx
+ subtype
+ IAAE
+ version
+ 65536
+
+
+
+
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect.entitlements b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect.entitlements
new file mode 100644
index 0000000000..ee8c4fb8d8
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect.entitlements
@@ -0,0 +1,8 @@
+
+
+
+
+ inter-app-audio
+
+
+
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect.xcodeproj/project.pbxproj b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..2f6cef507d
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect.xcodeproj/project.pbxproj
@@ -0,0 +1,373 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+ 48524E1776017288798AB20A = {isa = PBXBuildFile; fileRef = E9D6BA12BDD1947BDDAE08F7; };
+ 8EF8670E422BB9CF164302DF = {isa = PBXBuildFile; fileRef = 873711620EC157BCCFFF80B1; };
+ 61D6F1506B76AFBA614F491E = {isa = PBXBuildFile; fileRef = 67BBA32BE9EE1CAF8A105F6A; };
+ 03A7A8C261C0A1B578F219EF = {isa = PBXBuildFile; fileRef = E43030B35C6CB127DC67FEE7; };
+ E9FB1841DE3518ADBD86293C = {isa = PBXBuildFile; fileRef = 53BB9950BAA9E837613ED83B; };
+ 7B71DA92A48B9D67BA68C69E = {isa = PBXBuildFile; fileRef = 212019C041EE17C23460CE02; };
+ BC8485848043996AFA210EF9 = {isa = PBXBuildFile; fileRef = C293562C310CB0B3259811F0; };
+ 7FF11BF2317D79501E0632DB = {isa = PBXBuildFile; fileRef = E4431E84242848EF9D250FC7; };
+ DD2143886468728A97F9586E = {isa = PBXBuildFile; fileRef = C43FC3A63342AA4CDE8F0906; };
+ EE6B5FC34FB47B41336EA293 = {isa = PBXBuildFile; fileRef = AD9B42ED650058295A747510; };
+ B2E5CB24DBACF25E2CBAC9A1 = {isa = PBXBuildFile; fileRef = F07FA71EC2B5FCA584FAA10B; };
+ 6FAEC70FAE3DBC629160F86C = {isa = PBXBuildFile; fileRef = 41CB50701EE5BFDCE1F89BBA; };
+ DFF48C0819F2191B154569A9 = {isa = PBXBuildFile; fileRef = B69C94CF64688C5270D8122C; };
+ 9BB46E700B9A4617B4CFDC24 = {isa = PBXBuildFile; fileRef = 82F310E23852E0C002F5A2D1; };
+ 4EC4A8C3AF328E40626CBAE7 = {isa = PBXBuildFile; fileRef = E5A657DE5A5B1516B3E35FA8; };
+ 9A7D9D7490AF3D82BA8D9686 = {isa = PBXBuildFile; fileRef = 2C4476A46744766A478A74B6; };
+ 40833B424B5E9EC84C09EE40 = {isa = PBXBuildFile; fileRef = 131A768FD64EB99097B0B190; };
+ 7ACC830E1DDF0F171C890B2B = {isa = PBXBuildFile; fileRef = 7C1F5AA6FE8016951F45F916; };
+ 78BD211C42E345A8048DEDD5 = {isa = PBXBuildFile; fileRef = 0EB1F323BA52207C49A27479; };
+ A49F3F55F083BAD332CA4324 = {isa = PBXBuildFile; fileRef = 223C6D257BB45525A7C2D495; };
+ B2BE378326805DEBB71B3016 = {isa = PBXBuildFile; fileRef = D9C8C1E2D3F27800C6E774D7; };
+ BCA424EEB2F9F33372CA4909 = {isa = PBXBuildFile; fileRef = CDCF152172E34769B268ECDA; };
+ 246490CF3D197E69B1F7FCC8 = {isa = PBXBuildFile; fileRef = 02ABCEB5E369CDE6AEA817B3; };
+ 873E620B819DC84C953EC518 = {isa = PBXBuildFile; fileRef = 32E0486AA56B56AD10D18A56; };
+ 40E6F5A9B432DEB7689AF7D0 = {isa = PBXBuildFile; fileRef = 4B55841B06C897F72BC2F8CE; };
+ 78412E76B9D1D75907390309 = {isa = PBXBuildFile; fileRef = C450D63325E2C29C72B6606C; };
+ E3DD6181D2A4E2703637E1EF = {isa = PBXBuildFile; fileRef = 36A796A962C81B44E9233775; };
+ E8410AF631A96357D2807C3A = {isa = PBXBuildFile; fileRef = 10EEE1E56B53B7A31753365C; };
+ DCEE24917F78097ACF14EAD0 = {isa = PBXBuildFile; fileRef = 1F042A6F2A0986F23B7097FC; };
+ CA28F22C95EBC20CB37612FF = {isa = PBXBuildFile; fileRef = A3BDBD773FBCCD4F9440D174; };
+ 02ABCEB5E369CDE6AEA817B3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_audio_processors.mm"; path = "../../JuceLibraryCode/juce_audio_processors.mm"; sourceTree = "SOURCE_ROOT"; };
+ 0EB1F323BA52207C49A27479 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_audio_formats.mm"; path = "../../JuceLibraryCode/juce_audio_formats.mm"; sourceTree = "SOURCE_ROOT"; };
+ 10EEE1E56B53B7A31753365C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_graphics.mm"; path = "../../JuceLibraryCode/juce_graphics.mm"; sourceTree = "SOURCE_ROOT"; };
+ 131A768FD64EB99097B0B190 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_audio_basics.mm"; path = "../../JuceLibraryCode/juce_audio_basics.mm"; sourceTree = "SOURCE_ROOT"; };
+ 1F042A6F2A0986F23B7097FC = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_gui_basics.mm"; path = "../../JuceLibraryCode/juce_gui_basics.mm"; sourceTree = "SOURCE_ROOT"; };
+ 212019C041EE17C23460CE02 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
+ 223C6D257BB45525A7C2D495 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_audio_plugin_client_Standalone.cpp"; path = "../../JuceLibraryCode/juce_audio_plugin_client_Standalone.cpp"; sourceTree = "SOURCE_ROOT"; };
+ 2A2D7663F8BC39E97FF490E3 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_core"; path = "../../../../../modules/juce_core"; sourceTree = "SOURCE_ROOT"; };
+ 2C4476A46744766A478A74B6 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = IAAEffectProcessor.cpp; path = ../../Source/IAAEffectProcessor.cpp; sourceTree = "SOURCE_ROOT"; };
+ 3158E31C9E0DBE333E275FB1 = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = InterAppAudioEffect.entitlements; path = InterAppAudioEffect.entitlements; sourceTree = "SOURCE_ROOT"; };
+ 32E0486AA56B56AD10D18A56 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_audio_utils.mm"; path = "../../JuceLibraryCode/juce_audio_utils.mm"; sourceTree = "SOURCE_ROOT"; };
+ 36A796A962C81B44E9233775 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_events.mm"; path = "../../JuceLibraryCode/juce_events.mm"; sourceTree = "SOURCE_ROOT"; };
+ 41CB50701EE5BFDCE1F89BBA = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 4B55841B06C897F72BC2F8CE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_core.mm"; path = "../../JuceLibraryCode/juce_core.mm"; sourceTree = "SOURCE_ROOT"; };
+ 4D36B733C9B175319B696E33 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AppConfig.h; path = ../../JuceLibraryCode/AppConfig.h; sourceTree = "SOURCE_ROOT"; };
+ 50724579E5DD043CD53B0C95 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_plugin_client"; path = "../../../../../modules/juce_audio_plugin_client"; sourceTree = "SOURCE_ROOT"; };
+ 51A5B253018FC02A6AFB7416 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_processors"; path = "../../../../../modules/juce_audio_processors"; sourceTree = "SOURCE_ROOT"; };
+ 53BB9950BAA9E837613ED83B = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
+ 54EEC3679EBFF5E6C7B580F1 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_data_structures"; path = "../../../../../modules/juce_data_structures"; sourceTree = "SOURCE_ROOT"; };
+ 59469A0541A1B91E7968B8FC = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_gui_extra"; path = "../../../../../modules/juce_gui_extra"; sourceTree = "SOURCE_ROOT"; };
+ 67BBA32BE9EE1CAF8A105F6A = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
+ 6E90633D52FCA2BC0B99F9F2 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_formats"; path = "../../../../../modules/juce_audio_formats"; sourceTree = "SOURCE_ROOT"; };
+ 746E2820600C97BD2E760C34 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IAAEffectEditor.h; path = ../../Source/IAAEffectEditor.h; sourceTree = "SOURCE_ROOT"; };
+ 78F41A05666E3B38C9FDE9D3 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_events"; path = "../../../../../modules/juce_events"; sourceTree = "SOURCE_ROOT"; };
+ 7B37ABD2C5B9FF909250C8DE = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-Standalone_Plugin.plist"; path = "Info-Standalone_Plugin.plist"; sourceTree = "SOURCE_ROOT"; };
+ 7C1F5AA6FE8016951F45F916 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_audio_devices.mm"; path = "../../JuceLibraryCode/juce_audio_devices.mm"; sourceTree = "SOURCE_ROOT"; };
+ 82F310E23852E0C002F5A2D1 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ 9C809DD426D6B660393427D4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SimpleMeter.h; path = ../../Source/SimpleMeter.h; sourceTree = "SOURCE_ROOT"; };
+ A3BDBD773FBCCD4F9440D174 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_gui_extra.mm"; path = "../../JuceLibraryCode/juce_gui_extra.mm"; sourceTree = "SOURCE_ROOT"; };
+ AD9B42ED650058295A747510 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = System/Library/Frameworks/CoreMIDI.framework; sourceTree = SDKROOT; };
+ B3D01A391D4DF11709AE5688 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JuceHeader.h; path = ../../JuceLibraryCode/JuceHeader.h; sourceTree = "SOURCE_ROOT"; };
+ B69C94CF64688C5270D8122C = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+ C1507624A4C7CFDCE375CEB6 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_graphics"; path = "../../../../../modules/juce_graphics"; sourceTree = "SOURCE_ROOT"; };
+ C21DF85AC43B32B0E0735A3E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IAAEffectProcessor.h; path = ../../Source/IAAEffectProcessor.h; sourceTree = "SOURCE_ROOT"; };
+ C293562C310CB0B3259811F0 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudioKit.framework; path = System/Library/Frameworks/CoreAudioKit.framework; sourceTree = SDKROOT; };
+ C43FC3A63342AA4CDE8F0906 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreImage.framework; path = System/Library/Frameworks/CoreImage.framework; sourceTree = SDKROOT; };
+ C450D63325E2C29C72B6606C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_data_structures.mm"; path = "../../JuceLibraryCode/juce_data_structures.mm"; sourceTree = "SOURCE_ROOT"; };
+ C6F57BB192F1BC9BE7D82F99 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_devices"; path = "../../../../../modules/juce_audio_devices"; sourceTree = "SOURCE_ROOT"; };
+ CB7EB47782C231D8D6CD52FD = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_basics"; path = "../../../../../modules/juce_audio_basics"; sourceTree = "SOURCE_ROOT"; };
+ CDCF152172E34769B268ECDA = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_audio_plugin_client_VST_utils.mm"; path = "../../JuceLibraryCode/juce_audio_plugin_client_VST_utils.mm"; sourceTree = "SOURCE_ROOT"; };
+ E43030B35C6CB127DC67FEE7 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
+ E4431E84242848EF9D250FC7 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ E9D6BA12BDD1947BDDAE08F7 = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InterAppAudioEffect.app; sourceTree = "BUILT_PRODUCTS_DIR"; };
+ 873711620EC157BCCFFF80B1 = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libInterAppAudioEffect.a; sourceTree = "BUILT_PRODUCTS_DIR"; };
+ D9C8C1E2D3F27800C6E774D7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_audio_plugin_client_utils.cpp"; path = "../../JuceLibraryCode/juce_audio_plugin_client_utils.cpp"; sourceTree = "SOURCE_ROOT"; };
+ E5A657DE5A5B1516B3E35FA8 = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = InterAppAudioEffect/Images.xcassets; sourceTree = "SOURCE_ROOT"; };
+ EBA214D367A10FDDC99E8922 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_audio_utils"; path = "../../../../../modules/juce_audio_utils"; sourceTree = "SOURCE_ROOT"; };
+ F07FA71EC2B5FCA584FAA10B = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
+ FEBA6F6C0A62E2749D6ACC88 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_gui_basics"; path = "../../../../../modules/juce_gui_basics"; sourceTree = "SOURCE_ROOT"; };
+ 9D54126CE5CE65025DE4742F = {isa = PBXGroup; children = (
+ C21DF85AC43B32B0E0735A3E,
+ 2C4476A46744766A478A74B6,
+ 746E2820600C97BD2E760C34,
+ 9C809DD426D6B660393427D4, ); name = Source; sourceTree = ""; };
+ EB371D6195C6398C6F1946EF = {isa = PBXGroup; children = (
+ 9D54126CE5CE65025DE4742F, ); name = InterAppAudioEffect; sourceTree = ""; };
+ 3CDCF2D2F9AA23710946CF21 = {isa = PBXGroup; children = (
+ CB7EB47782C231D8D6CD52FD,
+ C6F57BB192F1BC9BE7D82F99,
+ 6E90633D52FCA2BC0B99F9F2,
+ 50724579E5DD043CD53B0C95,
+ 51A5B253018FC02A6AFB7416,
+ EBA214D367A10FDDC99E8922,
+ 2A2D7663F8BC39E97FF490E3,
+ 54EEC3679EBFF5E6C7B580F1,
+ 78F41A05666E3B38C9FDE9D3,
+ C1507624A4C7CFDCE375CEB6,
+ FEBA6F6C0A62E2749D6ACC88,
+ 59469A0541A1B91E7968B8FC, ); name = "Juce Modules"; sourceTree = ""; };
+ C560791DA1D2E0CA6690BC9E = {isa = PBXGroup; children = (
+ 4D36B733C9B175319B696E33,
+ 131A768FD64EB99097B0B190,
+ 7C1F5AA6FE8016951F45F916,
+ 0EB1F323BA52207C49A27479,
+ 223C6D257BB45525A7C2D495,
+ D9C8C1E2D3F27800C6E774D7,
+ CDCF152172E34769B268ECDA,
+ 02ABCEB5E369CDE6AEA817B3,
+ 32E0486AA56B56AD10D18A56,
+ 4B55841B06C897F72BC2F8CE,
+ C450D63325E2C29C72B6606C,
+ 36A796A962C81B44E9233775,
+ 10EEE1E56B53B7A31753365C,
+ 1F042A6F2A0986F23B7097FC,
+ A3BDBD773FBCCD4F9440D174,
+ B3D01A391D4DF11709AE5688, ); name = "Juce Library Code"; sourceTree = ""; };
+ E1CFC4C60E9EC5DBE60DB32F = {isa = PBXGroup; children = (
+ 7B37ABD2C5B9FF909250C8DE,
+ E5A657DE5A5B1516B3E35FA8, ); name = Resources; sourceTree = ""; };
+ BF7815807DD5B5FAF4BC3669 = {isa = PBXGroup; children = (
+ 67BBA32BE9EE1CAF8A105F6A,
+ E43030B35C6CB127DC67FEE7,
+ 53BB9950BAA9E837613ED83B,
+ 212019C041EE17C23460CE02,
+ C293562C310CB0B3259811F0,
+ E4431E84242848EF9D250FC7,
+ C43FC3A63342AA4CDE8F0906,
+ AD9B42ED650058295A747510,
+ F07FA71EC2B5FCA584FAA10B,
+ 41CB50701EE5BFDCE1F89BBA,
+ B69C94CF64688C5270D8122C,
+ 82F310E23852E0C002F5A2D1, ); name = Frameworks; sourceTree = ""; };
+ 196E6AA022E8A0902AB15281 = {isa = PBXGroup; children = (
+ E9D6BA12BDD1947BDDAE08F7,
+ 873711620EC157BCCFFF80B1, ); name = Products; sourceTree = ""; };
+ EC01685A042C62251C5AF093 = {isa = PBXGroup; children = (
+ 3158E31C9E0DBE333E275FB1,
+ EB371D6195C6398C6F1946EF,
+ 3CDCF2D2F9AA23710946CF21,
+ C560791DA1D2E0CA6690BC9E,
+ E1CFC4C60E9EC5DBE60DB32F,
+ BF7815807DD5B5FAF4BC3669,
+ 196E6AA022E8A0902AB15281, ); name = Source; sourceTree = ""; };
+ 22DBBF091193373BEA063A5B = {isa = XCBuildConfiguration; buildSettings = { }; name = Debug; };
+ 54D411166886E8F3BBC0E25F = {isa = XCBuildConfiguration; buildSettings = { }; name = Release; };
+ 8DA1E39A676F877EB549B8CA = {isa = XCBuildConfiguration; buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ CLANG_LINK_OBJC_RUNTIME = NO;
+ CODE_SIGN_ENTITLEMENTS = "InterAppAudioEffect.entitlements";
+ COMBINE_HIDPI_IMAGES = YES;
+ CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "_DEBUG=1",
+ "DEBUG=1",
+ "JUCER_XCODE_IPHONE_5BC26AE3=1",
+ "JUCE_APP_VERSION=1.0.0",
+ "JUCE_APP_VERSION_HEX=0x10000",
+ "JucePlugin_Build_VST=0",
+ "JucePlugin_Build_VST3=0",
+ "JucePlugin_Build_AU=0",
+ "JucePlugin_Build_AUv3=0",
+ "JucePlugin_Build_RTAS=0",
+ "JucePlugin_Build_AAX=0",
+ "JucePlugin_Build_Standalone=1", );
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../../modules", "$(inherited)");
+ INFOPLIST_FILE = Info-Standalone_Plugin.plist;
+ OTHER_CPLUSPLUSFLAGS = "-Wall -Wshadow -Wno-missing-field-initializers -Wshadow -Wshorten-64-to-32 -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare -Wint-conversion -Woverloaded-virtual -Wreorder -Wconstant-conversion -Wsign-conversion";
+ OTHER_LDFLAGS = "-lInterAppAudioEffect";
+ PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.InterAppAudioEffect; }; name = Debug; };
+ 07EA55A19B872E1F49C62539 = {isa = XCBuildConfiguration; buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ CLANG_LINK_OBJC_RUNTIME = NO;
+ CODE_SIGN_ENTITLEMENTS = "InterAppAudioEffect.entitlements";
+ COMBINE_HIDPI_IMAGES = YES;
+ CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)";
+ DEAD_CODE_STRIPPING = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "_NDEBUG=1",
+ "NDEBUG=1",
+ "JUCER_XCODE_IPHONE_5BC26AE3=1",
+ "JUCE_APP_VERSION=1.0.0",
+ "JUCE_APP_VERSION_HEX=0x10000",
+ "JucePlugin_Build_VST=0",
+ "JucePlugin_Build_VST3=0",
+ "JucePlugin_Build_AU=0",
+ "JucePlugin_Build_AUv3=0",
+ "JucePlugin_Build_RTAS=0",
+ "JucePlugin_Build_AAX=0",
+ "JucePlugin_Build_Standalone=1", );
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../../modules", "$(inherited)");
+ INFOPLIST_FILE = Info-Standalone_Plugin.plist;
+ OTHER_CPLUSPLUSFLAGS = "-Wall -Wshadow -Wno-missing-field-initializers -Wshadow -Wshorten-64-to-32 -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare -Wint-conversion -Woverloaded-virtual -Wreorder -Wconstant-conversion -Wsign-conversion";
+ OTHER_LDFLAGS = "-lInterAppAudioEffect";
+ PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.InterAppAudioEffect; }; name = Release; };
+ E6FA0B75AC78727D8A3F1888 = {isa = XCBuildConfiguration; buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ CLANG_LINK_OBJC_RUNTIME = NO;
+ COMBINE_HIDPI_IMAGES = YES;
+ CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "_DEBUG=1",
+ "DEBUG=1",
+ "JUCER_XCODE_IPHONE_5BC26AE3=1",
+ "JUCE_APP_VERSION=1.0.0",
+ "JUCE_APP_VERSION_HEX=0x10000",
+ "JucePlugin_Build_VST=0",
+ "JucePlugin_Build_VST3=0",
+ "JucePlugin_Build_AU=0",
+ "JucePlugin_Build_AUv3=0",
+ "JucePlugin_Build_RTAS=0",
+ "JucePlugin_Build_AAX=0",
+ "JucePlugin_Build_Standalone=1",
+ "JUCE_SHARED_CODE=1", );
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../../modules", "$(inherited)");
+ INSTALL_PATH = "@executable_path/Frameworks";
+ OTHER_CPLUSPLUSFLAGS = "-Wall -Wshadow -Wno-missing-field-initializers -Wshadow -Wshorten-64-to-32 -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare -Wint-conversion -Woverloaded-virtual -Wreorder -Wconstant-conversion -Wsign-conversion";
+ PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.InterAppAudioEffect; }; name = Debug; };
+ 665044AFDC3F0D4E11643857 = {isa = XCBuildConfiguration; buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ CLANG_LINK_OBJC_RUNTIME = NO;
+ COMBINE_HIDPI_IMAGES = YES;
+ CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)";
+ DEAD_CODE_STRIPPING = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "_NDEBUG=1",
+ "NDEBUG=1",
+ "JUCER_XCODE_IPHONE_5BC26AE3=1",
+ "JUCE_APP_VERSION=1.0.0",
+ "JUCE_APP_VERSION_HEX=0x10000",
+ "JucePlugin_Build_VST=0",
+ "JucePlugin_Build_VST3=0",
+ "JucePlugin_Build_AU=0",
+ "JucePlugin_Build_AUv3=0",
+ "JucePlugin_Build_RTAS=0",
+ "JucePlugin_Build_AAX=0",
+ "JucePlugin_Build_Standalone=1",
+ "JUCE_SHARED_CODE=1", );
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../../modules", "$(inherited)");
+ INSTALL_PATH = "@executable_path/Frameworks";
+ OTHER_CPLUSPLUSFLAGS = "-Wall -Wshadow -Wno-missing-field-initializers -Wshadow -Wshorten-64-to-32 -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare -Wint-conversion -Woverloaded-virtual -Wreorder -Wconstant-conversion -Wsign-conversion";
+ PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.InterAppAudioEffect; }; name = Release; };
+ 4650CE5DEC4B4B8ED96435A4 = {isa = XCBuildConfiguration; buildSettings = {
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf";
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = c11;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_MISSING_PARENTHESES = YES;
+ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+ GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = "InterAppAudioEffect";
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ WARNING_CFLAGS = -Wreorder;
+ ZERO_LINK = NO; }; name = Debug; };
+ C2BB86E774E1461CAF0D87DD = {isa = XCBuildConfiguration; buildSettings = {
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf";
+ GCC_C_LANGUAGE_STANDARD = c11;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_MISSING_PARENTHESES = YES;
+ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+ GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+ PRODUCT_NAME = "InterAppAudioEffect";
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ WARNING_CFLAGS = -Wreorder;
+ ZERO_LINK = NO; }; name = Release; };
+ 2C494CD599EC256FDB6CCE00 = {isa = PBXTargetDependency; target = 51FB6E6A2D0998D38E999826; };
+ CECAF531D33909A1FB3ABE80 = {isa = PBXTargetDependency; target = A3401CC1AC6C5B89EFBAEF01; };
+ 016ACE6B9EC6F47020502F4F = {isa = XCConfigurationList; buildConfigurations = (
+ 4650CE5DEC4B4B8ED96435A4,
+ C2BB86E774E1461CAF0D87DD, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; };
+ D10DBCC16019A5712E897068 = {isa = XCConfigurationList; buildConfigurations = (
+ 22DBBF091193373BEA063A5B,
+ 54D411166886E8F3BBC0E25F, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; };
+ 03BD5476C606A5BA65CD4FDF = {isa = PBXAggregateTarget; buildConfigurationList = D10DBCC16019A5712E897068; buildPhases = ( ); buildRules = ( ); dependencies = (
+ 2C494CD599EC256FDB6CCE00,
+ CECAF531D33909A1FB3ABE80, ); name = "InterAppAudioEffect - All"; productName = InterAppAudioEffect; };
+ 10A00DA553BF0C30212421D2 = {isa = XCConfigurationList; buildConfigurations = (
+ 8DA1E39A676F877EB549B8CA,
+ 07EA55A19B872E1F49C62539, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; };
+ C8358163192CC594074B35EA = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (
+ 4EC4A8C3AF328E40626CBAE7, ); runOnlyForDeploymentPostprocessing = 0; };
+ AC1841BDF7829D1EA1146F56 = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (
+ A49F3F55F083BAD332CA4324, ); runOnlyForDeploymentPostprocessing = 0; };
+ A0069210E3FD182F29030BDB = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = (
+ 61D6F1506B76AFBA614F491E,
+ 03A7A8C261C0A1B578F219EF,
+ E9FB1841DE3518ADBD86293C,
+ 7B71DA92A48B9D67BA68C69E,
+ BC8485848043996AFA210EF9,
+ 7FF11BF2317D79501E0632DB,
+ DD2143886468728A97F9586E,
+ EE6B5FC34FB47B41336EA293,
+ B2E5CB24DBACF25E2CBAC9A1,
+ 6FAEC70FAE3DBC629160F86C,
+ DFF48C0819F2191B154569A9,
+ 9BB46E700B9A4617B4CFDC24, ); runOnlyForDeploymentPostprocessing = 0; };
+ 51FB6E6A2D0998D38E999826 = {isa = PBXNativeTarget; buildConfigurationList = 10A00DA553BF0C30212421D2; buildPhases = (
+ C8358163192CC594074B35EA,
+ AC1841BDF7829D1EA1146F56,
+ A0069210E3FD182F29030BDB, ); buildRules = ( ); dependencies = (
+ CECAF531D33909A1FB3ABE80, ); name = "InterAppAudioEffect - Standalone Plugin"; productName = InterAppAudioEffect; productReference = E9D6BA12BDD1947BDDAE08F7; productType = "com.apple.product-type.application"; };
+ AA6F190D4FECB06C7A7A0658 = {isa = XCConfigurationList; buildConfigurations = (
+ E6FA0B75AC78727D8A3F1888,
+ 665044AFDC3F0D4E11643857, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; };
+ 177DC2A7A303F23EDDE5183A = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (
+ 9A7D9D7490AF3D82BA8D9686,
+ 40833B424B5E9EC84C09EE40,
+ 7ACC830E1DDF0F171C890B2B,
+ 78BD211C42E345A8048DEDD5,
+ B2BE378326805DEBB71B3016,
+ BCA424EEB2F9F33372CA4909,
+ 246490CF3D197E69B1F7FCC8,
+ 873E620B819DC84C953EC518,
+ 40E6F5A9B432DEB7689AF7D0,
+ 78412E76B9D1D75907390309,
+ E3DD6181D2A4E2703637E1EF,
+ E8410AF631A96357D2807C3A,
+ DCEE24917F78097ACF14EAD0,
+ CA28F22C95EBC20CB37612FF, ); runOnlyForDeploymentPostprocessing = 0; };
+ A3401CC1AC6C5B89EFBAEF01 = {isa = PBXNativeTarget; buildConfigurationList = AA6F190D4FECB06C7A7A0658; buildPhases = (
+ 177DC2A7A303F23EDDE5183A, ); buildRules = ( ); dependencies = ( ); name = "InterAppAudioEffect - Shared Code"; productName = InterAppAudioEffect; productReference = 873711620EC157BCCFFF80B1; productType = "com.apple.product-type.library.static"; };
+ DF3D0C1B88ADC0274AE6BD73 = {isa = PBXProject; buildConfigurationList = 016ACE6B9EC6F47020502F4F; attributes = { LastUpgradeCheck = 0820; TargetAttributes = { 03BD5476C606A5BA65CD4FDF = { SystemCapabilities = {com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; };51FB6E6A2D0998D38E999826 = { SystemCapabilities = {com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 1; }; com.apple.Sandbox = { enabled = 0; }; }; };A3401CC1AC6C5B89EFBAEF01 = { SystemCapabilities = {com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; }; }; }; compatibilityVersion = "Xcode 3.2"; hasScannedForEncodings = 0; mainGroup = EC01685A042C62251C5AF093; projectDirPath = ""; projectRoot = ""; targets = (03BD5476C606A5BA65CD4FDF, 51FB6E6A2D0998D38E999826, A3401CC1AC6C5B89EFBAEF01); };
+ };
+ rootObject = DF3D0C1B88ADC0274AE6BD73;
+}
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-landscape-1x.png b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-landscape-1x.png
new file mode 100644
index 0000000000..b8a0025f63
Binary files /dev/null and b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-landscape-1x.png differ
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-landscape-2x.png b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-landscape-2x.png
new file mode 100644
index 0000000000..817cdf8057
Binary files /dev/null and b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-landscape-2x.png differ
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-portrait-1x.png b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-portrait-1x.png
new file mode 100644
index 0000000000..f3685597a1
Binary files /dev/null and b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-portrait-1x.png differ
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-portrait-2x.png b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-portrait-2x.png
new file mode 100644
index 0000000000..5447ddfc5b
Binary files /dev/null and b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-ipad-portrait-2x.png differ
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-iphone-2x.png b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-iphone-2x.png
new file mode 100644
index 0000000000..efe9e82a32
Binary files /dev/null and b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-iphone-2x.png differ
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-iphone-retina4.png b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-iphone-retina4.png
new file mode 100644
index 0000000000..d0e3261440
Binary files /dev/null and b/examples/PlugInSamples/InterAppAudioEffect/Builds/iOS/InterAppAudioEffect/Images.xcassets/LaunchImage.launchimage/LaunchImage-iphone-retina4.png differ
diff --git a/examples/PlugInSamples/InterAppAudioEffect/InterAppAudioEffect.jucer b/examples/PlugInSamples/InterAppAudioEffect/InterAppAudioEffect.jucer
new file mode 100644
index 0000000000..ccd185b9d1
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/InterAppAudioEffect.jucer
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/AppConfig.h b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/AppConfig.h
new file mode 100644
index 0000000000..f6a6a0a543
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/AppConfig.h
@@ -0,0 +1,363 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+ There's a section below where you can add your own custom code safely, and the
+ Projucer will preserve the contents of that block, but the best way to change
+ any of these definitions is by using the Projucer's project settings.
+
+ Any commented-out settings will assume their default values.
+
+*/
+
+#pragma once
+
+//==============================================================================
+// [BEGIN_USER_CODE_SECTION]
+
+// (You can add your own code in this section, and the Projucer will not overwrite it)
+
+// [END_USER_CODE_SECTION]
+
+//==============================================================================
+#define JUCE_MODULE_AVAILABLE_juce_audio_basics 1
+#define JUCE_MODULE_AVAILABLE_juce_audio_devices 1
+#define JUCE_MODULE_AVAILABLE_juce_audio_formats 1
+#define JUCE_MODULE_AVAILABLE_juce_audio_plugin_client 1
+#define JUCE_MODULE_AVAILABLE_juce_audio_processors 1
+#define JUCE_MODULE_AVAILABLE_juce_audio_utils 1
+#define JUCE_MODULE_AVAILABLE_juce_core 1
+#define JUCE_MODULE_AVAILABLE_juce_data_structures 1
+#define JUCE_MODULE_AVAILABLE_juce_events 1
+#define JUCE_MODULE_AVAILABLE_juce_graphics 1
+#define JUCE_MODULE_AVAILABLE_juce_gui_basics 1
+#define JUCE_MODULE_AVAILABLE_juce_gui_extra 1
+
+//==============================================================================
+#ifndef JUCE_STANDALONE_APPLICATION
+ #if defined(JucePlugin_Name) && defined(JucePlugin_Build_Standalone)
+ #define JUCE_STANDALONE_APPLICATION JucePlugin_Build_Standalone
+ #else
+ #define JUCE_STANDALONE_APPLICATION 0
+ #endif
+#endif
+
+#define JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED 1
+
+//==============================================================================
+// juce_audio_devices flags:
+
+#ifndef JUCE_ASIO
+ //#define JUCE_ASIO
+#endif
+
+#ifndef JUCE_WASAPI
+ //#define JUCE_WASAPI
+#endif
+
+#ifndef JUCE_WASAPI_EXCLUSIVE
+ //#define JUCE_WASAPI_EXCLUSIVE
+#endif
+
+#ifndef JUCE_DIRECTSOUND
+ //#define JUCE_DIRECTSOUND
+#endif
+
+#ifndef JUCE_ALSA
+ //#define JUCE_ALSA
+#endif
+
+#ifndef JUCE_JACK
+ //#define JUCE_JACK
+#endif
+
+#ifndef JUCE_USE_ANDROID_OPENSLES
+ //#define JUCE_USE_ANDROID_OPENSLES
+#endif
+
+#ifndef JUCE_USE_WINRT_MIDI
+ //#define JUCE_USE_WINRT_MIDI
+#endif
+
+//==============================================================================
+// juce_audio_formats flags:
+
+#ifndef JUCE_USE_FLAC
+ //#define JUCE_USE_FLAC
+#endif
+
+#ifndef JUCE_USE_OGGVORBIS
+ //#define JUCE_USE_OGGVORBIS
+#endif
+
+#ifndef JUCE_USE_MP3AUDIOFORMAT
+ //#define JUCE_USE_MP3AUDIOFORMAT
+#endif
+
+#ifndef JUCE_USE_LAME_AUDIO_FORMAT
+ //#define JUCE_USE_LAME_AUDIO_FORMAT
+#endif
+
+#ifndef JUCE_USE_WINDOWS_MEDIA_FORMAT
+ //#define JUCE_USE_WINDOWS_MEDIA_FORMAT
+#endif
+
+//==============================================================================
+// juce_audio_plugin_client flags:
+
+#ifndef JUCE_FORCE_USE_LEGACY_PARAM_IDS
+ //#define JUCE_FORCE_USE_LEGACY_PARAM_IDS
+#endif
+
+#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
+ //#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
+#endif
+
+//==============================================================================
+// juce_audio_processors flags:
+
+#ifndef JUCE_PLUGINHOST_VST
+ //#define JUCE_PLUGINHOST_VST
+#endif
+
+#ifndef JUCE_PLUGINHOST_VST3
+ //#define JUCE_PLUGINHOST_VST3
+#endif
+
+#ifndef JUCE_PLUGINHOST_AU
+ //#define JUCE_PLUGINHOST_AU
+#endif
+
+//==============================================================================
+// juce_audio_utils flags:
+
+#ifndef JUCE_USE_CDREADER
+ //#define JUCE_USE_CDREADER
+#endif
+
+#ifndef JUCE_USE_CDBURNER
+ //#define JUCE_USE_CDBURNER
+#endif
+
+//==============================================================================
+// juce_core flags:
+
+#ifndef JUCE_FORCE_DEBUG
+ //#define JUCE_FORCE_DEBUG
+#endif
+
+#ifndef JUCE_LOG_ASSERTIONS
+ //#define JUCE_LOG_ASSERTIONS
+#endif
+
+#ifndef JUCE_CHECK_MEMORY_LEAKS
+ //#define JUCE_CHECK_MEMORY_LEAKS
+#endif
+
+#ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
+ //#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
+#endif
+
+#ifndef JUCE_INCLUDE_ZLIB_CODE
+ //#define JUCE_INCLUDE_ZLIB_CODE
+#endif
+
+#ifndef JUCE_USE_CURL
+ //#define JUCE_USE_CURL
+#endif
+
+#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS
+ //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS
+#endif
+
+#ifndef JUCE_ALLOW_STATIC_NULL_VARIABLES
+ //#define JUCE_ALLOW_STATIC_NULL_VARIABLES
+#endif
+
+//==============================================================================
+// juce_events flags:
+
+#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK
+ //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK
+#endif
+
+//==============================================================================
+// juce_graphics flags:
+
+#ifndef JUCE_USE_COREIMAGE_LOADER
+ //#define JUCE_USE_COREIMAGE_LOADER
+#endif
+
+#ifndef JUCE_USE_DIRECTWRITE
+ //#define JUCE_USE_DIRECTWRITE
+#endif
+
+//==============================================================================
+// juce_gui_basics flags:
+
+#ifndef JUCE_ENABLE_REPAINT_DEBUGGING
+ //#define JUCE_ENABLE_REPAINT_DEBUGGING
+#endif
+
+#ifndef JUCE_USE_XSHM
+ //#define JUCE_USE_XSHM
+#endif
+
+#ifndef JUCE_USE_XRENDER
+ //#define JUCE_USE_XRENDER
+#endif
+
+#ifndef JUCE_USE_XCURSOR
+ //#define JUCE_USE_XCURSOR
+#endif
+
+//==============================================================================
+// juce_gui_extra flags:
+
+#ifndef JUCE_WEB_BROWSER
+ //#define JUCE_WEB_BROWSER
+#endif
+
+#ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR
+ //#define JUCE_ENABLE_LIVE_CONSTANT_EDITOR
+#endif
+
+//==============================================================================
+// Audio plugin settings..
+
+#ifndef JucePlugin_Build_VST
+ #define JucePlugin_Build_VST 0
+#endif
+#ifndef JucePlugin_Build_VST3
+ #define JucePlugin_Build_VST3 0
+#endif
+#ifndef JucePlugin_Build_AU
+ #define JucePlugin_Build_AU 0
+#endif
+#ifndef JucePlugin_Build_AUv3
+ #define JucePlugin_Build_AUv3 0
+#endif
+#ifndef JucePlugin_Build_RTAS
+ #define JucePlugin_Build_RTAS 0
+#endif
+#ifndef JucePlugin_Build_AAX
+ #define JucePlugin_Build_AAX 0
+#endif
+#ifndef JucePlugin_Build_STANDALONE
+ #define JucePlugin_Build_STANDALONE 1
+#endif
+#ifndef JucePlugin_Enable_IAA
+ #define JucePlugin_Enable_IAA 1
+#endif
+#ifndef JucePlugin_Name
+ #define JucePlugin_Name "InterAppAudioEffect"
+#endif
+#ifndef JucePlugin_Desc
+ #define JucePlugin_Desc "InterAppAudioEffect"
+#endif
+#ifndef JucePlugin_Manufacturer
+ #define JucePlugin_Manufacturer "ROLI Ltd."
+#endif
+#ifndef JucePlugin_ManufacturerWebsite
+ #define JucePlugin_ManufacturerWebsite ""
+#endif
+#ifndef JucePlugin_ManufacturerEmail
+ #define JucePlugin_ManufacturerEmail ""
+#endif
+#ifndef JucePlugin_ManufacturerCode
+ #define JucePlugin_ManufacturerCode 0x524f4c49 // 'ROLI'
+#endif
+#ifndef JucePlugin_PluginCode
+ #define JucePlugin_PluginCode 0x49414145 // 'IAAE'
+#endif
+#ifndef JucePlugin_IsSynth
+ #define JucePlugin_IsSynth 0
+#endif
+#ifndef JucePlugin_WantsMidiInput
+ #define JucePlugin_WantsMidiInput 0
+#endif
+#ifndef JucePlugin_ProducesMidiOutput
+ #define JucePlugin_ProducesMidiOutput 0
+#endif
+#ifndef JucePlugin_IsMidiEffect
+ #define JucePlugin_IsMidiEffect 0
+#endif
+#ifndef JucePlugin_EditorRequiresKeyboardFocus
+ #define JucePlugin_EditorRequiresKeyboardFocus 0
+#endif
+#ifndef JucePlugin_Version
+ #define JucePlugin_Version 1.0.0
+#endif
+#ifndef JucePlugin_VersionCode
+ #define JucePlugin_VersionCode 0x10000
+#endif
+#ifndef JucePlugin_VersionString
+ #define JucePlugin_VersionString "1.0.0"
+#endif
+#ifndef JucePlugin_VSTUniqueID
+ #define JucePlugin_VSTUniqueID JucePlugin_PluginCode
+#endif
+#ifndef JucePlugin_VSTCategory
+ #define JucePlugin_VSTCategory kPlugCategEffect
+#endif
+#ifndef JucePlugin_AUMainType
+ #define JucePlugin_AUMainType kAudioUnitType_Effect
+#endif
+#ifndef JucePlugin_AUSubType
+ #define JucePlugin_AUSubType JucePlugin_PluginCode
+#endif
+#ifndef JucePlugin_AUExportPrefix
+ #define JucePlugin_AUExportPrefix InterAppAudioEffectAU
+#endif
+#ifndef JucePlugin_AUExportPrefixQuoted
+ #define JucePlugin_AUExportPrefixQuoted "InterAppAudioEffectAU"
+#endif
+#ifndef JucePlugin_AUManufacturerCode
+ #define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode
+#endif
+#ifndef JucePlugin_CFBundleIdentifier
+ #define JucePlugin_CFBundleIdentifier com.yourcompany.InterAppAudioEffect
+#endif
+#ifndef JucePlugin_RTASCategory
+ #define JucePlugin_RTASCategory ePlugInCategory_None
+#endif
+#ifndef JucePlugin_RTASManufacturerCode
+ #define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode
+#endif
+#ifndef JucePlugin_RTASProductId
+ #define JucePlugin_RTASProductId JucePlugin_PluginCode
+#endif
+#ifndef JucePlugin_RTASDisableBypass
+ #define JucePlugin_RTASDisableBypass 0
+#endif
+#ifndef JucePlugin_RTASDisableMultiMono
+ #define JucePlugin_RTASDisableMultiMono 0
+#endif
+#ifndef JucePlugin_AAXIdentifier
+ #define JucePlugin_AAXIdentifier com.yourcompany.InterAppAudioEffect
+#endif
+#ifndef JucePlugin_AAXManufacturerCode
+ #define JucePlugin_AAXManufacturerCode JucePlugin_ManufacturerCode
+#endif
+#ifndef JucePlugin_AAXProductId
+ #define JucePlugin_AAXProductId JucePlugin_PluginCode
+#endif
+#ifndef JucePlugin_AAXCategory
+ #define JucePlugin_AAXCategory AAX_ePlugInCategory_Dynamics
+#endif
+#ifndef JucePlugin_AAXDisableBypass
+ #define JucePlugin_AAXDisableBypass 0
+#endif
+#ifndef JucePlugin_AAXDisableMultiMono
+ #define JucePlugin_AAXDisableMultiMono 0
+#endif
+#ifndef JucePlugin_IAAType
+ #define JucePlugin_IAAType 0x61757278 // 'aurx'
+#endif
+#ifndef JucePlugin_IAASubType
+ #define JucePlugin_IAASubType JucePlugin_PluginCode
+#endif
+#ifndef JucePlugin_IAAName
+ #define JucePlugin_IAAName "ROLI Ltd.: InterAppAudioEffect"
+#endif
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/JuceHeader.h b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/JuceHeader.h
new file mode 100644
index 0000000000..7dd9559672
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/JuceHeader.h
@@ -0,0 +1,44 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+ This is the header file that your files should include in order to get all the
+ JUCE library headers. You should avoid including the JUCE headers directly in
+ your own source files, because that wouldn't pick up the correct configuration
+ options for your app.
+
+*/
+
+#pragma once
+
+#include "AppConfig.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#if ! DONT_SET_USING_JUCE_NAMESPACE
+ // If your code uses a lot of JUCE classes, then this will obviously save you
+ // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE.
+ using namespace juce;
+#endif
+
+#if ! JUCE_DONT_DECLARE_PROJECTINFO
+namespace ProjectInfo
+{
+ const char* const projectName = "InterAppAudioEffect";
+ const char* const versionString = "1.0.0";
+ const int versionNumber = 0x10000;
+}
+#endif
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/ReadMe.txt b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/ReadMe.txt
new file mode 100644
index 0000000000..091a5aa6eb
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/ReadMe.txt
@@ -0,0 +1,12 @@
+
+ Important Note!!
+ ================
+
+The purpose of this folder is to contain files that are auto-generated by the Projucer,
+and ALL files in this folder will be mercilessly DELETED and completely re-written whenever
+the Projucer saves your project.
+
+Therefore, it's a bad idea to make any manual changes to the files in here, or to
+put any of your own files in here if you don't want to lose them. (Of course you may choose
+to add the folder's contents to your version-control system so that you can re-merge your own
+modifications after the Projucer has saved its changes).
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_basics.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_basics.cpp
new file mode 100644
index 0000000000..418694873c
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_basics.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_basics.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_basics.mm
new file mode 100644
index 0000000000..e0e6c577cc
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_basics.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_devices.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_devices.cpp
new file mode 100644
index 0000000000..fb5c2219d7
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_devices.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_devices.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_devices.mm
new file mode 100644
index 0000000000..e58b67ea49
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_devices.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_formats.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_formats.cpp
new file mode 100644
index 0000000000..a3c61170eb
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_formats.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_formats.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_formats.mm
new file mode 100644
index 0000000000..f325b8fb67
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_formats.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AAX.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AAX.cpp
new file mode 100644
index 0000000000..c599b8759f
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AAX.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AAX.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AAX.mm
new file mode 100644
index 0000000000..d4b8c31117
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AAX.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AU_1.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AU_1.mm
new file mode 100644
index 0000000000..a4fdf7f366
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AU_1.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AU_2.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AU_2.mm
new file mode 100644
index 0000000000..175b30047f
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AU_2.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AUv3.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AUv3.mm
new file mode 100644
index 0000000000..0ac2b2f599
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_AUv3.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_1.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_1.cpp
new file mode 100644
index 0000000000..29d48f3faa
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_1.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_2.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_2.cpp
new file mode 100644
index 0000000000..2da08c6dc3
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_2.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_3.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_3.cpp
new file mode 100644
index 0000000000..72a8426cbe
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_3.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_4.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_4.cpp
new file mode 100644
index 0000000000..6064f99d28
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_4.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_utils.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_utils.cpp
new file mode 100644
index 0000000000..5c5509abde
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_utils.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_utils.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_utils.mm
new file mode 100644
index 0000000000..56af9aebab
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_RTAS_utils.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_Standalone.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_Standalone.cpp
new file mode 100644
index 0000000000..d3b6529a80
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_Standalone.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_VST2.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_VST2.cpp
new file mode 100644
index 0000000000..c35394b418
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_VST2.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_VST3.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_VST3.cpp
new file mode 100644
index 0000000000..8e2e5cde2e
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_VST3.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_VST_utils.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_VST_utils.mm
new file mode 100644
index 0000000000..ee2f414e66
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_VST_utils.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_utils.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_utils.cpp
new file mode 100644
index 0000000000..183f61b238
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_plugin_client_utils.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_processors.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_processors.cpp
new file mode 100644
index 0000000000..bfe172edd0
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_processors.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_processors.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_processors.mm
new file mode 100644
index 0000000000..b80ae9017f
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_processors.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_utils.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_utils.cpp
new file mode 100644
index 0000000000..97bd2c568c
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_utils.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_utils.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_utils.mm
new file mode 100644
index 0000000000..8eae7c6e2f
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_audio_utils.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_core.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_core.cpp
new file mode 100644
index 0000000000..d0ce1636f0
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_core.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_core.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_core.mm
new file mode 100644
index 0000000000..72b10bf817
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_core.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_data_structures.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_data_structures.cpp
new file mode 100644
index 0000000000..9315aa1686
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_data_structures.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_data_structures.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_data_structures.mm
new file mode 100644
index 0000000000..695ec43925
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_data_structures.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_events.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_events.cpp
new file mode 100644
index 0000000000..1bba110a97
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_events.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_events.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_events.mm
new file mode 100644
index 0000000000..4cc34fc401
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_events.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_graphics.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_graphics.cpp
new file mode 100644
index 0000000000..319c76de0e
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_graphics.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_graphics.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_graphics.mm
new file mode 100644
index 0000000000..b28e6dd056
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_graphics.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_basics.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_basics.cpp
new file mode 100644
index 0000000000..216c76bb05
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_basics.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_basics.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_basics.mm
new file mode 100644
index 0000000000..6a9726fa5f
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_basics.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_extra.cpp b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_extra.cpp
new file mode 100644
index 0000000000..7226e19833
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_extra.cpp
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_extra.mm b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_extra.mm
new file mode 100644
index 0000000000..c9b6c3bfc6
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/JuceLibraryCode/juce_gui_extra.mm
@@ -0,0 +1,9 @@
+/*
+
+ IMPORTANT! This file is auto-generated each time you save your
+ project - if you alter its contents, your changes may be overwritten!
+
+*/
+
+#include "AppConfig.h"
+#include
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Source/IAAEffectEditor.h b/examples/PlugInSamples/InterAppAudioEffect/Source/IAAEffectEditor.h
new file mode 100644
index 0000000000..7f44b4e87c
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/Source/IAAEffectEditor.h
@@ -0,0 +1,277 @@
+#ifndef IAAEFFECTEDITOR_H_INCLUDED
+#define IAAEFFECTEDITOR_H_INCLUDED
+
+#include "../JuceLibraryCode/JuceHeader.h"
+#include "IAAEffectProcessor.h"
+#include "SimpleMeter.h"
+
+
+class IAAEffectEditor : public AudioProcessorEditor,
+ private IAAEffectProcessor::MeterListener,
+ private ButtonListener,
+ private Timer
+{
+public:
+ IAAEffectEditor (IAAEffectProcessor& p,
+ AudioProcessorValueTreeState& vts)
+ : AudioProcessorEditor (p),
+ processor (p),
+ parameters (vts)
+ {
+ // Register for meter value updates.
+ processor.addMeterListener (*this);
+
+ gainSlider.setSliderStyle (Slider::SliderStyle::LinearVertical);
+ gainSlider.setTextBoxStyle (Slider::TextEntryBoxPosition::TextBoxAbove, false, 60, 20);
+ addAndMakeVisible (gainSlider);
+
+ for (auto& meter : meters)
+ addAndMakeVisible (meter);
+
+ // Configure all the graphics for the transport control.
+
+ transportText.setColour (Label::textColourId, Colours::white);
+ transportText.setFont (Font (Font::getDefaultMonospacedFontName(), 18.0f, Font::plain));
+ transportText.setJustificationType (Justification::topLeft);
+ addChildComponent (transportText);
+
+ Path rewindShape;
+ rewindShape.addRectangle (0.0, 0.0, 5.0, buttonSize);
+ rewindShape.addTriangle (0.0, buttonSize / 2, buttonSize, 0.0, buttonSize, buttonSize);
+ rewindButton.setShape (rewindShape, true, true, false);
+ rewindButton.addListener (this);
+ addChildComponent (rewindButton);
+
+ Path playShape;
+ playShape.addTriangle (0.0, 0.0, 0.0, buttonSize, buttonSize, buttonSize / 2);
+ playButton.setShape (playShape, true, true, false);
+ playButton.addListener (this);
+ addChildComponent (playButton);
+
+ Path recordShape;
+ recordShape.addEllipse (0.0, 0.0, buttonSize, buttonSize);
+ recordButton.setShape (recordShape, true, true, false);
+ recordButton.addListener (this);
+ addChildComponent (recordButton);
+
+ // Configure the switch to host button.
+
+ switchToHostButtonLabel.setColour (Label::textColourId, Colours::white);
+ switchToHostButtonLabel.setFont (Font (Font::getDefaultMonospacedFontName(), 18.0f, Font::plain));
+ switchToHostButtonLabel.setJustificationType (Justification::centredRight);
+ switchToHostButtonLabel.setText ("Switch to\nhost app:", dontSendNotification);
+ addChildComponent (switchToHostButtonLabel);
+
+ switchToHostButton.addListener (this);
+ addChildComponent (switchToHostButton);
+
+ Rectangle screenSize = Desktop::getInstance().getDisplays().getMainDisplay().userArea;
+ setSize (screenSize.getWidth(), screenSize.getHeight());
+
+ resized();
+
+ startTimerHz (60);
+ }
+
+ //==============================================================================
+ void paint (Graphics& g) override
+ {
+ g.fillAll (Colours::darkgrey);
+ }
+
+ void resized() override
+ {
+ auto area = getBounds().reduced (10);
+
+ gainSlider.setBounds (area.removeFromLeft (60));
+
+ for (auto& meter : meters)
+ {
+ area.removeFromLeft (10);
+ meter.setBounds (area.removeFromLeft (20));
+ }
+
+ area.removeFromLeft (20);
+ transportText.setBounds (area.removeFromTop (120));
+
+ auto navigationArea = area.removeFromTop (buttonSize);
+ rewindButton.setTopLeftPosition (navigationArea.getPosition());
+ navigationArea.removeFromLeft (buttonSize + 10);
+ playButton.setTopLeftPosition (navigationArea.getPosition());
+ navigationArea.removeFromLeft (buttonSize + 10);
+ recordButton.setTopLeftPosition (navigationArea.getPosition());
+
+ area.removeFromTop (30);
+
+ auto appSwitchArea = area.removeFromTop (buttonSize);
+ switchToHostButtonLabel.setBounds (appSwitchArea.removeFromLeft (100));
+ appSwitchArea.removeFromLeft (5);
+ switchToHostButton.setBounds (appSwitchArea.removeFromLeft (buttonSize));
+ }
+
+private:
+ //==============================================================================
+ // Called from the audio thread.
+ void handleNewMeterValue (int channel, float value) override
+ {
+ meters[(size_t) channel].update (value);
+ }
+
+ //==============================================================================
+ void timerCallback () override
+ {
+ auto timeInfoSuccess = processor.updateCurrentTimeInfoFromHost (lastPosInfo);
+ transportText.setVisible (timeInfoSuccess);
+ if (timeInfoSuccess)
+ updateTransportTextDisplay();
+
+ updateTransportButtonsDisplay();
+
+ updateSwitchToHostDisplay();
+ }
+
+ //==============================================================================
+ void buttonClicked (Button* b) override
+ {
+ auto playHead = processor.getPlayHead();
+ if (playHead != nullptr && playHead->canControlTransport())
+ {
+ if (b == &rewindButton)
+ {
+ playHead->transportRewind();
+ }
+ else if (b == &playButton)
+ {
+ playHead->transportPlay(! lastPosInfo.isPlaying);
+ }
+ else if (b == &recordButton)
+ {
+ playHead->transportRecord (! lastPosInfo.isRecording);
+ }
+ else if (b == &switchToHostButton)
+ {
+ PluginHostType hostType;
+
+ hostType.switchToHostApplication();
+ }
+ }
+ }
+
+ //==============================================================================
+ // quick-and-dirty function to format a timecode string
+ String timeToTimecodeString (double seconds)
+ {
+ auto millisecs = roundToInt (seconds * 1000.0);
+ auto absMillisecs = std::abs (millisecs);
+
+ return String::formatted ("%02d:%02d:%02d.%03d",
+ millisecs / 360000,
+ (absMillisecs / 60000) % 60,
+ (absMillisecs / 1000) % 60,
+ absMillisecs % 1000);
+ }
+
+ // A quick-and-dirty function to format a bars/beats string.
+ String quarterNotePositionToBarsBeatsString (double quarterNotes, int numerator, int denominator)
+ {
+ if (numerator == 0 || denominator == 0)
+ return "1|1|000";
+
+ auto quarterNotesPerBar = (numerator * 4 / denominator);
+ auto beats = (fmod (quarterNotes, quarterNotesPerBar) / quarterNotesPerBar) * numerator;
+
+ auto bar = ((int) quarterNotes) / quarterNotesPerBar + 1;
+ auto beat = ((int) beats) + 1;
+ auto ticks = ((int) (fmod (beats, 1.0) * 960.0 + 0.5));
+
+ return String::formatted ("%d|%d|%03d", bar, beat, ticks);
+ }
+
+ void updateTransportTextDisplay()
+ {
+ MemoryOutputStream displayText;
+
+ displayText << "[" << SystemStats::getJUCEVersion() << "]\n"
+ << String (lastPosInfo.bpm, 2) << " bpm\n"
+ << lastPosInfo.timeSigNumerator << '/' << lastPosInfo.timeSigDenominator << "\n"
+ << timeToTimecodeString (lastPosInfo.timeInSeconds) << "\n"
+ << quarterNotePositionToBarsBeatsString (lastPosInfo.ppqPosition,
+ lastPosInfo.timeSigNumerator,
+ lastPosInfo.timeSigDenominator) << "\n";
+
+ if (lastPosInfo.isRecording)
+ displayText << "(recording)";
+ else if (lastPosInfo.isPlaying)
+ displayText << "(playing)";
+
+ transportText.setText (displayText.toString(), dontSendNotification);
+ }
+
+ void updateTransportButtonsDisplay()
+ {
+ auto visible = processor.getPlayHead() != nullptr
+ && processor.getPlayHead()->canControlTransport();
+
+ if (rewindButton.isVisible() != visible)
+ {
+ rewindButton.setVisible (visible);
+ playButton.setVisible (visible);
+ recordButton.setVisible (visible);
+ }
+
+ if (visible)
+ {
+ Colour playColour = lastPosInfo.isPlaying ? Colours::green : defaultButtonColour;
+ playButton.setColours (playColour, playColour, playColour);
+ playButton.repaint();
+
+ Colour recordColour = lastPosInfo.isRecording ? Colours::red : defaultButtonColour;
+ recordButton.setColours (recordColour, recordColour, recordColour);
+ recordButton.repaint();
+ }
+ }
+
+ void updateSwitchToHostDisplay()
+ {
+ PluginHostType hostType;
+ const bool visible = hostType.isInterAppAudioConnected();
+
+ if (switchToHostButtonLabel.isVisible() != visible)
+ {
+ switchToHostButtonLabel.setVisible (visible);
+ switchToHostButton.setVisible (visible);
+ if (visible) {
+ auto icon = hostType.getHostIcon (buttonSize);
+ switchToHostButton.setImages(false, true, true,
+ icon, 1.0, Colours::transparentBlack,
+ icon, 1.0, Colours::transparentBlack,
+ icon, 1.0, Colours::transparentBlack);
+ }
+ }
+ }
+
+ IAAEffectProcessor& processor;
+ AudioProcessorValueTreeState& parameters;
+
+ const int buttonSize = 30;
+ const Colour defaultButtonColour = Colours::lightgrey;
+ ShapeButton rewindButton {"Rewind", defaultButtonColour, defaultButtonColour, defaultButtonColour};
+ ShapeButton playButton {"Play", defaultButtonColour, defaultButtonColour, defaultButtonColour};
+ ShapeButton recordButton {"Record", defaultButtonColour, defaultButtonColour, defaultButtonColour};
+
+ Slider gainSlider;
+ AudioProcessorValueTreeState::SliderAttachment gainAttachment = {parameters, "gain", gainSlider};
+
+ std::array meters;
+
+ ImageButton switchToHostButton;
+ Label transportText, switchToHostButtonLabel;
+ Image hostImage;
+
+ AudioPlayHead::CurrentPositionInfo lastPosInfo;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IAAEffectEditor)
+};
+
+
+#endif // IAAEFFECTEDITOR_H_INCLUDED
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Source/IAAEffectProcessor.cpp b/examples/PlugInSamples/InterAppAudioEffect/Source/IAAEffectProcessor.cpp
new file mode 100644
index 0000000000..ae65414bb6
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/Source/IAAEffectProcessor.cpp
@@ -0,0 +1,169 @@
+#include "IAAEffectProcessor.h"
+#include "IAAEffectEditor.h"
+
+
+IAAEffectProcessor::IAAEffectProcessor()
+ : AudioProcessor (BusesProperties()
+ .withInput ("Input", AudioChannelSet::stereo(), true)
+ .withOutput ("Output", AudioChannelSet::stereo(), true)),
+ parameters (*this, nullptr)
+{
+ parameters.createAndAddParameter ("gain",
+ "Gain",
+ String(),
+ NormalisableRange (0.0f, 1.0f),
+ (float) (1.0 / 3.14),
+ nullptr,
+ nullptr);
+
+ parameters.state = ValueTree (Identifier ("InterAppAudioEffect"));
+}
+
+IAAEffectProcessor::~IAAEffectProcessor()
+{
+}
+
+//==============================================================================
+const String IAAEffectProcessor::getName() const
+{
+ return JucePlugin_Name;
+}
+
+bool IAAEffectProcessor::acceptsMidi() const
+{
+ return false;
+}
+
+bool IAAEffectProcessor::producesMidi() const
+{
+ return false;
+}
+
+double IAAEffectProcessor::getTailLengthSeconds() const
+{
+ return 0.0;
+}
+
+int IAAEffectProcessor::getNumPrograms()
+{
+ return 1;
+}
+
+int IAAEffectProcessor::getCurrentProgram()
+{
+ return 0;
+}
+
+void IAAEffectProcessor::setCurrentProgram (int)
+{
+}
+
+const String IAAEffectProcessor::getProgramName (int)
+{
+ return String();
+}
+
+void IAAEffectProcessor::changeProgramName (int, const String&)
+{
+}
+
+//==============================================================================
+void IAAEffectProcessor::prepareToPlay (double, int)
+{
+ previousGain = *parameters.getRawParameterValue ("gain");
+}
+
+void IAAEffectProcessor::releaseResources()
+{
+}
+
+bool IAAEffectProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
+{
+ if (layouts.getMainInputChannelSet() != AudioChannelSet::stereo())
+ return false;
+
+ if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
+ return false;
+
+ return true;
+}
+
+void IAAEffectProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer&)
+{
+ const float gain = *parameters.getRawParameterValue ("gain");
+
+ const int totalNumInputChannels = getTotalNumInputChannels();
+ const int totalNumOutputChannels = getTotalNumOutputChannels();
+
+ const int numSamples = buffer.getNumSamples();
+
+ for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
+ buffer.clear (i, 0, buffer.getNumSamples());
+
+ // Apply the gain to the samples using a ramp to avoid discontinuities in
+ // the audio between processed buffers.
+ for (int channel = 0; channel < totalNumInputChannels; ++channel)
+ {
+ buffer.applyGainRamp (channel, 0, numSamples, previousGain, gain);
+
+ meterListeners.call (&IAAEffectProcessor::MeterListener::handleNewMeterValue,
+ channel,
+ buffer.getMagnitude (channel, 0, numSamples));
+ }
+
+ previousGain = gain;
+
+ // Now ask the host for the current time so we can store it to be displayed later.
+ updateCurrentTimeInfoFromHost (lastPosInfo);
+}
+
+//==============================================================================
+bool IAAEffectProcessor::hasEditor() const
+{
+ return true;
+}
+
+AudioProcessorEditor* IAAEffectProcessor::createEditor()
+{
+ return new IAAEffectEditor (*this, parameters);
+}
+
+//==============================================================================
+void IAAEffectProcessor::getStateInformation (MemoryBlock& destData)
+{
+ auto xml = std::unique_ptr (parameters.state.createXml());
+ copyXmlToBinary (*xml, destData);
+}
+
+void IAAEffectProcessor::setStateInformation (const void* data, int sizeInBytes)
+{
+ auto xmlState = std::unique_ptr (getXmlFromBinary (data, sizeInBytes));
+ if (xmlState.get() != nullptr)
+ if (xmlState->hasTagName (parameters.state.getType()))
+ parameters.state = ValueTree::fromXml (*xmlState);
+}
+
+bool IAAEffectProcessor::updateCurrentTimeInfoFromHost (AudioPlayHead::CurrentPositionInfo &posInfo)
+{
+ if (AudioPlayHead* ph = getPlayHead())
+ {
+ AudioPlayHead::CurrentPositionInfo newTime;
+
+ if (ph->getCurrentPosition (newTime))
+ {
+ posInfo = newTime; // Successfully got the current time from the host.
+ return true;
+ }
+ }
+
+ // If the host fails to provide the current time, we'll just reset our copy to a default.
+ lastPosInfo.resetToDefault();
+
+ return false;
+}
+
+//==============================================================================
+AudioProcessor* JUCE_CALLTYPE createPluginFilter()
+{
+ return new IAAEffectProcessor();
+}
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Source/IAAEffectProcessor.h b/examples/PlugInSamples/InterAppAudioEffect/Source/IAAEffectProcessor.h
new file mode 100644
index 0000000000..779ed17961
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/Source/IAAEffectProcessor.h
@@ -0,0 +1,78 @@
+#ifndef PLUGINPROCESSOR_H_INCLUDED
+#define PLUGINPROCESSOR_H_INCLUDED
+
+#include "../JuceLibraryCode/JuceHeader.h"
+
+#include
+
+
+// A simple Inter-App Audio plug-in with a gain control and some meters.
+class IAAEffectProcessor : public AudioProcessor
+{
+public:
+ IAAEffectProcessor();
+ ~IAAEffectProcessor();
+
+ //==============================================================================
+ void prepareToPlay (double sampleRate, int samplesPerBlock) override;
+ void releaseResources() override;
+
+ bool isBusesLayoutSupported (const BusesLayout& layouts) const override;
+
+ void processBlock (AudioSampleBuffer&, MidiBuffer&) override;
+
+ //==============================================================================
+ AudioProcessorEditor* createEditor() override;
+ bool hasEditor() const override;
+
+ //==============================================================================
+ const String getName() const override;
+
+ bool acceptsMidi() const override;
+ bool producesMidi() const override;
+ double getTailLengthSeconds() const override;
+
+ //==============================================================================
+ int getNumPrograms() override;
+ int getCurrentProgram() override;
+ void setCurrentProgram (int index) override;
+ const String getProgramName (int index) override;
+ void changeProgramName (int index, const String& newName) override;
+
+ //==============================================================================
+ void getStateInformation (MemoryBlock& destData) override;
+ void setStateInformation (const void* data, int sizeInBytes) override;
+
+ //==============================================================================
+ bool updateCurrentTimeInfoFromHost (AudioPlayHead::CurrentPositionInfo&);
+
+ // Allow an IAAAudioProcessorEditor to register as a listener to receive new
+ // meter values directly from the audio thread.
+ struct MeterListener
+ {
+ virtual ~MeterListener() {};
+
+ virtual void handleNewMeterValue (int, float) = 0;
+ };
+
+ void addMeterListener (MeterListener& listener) { meterListeners.add (&listener); };
+ void removeMeterListener (MeterListener& listener) { meterListeners.remove (&listener); };
+
+
+private:
+ //==============================================================================
+ AudioProcessorValueTreeState parameters;
+ float previousGain = 0.0;
+ std::array meterValues = { { 0, 0 } };
+
+ // This keeps a copy of the last set of timing info that was acquired during an
+ // audio callback - the UI component will display this.
+ AudioPlayHead::CurrentPositionInfo lastPosInfo;
+
+ ListenerList meterListeners;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IAAEffectProcessor)
+};
+
+
+#endif // PLUGINPROCESSOR_H_INCLUDED
diff --git a/examples/PlugInSamples/InterAppAudioEffect/Source/SimpleMeter.h b/examples/PlugInSamples/InterAppAudioEffect/Source/SimpleMeter.h
new file mode 100644
index 0000000000..9547193536
--- /dev/null
+++ b/examples/PlugInSamples/InterAppAudioEffect/Source/SimpleMeter.h
@@ -0,0 +1,97 @@
+#ifndef SIMPLEMETER_H_INCLUDED
+#define SIMPLEMETER_H_INCLUDED
+
+#include "../JuceLibraryCode/JuceHeader.h"
+
+// A very simple decaying meter.
+class SimpleMeter : public Component,
+ private Timer
+{
+public:
+ SimpleMeter()
+ {
+ startTimerHz (30);
+ }
+
+ //==============================================================================
+ void paint (Graphics& g) override
+ {
+ g.fillAll(Colours::transparentBlack);
+
+ auto area = g.getClipBounds();
+ g.setColour (Colours::skyblue);
+ g.fillRoundedRectangle(area.toFloat(), 6.0);
+
+ auto unfilledHeight = area.getHeight() * (1.0 - level);
+ g.reduceClipRegion (area.getX(), area.getY(),
+ area.getWidth(), (int) unfilledHeight);
+ g.setColour (Colours::grey);
+ g.fillRoundedRectangle(area.toFloat(), 6.0);
+ }
+
+ void resized() override {}
+
+ //==============================================================================
+ // Called from the audio thread.
+ void update (float newLevel)
+ {
+ // We don't care if maxLevel gets set to zero (in timerCallback) between the
+ // load and the assignment.
+ maxLevel = jmax (maxLevel.load(), newLevel);
+ }
+
+private:
+ //==============================================================================
+ void timerCallback() override
+ {
+ auto callbackLevel = maxLevel.exchange (0.0);
+
+ auto decayFactor = 0.95;
+ if (callbackLevel > level)
+ level = callbackLevel;
+ else if (level > 0.001)
+ level *= decayFactor;
+ else
+ level = 0;
+
+ repaint();
+ }
+
+ std::atomic maxLevel {0.0};
+ float level = 0;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SimpleMeter)
+};
+
+#if JUCE_PROJUCER_LIVE_BUILD
+
+// Animate the meter in the Projucer live build.
+struct MockSimpleMeter : public Component,
+ private Timer
+{
+ MockSimpleMeter()
+ {
+ addAndMakeVisible (meter);
+ resized();
+ startTimerHz (100);
+ }
+
+ void paint (Graphics&) override {}
+
+ void resized() override
+ {
+ meter.setBounds (getBounds());
+ }
+
+ void timerCallback() override
+ {
+ meter.update (std::pow (randomNumberGenerator.nextFloat(), 2));
+ }
+
+ SimpleMeter meter;
+ Random randomNumberGenerator;
+};
+
+#endif
+
+#endif // SIMPLEMETER_H_INCLUDED
diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h
index 4318d3f4c2..b41e931c9c 100644
--- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h
+++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h
@@ -732,10 +732,14 @@ public:
attributes << "DevelopmentTeam = " << developmentTeamID << "; ";
const int inAppPurchasesEnabled = (owner.iOS && owner.isInAppPurchasesEnabled()) ? 1 : 0;
+ const int interAppAudioEnabled = (owner.iOS
+ && type == Target::StandalonePlugIn
+ && owner.getProject().shouldEnableIAA()) ? 1 : 0;
const int sandboxEnabled = (type == Target::AudioUnitv3PlugIn ? 1 : 0);
attributes << "SystemCapabilities = {";
attributes << "com.apple.InAppPurchase = { enabled = " << inAppPurchasesEnabled << "; }; ";
+ attributes << "com.apple.InterAppAudio = { enabled = " << interAppAudioEnabled << "; }; ";
attributes << "com.apple.Sandbox = { enabled = " << sandboxEnabled << "; }; ";
attributes << "}; };";
@@ -953,8 +957,10 @@ public:
s.add ("SEPARATE_STRIP = YES");
}
- if (owner.project.getProjectType().isAudioPlugin() && type == Target::AudioUnitv3PlugIn && owner.isOSX())
- s.add (String ("CODE_SIGN_ENTITLEMENTS = \"") + owner.getEntitlementsFileName() + String ("\""));
+ if (owner.project.getProjectType().isAudioPlugin())
+ if ((owner.isOSX() && type == Target::AudioUnitv3PlugIn)
+ || (owner.isiOS() && type == Target::StandalonePlugIn))
+ s.add (String ("CODE_SIGN_ENTITLEMENTS = \"") + owner.getEntitlementsFileName() + String ("\""));
defines = mergePreprocessorDefs (defines, owner.getAllPreprocessorDefs (config, type));
@@ -1112,14 +1118,36 @@ public:
if (owner.settings ["UIStatusBarHidden"] && type != AudioUnitv3PlugIn)
addPlistDictionaryKeyBool (dict, "UIStatusBarHidden", true);
- if (owner.iOS && type != AudioUnitv3PlugIn)
+ if (owner.iOS)
{
- // Forcing full screen disables the split screen feature and prevents error ITMS-90475
- addPlistDictionaryKeyBool (dict, "UIRequiresFullScreen", true);
- addPlistDictionaryKeyBool (dict, "UIStatusBarHidden", true);
+ if (type != AudioUnitv3PlugIn)
+ {
+ // Forcing full screen disables the split screen feature and prevents error ITMS-90475
+ addPlistDictionaryKeyBool (dict, "UIRequiresFullScreen", true);
+ addPlistDictionaryKeyBool (dict, "UIStatusBarHidden", true);
- addIosScreenOrientations (dict);
- addIosBackgroundModes (dict);
+ addIosScreenOrientations (dict);
+ addIosBackgroundModes (dict);
+ }
+
+ if (type == StandalonePlugIn && owner.getProject().shouldEnableIAA())
+ {
+ XmlElement audioComponentsPlistKey ("key");
+ audioComponentsPlistKey.addTextElement ("AudioComponents");
+
+ dict->addChildElement (new XmlElement (audioComponentsPlistKey));
+
+ XmlElement audioComponentsPlistEntry ("array");
+ XmlElement* audioComponentsDict = audioComponentsPlistEntry.createNewChildElement ("dict");
+
+ addPlistDictionaryKey (audioComponentsDict, "name", owner.project.getIAAPluginName());
+ addPlistDictionaryKey (audioComponentsDict, "manufacturer", owner.project.getPluginManufacturerCode().toString().trim().substring (0, 4));
+ addPlistDictionaryKey (audioComponentsDict, "type", owner.project.getIAATypeCode());
+ addPlistDictionaryKey (audioComponentsDict, "subtype", owner.project.getPluginCode().toString().trim().substring (0, 4));
+ addPlistDictionaryKeyInt (audioComponentsDict, "version", owner.project.getVersionAsHexInteger());
+
+ dict->addChildElement (new XmlElement (audioComponentsPlistEntry));
+ }
}
for (auto& e : xcodeExtraPListEntries)
@@ -1500,8 +1528,9 @@ private:
void addFilesAndGroupsToProject (StringArray& topLevelGroupIDs) const
{
- if (! isiOS() && project.getProjectType().isAudioPlugin())
- topLevelGroupIDs.add (addEntitlementsFile());
+ StringArray entitlements = getEntitlements();
+ if (! entitlements.isEmpty())
+ topLevelGroupIDs.add (addEntitlementsFile (entitlements));
for (auto& group : getAllGroups())
if (group.getNumChildren() > 0)
@@ -2188,20 +2217,41 @@ private:
return project.getProjectFilenameRoot() + String (".entitlements");
}
- String addEntitlementsFile() const
+ StringArray getEntitlements() const
{
- const char* sandboxEntitlement =
- ""
- ""
- ""
- ""
- " com.apple.security.app-sandbox"
- " "
- ""
- "";
+ StringArray keys;
+ if (project.getProjectType().isAudioPlugin())
+ {
+ if (isiOS())
+ {
+ if (project.shouldEnableIAA())
+ keys.add ("inter-app-audio");
+ }
+ else
+ {
+ keys.add ("com.apple.security.app-sandbox");
+ }
+ }
+ return keys;
+ }
+
+ String addEntitlementsFile (StringArray keys) const
+ {
+ String content =
+ "\n"
+ "\n"
+ "\n"
+ "\n";
+ for (auto& key : keys)
+ {
+ content += "\t" + key + "\n"
+ "\t\n";
+ }
+ content += "\n"
+ "\n";
File entitlementsFile = getTargetFolder().getChildFile (getEntitlementsFileName());
- overwriteFileIfDifferentOrThrow (entitlementsFile, sandboxEntitlement);
+ overwriteFileIfDifferentOrThrow (entitlementsFile, content);
RelativePath plistPath (entitlementsFile, getTargetFolder(), RelativePath::buildTargetFolder);
return addFile (plistPath, false, false, false, false, nullptr);
diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectSaver.cpp b/extras/Projucer/Source/Project Saving/jucer_ProjectSaver.cpp
index 2ca0f9f4a7..7b86286de9 100644
--- a/extras/Projucer/Source/Project Saving/jucer_ProjectSaver.cpp
+++ b/extras/Projucer/Source/Project Saving/jucer_ProjectSaver.cpp
@@ -80,6 +80,7 @@ void ProjectSaver::writePluginCharacteristicsFile()
flags.set ("JucePlugin_Build_RTAS", valueToBool (project.getShouldBuildRTASAsValue()));
flags.set ("JucePlugin_Build_AAX", valueToBool (project.getShouldBuildAAXAsValue()));
flags.set ("JucePlugin_Build_STANDALONE", valueToBool (project.getShouldBuildStandalonePluginAsValue()));
+ flags.set ("JucePlugin_Enable_IAA", valueToBool (project.getShouldEnableIAAAsValue()));
flags.set ("JucePlugin_Name", valueToStringLiteral (project.getPluginName()));
flags.set ("JucePlugin_Desc", valueToStringLiteral (project.getPluginDesc()));
flags.set ("JucePlugin_Manufacturer", valueToStringLiteral (project.getPluginManufacturer()));
@@ -114,6 +115,9 @@ void ProjectSaver::writePluginCharacteristicsFile()
flags.set ("JucePlugin_AAXCategory", project.getPluginAAXCategory().toString());
flags.set ("JucePlugin_AAXDisableBypass", valueToBool (project.getPluginAAXBypassDisabled()));
flags.set ("JucePlugin_AAXDisableMultiMono", valueToBool (project.getPluginAAXMultiMonoDisabled()));
+ flags.set ("JucePlugin_IAAType", valueToCharLiteral (project.getIAATypeCode()));
+ flags.set ("JucePlugin_IAASubType", "JucePlugin_PluginCode");
+ flags.set ("JucePlugin_IAAName", project.getIAAPluginName().quoted());
{
String plugInChannelConfig = project.getPluginChannelConfigs().toString();
diff --git a/extras/Projucer/Source/Project/jucer_Project.cpp b/extras/Projucer/Source/Project/jucer_Project.cpp
index 1d30292872..042b19c7d8 100644
--- a/extras/Projucer/Source/Project/jucer_Project.cpp
+++ b/extras/Projucer/Source/Project/jucer_Project.cpp
@@ -153,6 +153,7 @@ void Project::setMissingAudioPluginDefaultValues()
setValueIfVoid (getShouldBuildRTASAsValue(), false);
setValueIfVoid (getShouldBuildAAXAsValue(), false);
setValueIfVoid (getShouldBuildStandalonePluginAsValue(), false);
+ setValueIfVoid (getShouldEnableIAAAsValue(), false);
setValueIfVoid (getPluginName(), getTitle());
setValueIfVoid (getPluginDesc(), getTitle());
@@ -629,6 +630,9 @@ void Project::createAudioPluginPropertyEditors (PropertyListBuilder& props)
"Whether the project should produce an AAX plugin.");
props.add (new BooleanPropertyComponent (getShouldBuildStandalonePluginAsValue(), "Build Standalone Plug-In", "Enabled"),
"Whether the project should produce a standalone version of your plugin.");
+ props.add (new BooleanPropertyComponent (getShouldEnableIAAAsValue(), "Enable Inter-App Audio", "Enabled"),
+ "Whether a standalone plug-in should be an Inter-App Audio app. You should also enable the audio "
+ "background capability in the iOS exporter.");
props.add (new TextPropertyComponent (getPluginName(), "Plugin Name", 128, false),
"The name of your plugin (keep it short!)");
@@ -1258,6 +1262,34 @@ String Project::getAUMainTypeCode()
return s;
}
+String Project::getIAATypeCode()
+{
+ String s;
+ if (getPluginWantsMidiInput().getValue())
+ {
+ if (getPluginIsSynth().getValue())
+ s = "auri";
+ else
+ s = "aurm";
+ }
+ else
+ {
+ if (getPluginIsSynth().getValue())
+ s = "aurg";
+ else
+ s = "aurx";
+ }
+ return s;
+}
+
+String Project::getIAAPluginName()
+{
+ String s = getPluginManufacturer().toString();
+ s << ": ";
+ s << getPluginName().toString();
+ return s;
+}
+
String Project::getPluginVSTCategoryString()
{
String s (getPluginVSTCategory().toString().trim());
diff --git a/extras/Projucer/Source/Project/jucer_Project.h b/extras/Projucer/Source/Project/jucer_Project.h
index 06cd9251c2..b0c03a8311 100644
--- a/extras/Projucer/Source/Project/jucer_Project.h
+++ b/extras/Projucer/Source/Project/jucer_Project.h
@@ -130,6 +130,7 @@ public:
Value getShouldBuildRTASAsValue() { return getProjectValue ("buildRTAS"); }
Value getShouldBuildAAXAsValue() { return getProjectValue ("buildAAX"); }
Value getShouldBuildStandalonePluginAsValue() { return getProjectValue ("buildStandalone");}
+ Value getShouldEnableIAAAsValue() { return getProjectValue ("enableIAA"); }
bool shouldBuildVST() const { return getProjectVar ("buildVST"); }
bool shouldBuildVST3() const { return getProjectVar ("buildVST3"); }
@@ -138,6 +139,7 @@ public:
bool shouldBuildRTAS() const { return getProjectVar ("buildRTAS"); }
bool shouldBuildAAX() const { return getProjectVar ("buildAAX"); }
bool shouldBuildStandalonePlugin() const { return getProjectVar ("buildStandalone"); }
+ bool shouldEnableIAA() const { return getProjectVar ("enableIAA"); }
//==============================================================================
Value getPluginName() { return getProjectValue ("pluginName"); }
@@ -163,6 +165,8 @@ public:
String getPluginRTASCategoryCode();
String getAUMainTypeString();
String getAUMainTypeCode();
+ String getIAATypeCode();
+ String getIAAPluginName();
String getPluginVSTCategoryString();
bool isAUPluginHost();
diff --git a/modules/juce_audio_processors/processors/juce_AudioPlayHead.h b/modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h
similarity index 88%
rename from modules/juce_audio_processors/processors/juce_AudioPlayHead.h
rename to modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h
index 6eb0139937..96b2d83f6f 100644
--- a/modules/juce_audio_processors/processors/juce_AudioPlayHead.h
+++ b/modules/juce_audio_basics/audio_play_head/juce_AudioPlayHead.h
@@ -137,4 +137,16 @@ public:
multithreading issues if it's not called on the audio thread.
*/
virtual bool getCurrentPosition (CurrentPositionInfo& result) = 0;
+
+ /** Returns true if this object can control the transport. */
+ virtual bool canControlTransport() { return false; };
+
+ /** Starts or stops the audio. */
+ virtual void transportPlay (bool shouldStartPlaying) { ignoreUnused (shouldStartPlaying); };
+
+ /** Starts or stops recording the audio. */
+ virtual void transportRecord (bool shouldStartRecording) { ignoreUnused (shouldStartRecording); };
+
+ /** Rewinds the audio. */
+ virtual void transportRewind() {};
};
diff --git a/modules/juce_audio_basics/juce_audio_basics.h b/modules/juce_audio_basics/juce_audio_basics.h
index 4f033bd0da..24fac78df5 100644
--- a/modules/juce_audio_basics/juce_audio_basics.h
+++ b/modules/juce_audio_basics/juce_audio_basics.h
@@ -101,5 +101,6 @@ namespace juce
#include "sources/juce_ReverbAudioSource.h"
#include "sources/juce_ToneGeneratorAudioSource.h"
#include "synthesisers/juce_Synthesiser.h"
+#include "audio_play_head/juce_AudioPlayHead.h"
}
diff --git a/modules/juce_audio_devices/juce_audio_devices.cpp b/modules/juce_audio_devices/juce_audio_devices.cpp
index a4b079c0ce..f2d832c88f 100644
--- a/modules/juce_audio_devices/juce_audio_devices.cpp
+++ b/modules/juce_audio_devices/juce_audio_devices.cpp
@@ -182,6 +182,7 @@ namespace juce
//==============================================================================
#elif JUCE_IOS
+ #include "native/juce_ios_Audio.h"
#include "native/juce_ios_Audio.cpp"
#include "native/juce_mac_CoreMidi.cpp"
diff --git a/modules/juce_audio_devices/juce_audio_devices.h b/modules/juce_audio_devices/juce_audio_devices.h
index cac19bc90b..5c3b2d22d6 100644
--- a/modules/juce_audio_devices/juce_audio_devices.h
+++ b/modules/juce_audio_devices/juce_audio_devices.h
@@ -62,6 +62,10 @@
#include
#include
+#if JUCE_MODULE_AVAILABLE_juce_gui_extra
+#include
+#endif
+
//==============================================================================
/** Config: JUCE_ASIO
Enables ASIO audio devices (MS Windows only).
@@ -147,12 +151,12 @@
namespace juce
{
-#include "audio_io/juce_AudioIODevice.h"
-#include "audio_io/juce_AudioIODeviceType.h"
-#include "audio_io/juce_SystemAudioVolume.h"
#include "midi_io/juce_MidiInput.h"
#include "midi_io/juce_MidiMessageCollector.h"
#include "midi_io/juce_MidiOutput.h"
+#include "audio_io/juce_AudioIODevice.h"
+#include "audio_io/juce_AudioIODeviceType.h"
+#include "audio_io/juce_SystemAudioVolume.h"
#include "sources/juce_AudioSourcePlayer.h"
#include "sources/juce_AudioTransportSource.h"
#include "audio_io/juce_AudioDeviceManager.h"
diff --git a/modules/juce_audio_devices/native/juce_ios_Audio.cpp b/modules/juce_audio_devices/native/juce_ios_Audio.cpp
index e39b80cb7d..5c4b03772a 100644
--- a/modules/juce_audio_devices/native/juce_ios_Audio.cpp
+++ b/modules/juce_audio_devices/native/juce_ios_Audio.cpp
@@ -210,35 +210,24 @@ static void logNSError (NSError* e)
#define JUCE_NSERROR_CHECK(X) { NSError* error = nil; X; logNSError (error); }
+#if JUCE_MODULE_AVAILABLE_juce_graphics
+#include
+#endif
//==============================================================================
-class iOSAudioIODevice : public AudioIODevice
+class iOSAudioIODevice::Pimpl : public AudioPlayHead
{
public:
- iOSAudioIODevice (const String& deviceName)
- : AudioIODevice (deviceName, iOSAudioDeviceName)
- {
- sessionHolder->activeDevices.add (this);
- updateSampleRateAndAudioInput();
- }
-
- ~iOSAudioIODevice()
- {
- sessionHolder->activeDevices.removeFirstMatchingValue (this);
- close();
- }
-
- StringArray getOutputChannelNames() override
+ Pimpl (iOSAudioIODevice& ioDevice)
+ : owner (ioDevice)
{
- return { "Left", "Right" };
+ sessionHolder->activeDevices.add (&owner);
}
- StringArray getInputChannelNames() override
+ ~Pimpl()
{
- if (audioInputIsAvailable)
- return { "Left", "Right" };
-
- return {};
+ sessionHolder->activeDevices.removeFirstMatchingValue (&owner);
+ owner.close();
}
static void setAudioSessionActive (bool enabled)
@@ -255,7 +244,7 @@ public:
return session.sampleRate;
}
- Array getAvailableSampleRates() override
+ Array getAvailableSampleRates()
{
Array rates;
@@ -279,7 +268,7 @@ public:
rate = jmax (rate, supportedRate);
}
- trySampleRate (getCurrentSampleRate());
+ trySampleRate (owner.getCurrentSampleRate());
AudioUnitAddPropertyListener (audioUnit,
kAudioUnitProperty_StreamFormat,
@@ -295,7 +284,7 @@ public:
return rates;
}
- Array getAvailableBufferSizes() override
+ Array getAvailableBufferSizes()
{
Array r;
@@ -305,43 +294,33 @@ public:
return r;
}
- int getDefaultBufferSize() override
- {
- #if TARGET_IPHONE_SIMULATOR
- return 512;
- #else
- return 256;
- #endif
- }
-
String open (const BigInteger& inputChannelsWanted,
const BigInteger& outputChannelsWanted,
- double targetSampleRate, int bufferSize) override
+ double targetSampleRate, int bufferSize)
{
close();
- lastError.clear();
- preferredBufferSize = bufferSize <= 0 ? getDefaultBufferSize()
- : bufferSize;
+ owner.lastError.clear();
+ owner.preferredBufferSize = bufferSize <= 0 ? owner.getDefaultBufferSize() : bufferSize;
// xxx set up channel mapping
- activeOutputChans = outputChannelsWanted;
- activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false);
- numOutputChannels = activeOutputChans.countNumberOfSetBits();
- monoOutputChannelNumber = activeOutputChans.findNextSetBit (0);
+ owner.activeOutputChans = outputChannelsWanted;
+ owner.activeOutputChans.setRange (2, owner.activeOutputChans.getHighestBit(), false);
+ owner.numOutputChannels = owner.activeOutputChans.countNumberOfSetBits();
+ monoOutputChannelNumber = owner.activeOutputChans.findNextSetBit (0);
- activeInputChans = inputChannelsWanted;
- activeInputChans.setRange (2, activeInputChans.getHighestBit(), false);
- numInputChannels = activeInputChans.countNumberOfSetBits();
- monoInputChannelNumber = activeInputChans.findNextSetBit (0);
+ owner.activeInputChans = inputChannelsWanted;
+ owner.activeInputChans.setRange (2, owner.activeInputChans.getHighestBit(), false);
+ owner.numInputChannels = owner.activeInputChans.countNumberOfSetBits();
+ monoInputChannelNumber = owner.activeInputChans.findNextSetBit (0);
setAudioSessionActive (true);
// Set the session category & options:
auto session = [AVAudioSession sharedInstance];
- const bool useInputs = (numInputChannels > 0 && audioInputIsAvailable);
+ const bool useInputs = (owner.numInputChannels > 0 && owner.audioInputIsAvailable);
NSString* category = (useInputs ? AVAudioSessionCategoryPlayAndRecord : AVAudioSessionCategoryPlayback);
@@ -357,26 +336,26 @@ public:
// Set the sample rate
trySampleRate (targetSampleRate);
- updateSampleRateAndAudioInput();
+ owner.updateSampleRateAndAudioInput();
updateCurrentBufferSize();
- prepareFloatBuffers (actualBufferSize);
+ prepareFloatBuffers (owner.actualBufferSize);
- isRunning = true;
+ owner.isRunning = true;
handleRouteChange ("Started AudioUnit");
- lastError = (audioUnit != 0 ? "" : "Couldn't open the device");
+ owner.lastError = (audioUnit != 0 ? "" : "Couldn't open the device");
setAudioSessionActive (true);
- return lastError;
+ return owner.lastError;
}
- void close() override
+ void close()
{
- if (isRunning)
+ if (owner.isRunning)
{
- isRunning = false;
+ owner.isRunning = false;
if (audioUnit != 0)
{
@@ -389,40 +368,28 @@ public:
}
}
- bool isOpen() override { return isRunning; }
-
- int getCurrentBufferSizeSamples() override { return actualBufferSize; }
- double getCurrentSampleRate() override { return sampleRate; }
- int getCurrentBitDepth() override { return 16; }
-
- BigInteger getActiveOutputChannels() const override { return activeOutputChans; }
- BigInteger getActiveInputChannels() const override { return activeInputChans; }
-
- int getOutputLatencyInSamples() override { return roundToInt (getCurrentSampleRate() * [AVAudioSession sharedInstance].outputLatency); }
- int getInputLatencyInSamples() override { return roundToInt (getCurrentSampleRate() * [AVAudioSession sharedInstance].inputLatency); }
-
- void start (AudioIODeviceCallback* newCallback) override
+ void start (AudioIODeviceCallback* newCallback)
{
- if (isRunning && callback != newCallback)
+ if (owner.isRunning && owner.callback != newCallback)
{
if (newCallback != nullptr)
- newCallback->audioDeviceAboutToStart (this);
+ newCallback->audioDeviceAboutToStart (&owner);
const ScopedLock sl (callbackLock);
- callback = newCallback;
+ owner.callback = newCallback;
}
}
- void stop() override
+ void stop()
{
- if (isRunning)
+ if (owner.isRunning)
{
AudioIODeviceCallback* lastCallback;
{
const ScopedLock sl (callbackLock);
- lastCallback = callback;
- callback = nullptr;
+ lastCallback = owner.callback;
+ owner.callback = nullptr;
}
if (lastCallback != nullptr)
@@ -430,10 +397,7 @@ public:
}
}
- bool isPlaying() override { return isRunning && callback != nullptr; }
- String getLastError() override { return lastError; }
-
- bool setAudioPreprocessingEnabled (bool enable) override
+ bool setAudioPreprocessingEnabled (bool enable)
{
auto session = [AVAudioSession sharedInstance];
@@ -446,12 +410,169 @@ public:
return session.mode == mode;
}
+ //==============================================================================
+ bool canControlTransport() override { return owner.interAppAudioConnected; }
+
+ void transportPlay (bool shouldSartPlaying) override
+ {
+ if (! canControlTransport())
+ return;
+
+ HostCallbackInfo callbackInfo;
+ fillHostCallbackInfo (callbackInfo);
+
+ Boolean hostIsPlaying = NO;
+ OSStatus err = callbackInfo.transportStateProc2 (callbackInfo.hostUserData,
+ &hostIsPlaying,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ jassert (err == noErr);
+
+ if (hostIsPlaying != shouldSartPlaying)
+ handleAudioTransportEvent (kAudioUnitRemoteControlEvent_TogglePlayPause);
+ }
+
+ void transportRecord (bool shouldStartRecording) override
+ {
+ if (! canControlTransport())
+ return;
+
+ HostCallbackInfo callbackInfo;
+ fillHostCallbackInfo (callbackInfo);
+
+ Boolean hostIsRecording = NO;
+ OSStatus err = callbackInfo.transportStateProc2 (callbackInfo.hostUserData,
+ NULL,
+ &hostIsRecording,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ jassert (err == noErr);
+
+ if (hostIsRecording != shouldStartRecording)
+ handleAudioTransportEvent (kAudioUnitRemoteControlEvent_ToggleRecord);
+ }
+
+ void transportRewind() override
+ {
+ if (canControlTransport())
+ handleAudioTransportEvent (kAudioUnitRemoteControlEvent_Rewind);
+ }
+
+ bool getCurrentPosition (CurrentPositionInfo& result) override
+ {
+ if (! canControlTransport())
+ return false;
+
+ zerostruct (result);
+
+ HostCallbackInfo callbackInfo;
+ fillHostCallbackInfo (callbackInfo);
+
+ if (callbackInfo.hostUserData == nullptr)
+ return false;
+
+ Boolean hostIsPlaying = NO;
+ Boolean hostIsRecording = NO;
+ Float64 hostCurrentSampleInTimeLine = 0;
+ Boolean hostIsCycling = NO;
+ Float64 hostCycleStartBeat = 0;
+ Float64 hostCycleEndBeat = 0;
+ OSStatus err = callbackInfo.transportStateProc2 (callbackInfo.hostUserData,
+ &hostIsPlaying,
+ &hostIsRecording,
+ NULL,
+ &hostCurrentSampleInTimeLine,
+ &hostIsCycling,
+ &hostCycleStartBeat,
+ &hostCycleEndBeat);
+ if (err == kAUGraphErr_CannotDoInCurrentContext)
+ return false;
+
+ jassert (err == noErr);
+
+ result.timeInSamples = (int64) hostCurrentSampleInTimeLine;
+ result.isPlaying = hostIsPlaying;
+ result.isRecording = hostIsRecording;
+ result.isLooping = hostIsCycling;
+ result.ppqLoopStart = hostCycleStartBeat;
+ result.ppqLoopEnd = hostCycleEndBeat;
+
+ result.timeInSeconds = result.timeInSamples / owner.sampleRate;
+
+ Float64 hostBeat = 0;
+ Float64 hostTempo = 0;
+ err = callbackInfo.beatAndTempoProc (callbackInfo.hostUserData,
+ &hostBeat,
+ &hostTempo);
+ jassert (err == noErr);
+
+ result.ppqPosition = hostBeat;
+ result.bpm = hostTempo;
+
+ Float32 hostTimeSigNumerator = 0;
+ UInt32 hostTimeSigDenominator = 0;
+ Float64 hostCurrentMeasureDownBeat = 0;
+ err = callbackInfo.musicalTimeLocationProc (callbackInfo.hostUserData,
+ NULL,
+ &hostTimeSigNumerator,
+ &hostTimeSigDenominator,
+ &hostCurrentMeasureDownBeat);
+ jassert (err == noErr);
+
+ result.ppqPositionOfLastBarStart = hostCurrentMeasureDownBeat;
+ result.timeSigNumerator = (int) hostTimeSigNumerator;
+ result.timeSigDenominator = (int) hostTimeSigDenominator;
+
+ result.frameRate = AudioPlayHead::fpsUnknown;
+
+ return true;
+ }
+
+ //==============================================================================
+ #if JUCE_MODULE_AVAILABLE_juce_gui_basics
+ Image getIcon (int size)
+ {
+ if (owner.interAppAudioConnected)
+ {
+ UIImage* hostUIImage = AudioOutputUnitGetHostIcon (audioUnit, size);
+ if (hostUIImage != nullptr)
+ return juce_createImageFromUIImage (hostUIImage);
+ }
+ return Image();
+ }
+ #endif
+
+ void switchApplication()
+ {
+ if (! owner.interAppAudioConnected)
+ return;
+
+ CFURLRef hostUrl;
+ UInt32 dataSize = sizeof (hostUrl);
+ OSStatus err = AudioUnitGetProperty(audioUnit,
+ kAudioUnitProperty_PeerURL,
+ kAudioUnitScope_Global,
+ 0,
+ &hostUrl,
+ &dataSize);
+ if (err == noErr)
+ [[UIApplication sharedApplication] openURL:(NSURL*)hostUrl];
+ }
+
+ //==============================================================================
void invokeAudioDeviceErrorCallback (const String& reason)
{
const ScopedLock sl (callbackLock);
- if (callback != nullptr)
- callback->audioDeviceError (reason);
+ if (owner.callback != nullptr)
+ owner.callback->audioDeviceError (reason);
}
void handleStatusChange (bool enabled, const char* reason)
@@ -460,7 +581,7 @@ public:
JUCE_IOS_AUDIO_LOG ("handleStatusChange: enabled: " << (int) enabled << ", reason: " << reason);
- isRunning = enabled;
+ owner.isRunning = enabled;
setAudioSessionActive (enabled);
if (enabled)
@@ -480,10 +601,10 @@ public:
fixAudioRouteIfSetToReceiver();
- if (isRunning)
+ if (owner.isRunning)
{
invokeAudioDeviceErrorCallback (reason);
- updateSampleRateAndAudioInput();
+ owner.updateSampleRateAndAudioInput();
updateCurrentBufferSize();
createAudioUnit();
@@ -496,29 +617,72 @@ public:
AudioOutputUnitStart (audioUnit);
}
- if (callback != nullptr)
+ if (owner.callback != nullptr)
+ {
+ owner.callback->audioDeviceStopped();
+ owner.callback->audioDeviceAboutToStart (&owner);
+ }
+ }
+ }
+
+ void handleAudioUnitPropertyChange (AudioUnit,
+ AudioUnitPropertyID propertyID,
+ AudioUnitScope,
+ AudioUnitElement)
+ {
+ const ScopedLock myScopedLock (callbackLock);
+
+ switch (propertyID)
+ {
+ case kAudioUnitProperty_IsInterAppConnected: return handleInterAppAudioConnectionChange();
+ default: return;
+ }
+ }
+
+ void handleInterAppAudioConnectionChange()
+ {
+ UInt32 connected;
+ UInt32 dataSize = sizeof (connected);
+ OSStatus err = AudioUnitGetProperty (audioUnit, kAudioUnitProperty_IsInterAppConnected,
+ kAudioUnitScope_Global, 0, &connected, &dataSize);
+ jassert (err == noErr);
+
+ JUCE_IOS_AUDIO_LOG ("handleInterAppAudioConnectionChange: " << connected ? "connected"
+ : "disconnected");
+
+ if (connected != owner.interAppAudioConnected)
+ {
+ const ScopedLock myScopedLock (callbackLock);
+
+ owner.interAppAudioConnected = connected;
+
+ UIApplicationState appstate = [UIApplication sharedApplication].applicationState;
+ bool inForeground = (appstate != UIApplicationStateBackground);
+
+ if (owner.interAppAudioConnected || inForeground)
{
- callback->audioDeviceStopped();
- callback->audioDeviceAboutToStart (this);
+ setAudioSessionActive (true);
+ AudioOutputUnitStart (audioUnit);
+
+ if (owner.callback != nullptr)
+ owner.callback->audioDeviceAboutToStart (&owner);
+ }
+ else if (! inForeground)
+ {
+ AudioOutputUnitStop (audioUnit);
+ setAudioSessionActive (false);
}
}
}
private:
//==============================================================================
+ iOSAudioIODevice& owner;
SharedResourcePointer sessionHolder;
CriticalSection callbackLock;
- NSTimeInterval sampleRate = 0;
- int numInputChannels = 2, numOutputChannels = 2;
- int preferredBufferSize = 0, actualBufferSize = 0;
- bool isRunning = false;
- String lastError;
AudioStreamBasicDescription format;
AudioUnit audioUnit {};
- bool audioInputIsAvailable = false;
- AudioIODeviceCallback* callback = nullptr;
- BigInteger activeOutputChans, activeInputChans;
AudioSampleBuffer floatData;
float* inputChannels[3];
@@ -527,17 +691,17 @@ private:
void prepareFloatBuffers (int bufferSize)
{
- if (numInputChannels + numOutputChannels > 0)
+ if (owner.numInputChannels + owner.numOutputChannels > 0)
{
- floatData.setSize (numInputChannels + numOutputChannels, bufferSize);
+ floatData.setSize (owner.numInputChannels + owner.numOutputChannels, bufferSize);
zeromem (inputChannels, sizeof (inputChannels));
zeromem (outputChannels, sizeof (outputChannels));
- for (int i = 0; i < numInputChannels; ++i)
+ for (int i = 0; i < owner.numInputChannels; ++i)
inputChannels[i] = floatData.getWritePointer (i);
- for (int i = 0; i < numOutputChannels; ++i)
- outputChannels[i] = floatData.getWritePointer (i + numInputChannels);
+ for (int i = 0; i < owner.numOutputChannels; ++i)
+ outputChannels[i] = floatData.getWritePointer (i + owner.numInputChannels);
}
}
@@ -547,21 +711,21 @@ private:
{
OSStatus err = noErr;
- if (audioInputIsAvailable && numInputChannels > 0)
+ if (owner.audioInputIsAvailable && owner.numInputChannels > 0)
err = AudioUnitRender (audioUnit, flags, time, 1, numFrames, data);
const ScopedTryLock stl (callbackLock);
- if (stl.isLocked() && callback != nullptr)
+ if (stl.isLocked() && owner.callback != nullptr)
{
if ((int) numFrames > floatData.getNumSamples())
prepareFloatBuffers ((int) numFrames);
- if (audioInputIsAvailable && numInputChannels > 0)
+ if (owner.audioInputIsAvailable && owner.numInputChannels > 0)
{
short* shortData = (short*) data->mBuffers[0].mData;
- if (numInputChannels >= 2)
+ if (owner.numInputChannels >= 2)
{
for (UInt32 i = 0; i < numFrames; ++i)
{
@@ -583,17 +747,17 @@ private:
}
else
{
- for (int i = numInputChannels; --i >= 0;)
+ for (int i = owner.numInputChannels; --i >= 0;)
zeromem (inputChannels[i], sizeof (float) * numFrames);
}
- callback->audioDeviceIOCallback ((const float**) inputChannels, numInputChannels,
- outputChannels, numOutputChannels, (int) numFrames);
+ owner.callback->audioDeviceIOCallback ((const float**) inputChannels, owner.numInputChannels,
+ outputChannels, owner.numOutputChannels, (int) numFrames);
short* const shortData = (short*) data->mBuffers[0].mData;
int n = 0;
- if (numOutputChannels >= 2)
+ if (owner.numOutputChannels >= 2)
{
for (UInt32 i = 0; i < numFrames; ++i)
{
@@ -601,7 +765,7 @@ private:
shortData [n++] = (short) (outputChannels[1][i] * 32767.0f);
}
}
- else if (numOutputChannels == 1)
+ else if (owner.numOutputChannels == 1)
{
for (UInt32 i = 0; i < numFrames; ++i)
{
@@ -623,25 +787,13 @@ private:
return err;
}
- void updateSampleRateAndAudioInput()
- {
- auto session = [AVAudioSession sharedInstance];
- sampleRate = session.sampleRate;
- audioInputIsAvailable = session.isInputAvailable;
- actualBufferSize = roundToInt (sampleRate * session.IOBufferDuration);
-
- JUCE_IOS_AUDIO_LOG ("AVAudioSession: sampleRate: " << sampleRate
- << " Hz, audioInputAvailable: " << (int) audioInputIsAvailable
- << ", buffer size: " << actualBufferSize);
- }
-
void updateCurrentBufferSize()
{
- NSTimeInterval bufferDuration = sampleRate > 0 ? (NSTimeInterval) ((preferredBufferSize + 1) / sampleRate) : 0.0;
+ NSTimeInterval bufferDuration = owner.sampleRate > 0 ? (NSTimeInterval) ((owner.preferredBufferSize + 1) / owner.sampleRate) : 0.0;
JUCE_NSERROR_CHECK ([[AVAudioSession sharedInstance] setPreferredIOBufferDuration: bufferDuration
error: &error]);
- updateSampleRateAndAudioInput();
+ owner.updateSampleRateAndAudioInput();
}
//==============================================================================
@@ -649,7 +801,7 @@ private:
UInt32 /*busNumber*/, UInt32 numFrames, AudioBufferList* data)
{
- return static_cast (client)->process (flags, time, numFrames, data);
+ return static_cast (client)->process (flags, time, numFrames, data);
}
//==============================================================================
@@ -687,7 +839,32 @@ private:
if (audioUnit == 0)
return false;
- if (numInputChannels > 0)
+ #if JucePlugin_Enable_IAA
+ AudioComponentDescription appDesc;
+ appDesc.componentType = JucePlugin_IAAType;
+ appDesc.componentSubType = JucePlugin_IAASubType;
+ appDesc.componentManufacturer = JucePlugin_ManufacturerCode;
+ appDesc.componentFlags = 0;
+ appDesc.componentFlagsMask = 0;
+ OSStatus err = AudioOutputUnitPublish (&appDesc,
+ CFSTR(JucePlugin_IAAName),
+ JucePlugin_VersionCode,
+ audioUnit);
+
+ // This assert will be hit if the Inter-App Audio entitlement has not
+ // been enabled, or the description being published with
+ // AudioOutputUnitPublish is different from any in the AudioComponents
+ // array in this application's .plist file.
+ jassert (err == noErr);
+
+ err = AudioUnitAddPropertyListener(audioUnit,
+ kAudioUnitProperty_IsInterAppConnected,
+ audioUnitPropertyChangeDispatcher,
+ this);
+ jassert (err == noErr);
+ #endif
+
+ if (owner.numInputChannels > 0)
{
const UInt32 one = 1;
AudioUnitSetProperty (audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof (one));
@@ -721,7 +898,7 @@ private:
if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global, 0, &framesPerSlice, &dataSize) == noErr
- && dataSize == sizeof (framesPerSlice) && static_cast (framesPerSlice) != actualBufferSize)
+ && dataSize == sizeof (framesPerSlice) && static_cast (framesPerSlice) != owner.actualBufferSize)
{
prepareFloatBuffers (static_cast (framesPerSlice));
}
@@ -731,6 +908,26 @@ private:
return true;
}
+ void fillHostCallbackInfo (HostCallbackInfo& callbackInfo)
+ {
+ zerostruct (callbackInfo);
+ UInt32 dataSize = sizeof (HostCallbackInfo);
+ OSStatus err = AudioUnitGetProperty (audioUnit,
+ kAudioUnitProperty_HostCallbacks,
+ kAudioUnitScope_Global,
+ 0,
+ &callbackInfo,
+ &dataSize);
+ jassert (err == noErr);
+ }
+
+ void handleAudioTransportEvent (AudioUnitRemoteControlEvent event)
+ {
+ OSStatus err = AudioUnitSetProperty (audioUnit, kAudioOutputUnitProperty_RemoteControlToHost,
+ kAudioUnitScope_Global, 0, &event, sizeof (event));
+ jassert (err == noErr);
+ }
+
// If the routing is set to go through the receiver (i.e. the speaker, but quiet), this re-routes it
// to make it loud. Needed because by default when using an input + output, the output is kept quiet.
static void fixAudioRouteIfSetToReceiver()
@@ -768,14 +965,14 @@ private:
0,
&desc,
&dataSize);
- if (desc.mSampleRate != getCurrentSampleRate())
+ if (desc.mSampleRate != owner.getCurrentSampleRate())
{
- updateSampleRateAndAudioInput();
+ owner.updateSampleRateAndAudioInput();
const ScopedLock sl (callbackLock);
- if (callback != nullptr)
+ if (owner.callback != nullptr)
{
- callback->audioDeviceStopped();
- callback->audioDeviceAboutToStart (this);
+ owner.callback->audioDeviceStopped();
+ owner.callback->audioDeviceAboutToStart (&owner);
}
}
}
@@ -787,13 +984,91 @@ private:
AudioUnitElement element)
{
if (scope == kAudioUnitScope_Output && element == 0)
- static_cast (device)->handleStreamFormatChange();
+ static_cast (device)->handleStreamFormatChange();
+ }
+
+ static void audioUnitPropertyChangeDispatcher (void* data, AudioUnit unit, AudioUnitPropertyID propertyID,
+ AudioUnitScope scope, AudioUnitElement element)
+ {
+ Pimpl* device = (Pimpl*)data;
+ device->handleAudioUnitPropertyChange (unit, propertyID, scope, element);
+ }
+
+ void handleMidiMessage (MidiMessage msg)
+ {
+ if (owner.messageCollector != nullptr)
+ owner.messageCollector->addMessageToQueue (msg);
+ }
+
+ static void midiEventCallback (void *client, UInt32 status, UInt32 data1, UInt32 data2, UInt32)
+ {
+ return static_cast (client)->handleMidiMessage (MidiMessage ((int) status,
+ (int) data1,
+ (int) data2,
+ Time::getMillisecondCounter() / 1000.0));
}
- JUCE_DECLARE_NON_COPYABLE (iOSAudioIODevice)
+ JUCE_DECLARE_NON_COPYABLE (Pimpl)
};
+//==============================================================================
+iOSAudioIODevice::iOSAudioIODevice (const String& deviceName)
+ : AudioIODevice (deviceName, iOSAudioDeviceName),
+ #if TARGET_IPHONE_SIMULATOR
+ defaultBufferSize (512),
+ #else
+ defaultBufferSize (256),
+ #endif
+ sampleRate (0), numInputChannels (2), numOutputChannels (2),
+ preferredBufferSize (0), actualBufferSize (0), isRunning (false),
+ audioInputIsAvailable (false), interAppAudioConnected (false),
+ callback (nullptr), messageCollector (nullptr),
+ pimpl (new Pimpl (*this))
+{
+ updateSampleRateAndAudioInput();
+}
+
+//==============================================================================
+int iOSAudioIODevice::getOutputLatencyInSamples() { return roundToInt (sampleRate * [AVAudioSession sharedInstance].outputLatency); }
+int iOSAudioIODevice::getInputLatencyInSamples() { return roundToInt (sampleRate * [AVAudioSession sharedInstance].inputLatency); }
+
+//==============================================================================
+AudioPlayHead* iOSAudioIODevice::getAudioPlayHead() const { return pimpl; }
+void iOSAudioIODevice::close() { pimpl->close(); }
+void iOSAudioIODevice::start (AudioIODeviceCallback* callbackToUse) { pimpl->start (callbackToUse); }
+void iOSAudioIODevice::stop() { pimpl->stop(); }
+Array iOSAudioIODevice::getAvailableSampleRates() { return pimpl->getAvailableSampleRates(); }
+Array iOSAudioIODevice::getAvailableBufferSizes() { return pimpl->getAvailableBufferSizes(); }
+bool iOSAudioIODevice::setAudioPreprocessingEnabled (bool enabled) { return pimpl->setAudioPreprocessingEnabled (enabled); }
+void iOSAudioIODevice::switchApplication() { return pimpl->switchApplication(); }
+
+//==============================================================================
+void iOSAudioIODevice::handleStatusChange (bool enabled, const char* reason) { pimpl->handleStatusChange (enabled, reason); }
+void iOSAudioIODevice::handleRouteChange (const char* reason) { pimpl->handleRouteChange (reason); }
+
+#if JUCE_MODULE_AVAILABLE_juce_gui_basics
+Image iOSAudioIODevice::getIcon (int size) { return pimpl->getIcon (size); }
+#endif
+
+//==============================================================================
+String iOSAudioIODevice::open (const BigInteger& inChans, const BigInteger& outChans, double requestedSampleRate, int requestedBufferSize)
+{
+ return pimpl->open (inChans, outChans, requestedSampleRate, requestedBufferSize);
+}
+
+void iOSAudioIODevice::updateSampleRateAndAudioInput()
+{
+ auto session = [AVAudioSession sharedInstance];
+ sampleRate = session.sampleRate;
+ audioInputIsAvailable = session.isInputAvailable;
+ actualBufferSize = roundToInt (sampleRate * session.IOBufferDuration);
+
+ JUCE_IOS_AUDIO_LOG ("AVAudioSession: sampleRate: " << sampleRate
+ << " Hz, audioInputAvailable: " << (int) audioInputIsAvailable
+ << ", buffer size: " << actualBufferSize);
+}
+
//==============================================================================
class iOSAudioIODeviceType : public AudioIODeviceType
{
diff --git a/modules/juce_audio_devices/native/juce_ios_Audio.h b/modules/juce_audio_devices/native/juce_ios_Audio.h
new file mode 100644
index 0000000000..8964935b85
--- /dev/null
+++ b/modules/juce_audio_devices/native/juce_ios_Audio.h
@@ -0,0 +1,107 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library.
+ Copyright (c) 2016 - ROLI Ltd.
+
+ Permission is granted to use this software under the terms of the ISC license
+ http://www.isc.org/downloads/software-support-policy/isc-license/
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
+ TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
+ OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ OF THIS SOFTWARE.
+
+ -----------------------------------------------------------------------------
+
+ To release a closed-source product which uses other parts of JUCE not
+ licensed under the ISC terms, commercial licenses are available: visit
+ www.juce.com for more information.
+
+ ==============================================================================
+*/
+
+#pragma once
+
+class iOSAudioIODeviceType;
+
+class iOSAudioIODevice : public AudioIODevice
+{
+public:
+ //==============================================================================
+ String open (const BigInteger&, const BigInteger&, double, int) override;
+ void close() override;
+
+ void start (AudioIODeviceCallback*) override;
+ void stop() override;
+
+ Array getAvailableSampleRates() override;
+ Array getAvailableBufferSizes() override;
+ bool setAudioPreprocessingEnabled (bool) override;
+
+ //==============================================================================
+ bool isPlaying() override { return isRunning && callback != nullptr; }
+ bool isOpen() override { return isRunning; }
+ String getLastError() override { return lastError; };
+
+ //==============================================================================
+ StringArray getOutputChannelNames() override { return { "Left", "Right" }; }
+ StringArray getInputChannelNames() override { return audioInputIsAvailable ? getOutputChannelNames() : StringArray(); }
+ int getDefaultBufferSize() override { return defaultBufferSize; }
+ int getCurrentBufferSizeSamples() override { return actualBufferSize; }
+ double getCurrentSampleRate() override { return sampleRate; }
+ int getCurrentBitDepth() override { return 16; }
+ BigInteger getActiveOutputChannels() const override { return activeOutputChans; }
+ BigInteger getActiveInputChannels() const override { return activeInputChans; }
+ int getOutputLatencyInSamples() override;
+ int getInputLatencyInSamples() override;
+
+ //==============================================================================
+ void handleStatusChange (bool enabled, const char* reason);
+ void handleRouteChange (const char* reason);
+
+ //==============================================================================
+ virtual void setMidiMessageCollector (MidiMessageCollector* collector) { messageCollector = collector; }
+ virtual AudioPlayHead* getAudioPlayHead() const;
+
+ //==============================================================================
+ virtual bool isInterAppAudioConnected() const { return interAppAudioConnected; }
+ #if JUCE_MODULE_AVAILABLE_juce_gui_basics
+ virtual Image getIcon (int size);
+ #endif
+ virtual void switchApplication();
+private:
+ //==============================================================================
+ void updateSampleRateAndAudioInput();
+
+ //==============================================================================
+ friend class iOSAudioIODeviceType;
+ iOSAudioIODevice (const String& deviceName);
+
+ //==============================================================================
+ const int defaultBufferSize;
+ double sampleRate;
+ int numInputChannels, numOutputChannels;
+ int preferredBufferSize, actualBufferSize;
+ bool isRunning;
+ String lastError;
+
+ bool audioInputIsAvailable, interAppAudioConnected;
+ BigInteger activeOutputChans, activeInputChans;
+
+ AudioIODeviceCallback* callback;
+ MidiMessageCollector* messageCollector;
+
+ class Pimpl;
+ friend class Pimpl;
+ ScopedPointer pimpl;
+
+ JUCE_DECLARE_NON_COPYABLE (iOSAudioIODevice)
+};
diff --git a/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm b/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm
index ca0d8ae5a4..631a62e28f 100644
--- a/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm
+++ b/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm
@@ -1431,5 +1431,14 @@ private:
- (void)viewDidLayoutSubviews { return cpp->viewDidLayoutSubviews(); }
@end
+//==============================================================================
+#if JUCE_IOS
+bool JUCE_CALLTYPE juce_isInterAppAudioConnected() { return false; }
+void JUCE_CALLTYPE juce_switchToHostApplication() {}
+#if JUCE_MODULE_AVAILABLE_juce_gui_basics
+Image JUCE_CALLTYPE juce_getIAAHostIcon (int) { return Image(); }
+#endif
+#endif
+
#pragma clang diagnostic pop
#endif
diff --git a/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterApp.cpp b/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterApp.cpp
index d80723e7ff..490de16807 100644
--- a/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterApp.cpp
+++ b/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterApp.cpp
@@ -43,6 +43,10 @@ extern AudioProcessor* JUCE_CALLTYPE createPluginFilter();
namespace juce
{
+ #if JucePlugin_Enable_IAA && JUCE_IOS
+ #include "../../juce_audio_devices/native/juce_ios_Audio.h"
+ #endif
+
#include "juce_StandaloneFilterWindow.h"
}
@@ -107,4 +111,31 @@ protected:
ScopedPointer mainWindow;
};
+#if JucePlugin_Build_STANDALONE && JUCE_IOS
+
+bool JUCE_CALLTYPE juce_isInterAppAudioConnected()
+{
+ if (auto holder = StandalonePluginHolder::getInstance())
+ return holder->isInterAppAudioConnected();
+
+ return false;
+}
+
+void JUCE_CALLTYPE juce_switchToHostApplication()
+{
+ if (auto holder = StandalonePluginHolder::getInstance())
+ holder->switchToHostApplication();
+}
+
+#if JUCE_MODULE_AVAILABLE_juce_gui_basics
+Image JUCE_CALLTYPE juce_getIAAHostIcon (int size)
+{
+ if (auto holder = StandalonePluginHolder::getInstance())
+ return holder->getIAAHostIcon (size);
+
+ return Image();
+}
+#endif
+#endif
+
#endif
diff --git a/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h b/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h
index df6866c085..8b11566188 100644
--- a/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h
+++ b/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h
@@ -182,6 +182,14 @@ public:
void startPlaying()
{
player.setProcessor (processor);
+
+ #if JucePlugin_Enable_IAA && JUCE_IOS
+ if (auto device = dynamic_cast (deviceManager.getCurrentAudioDevice()))
+ {
+ processor->setPlayHead (device->getAudioPlayHead());
+ device->setMidiMessageCollector (&player.getMidiMessageCollector());
+ }
+ #endif
}
void stopPlaying()
@@ -260,6 +268,41 @@ public:
}
}
+ //==============================================================================
+ void switchToHostApplication()
+ {
+ #if JUCE_IOS
+ if (auto device = dynamic_cast (deviceManager.getCurrentAudioDevice()))
+ device->switchApplication();
+ #endif
+ }
+
+ bool isInterAppAudioConnected()
+ {
+ #if JUCE_IOS
+ if (auto device = dynamic_cast (deviceManager.getCurrentAudioDevice()))
+ return device->isInterAppAudioConnected();
+ #endif
+
+ return false;
+ }
+
+ #if JUCE_MODULE_AVAILABLE_juce_gui_basics
+ Image getIAAHostIcon (int size)
+ {
+ #if JUCE_IOS && JucePlugin_Enable_IAA
+ if (auto device = dynamic_cast (deviceManager.getCurrentAudioDevice()))
+ return device->getIcon (size);
+ #else
+ ignoreUnused (size);
+ #endif
+
+ return Image();
+ }
+ #endif
+
+ static StandalonePluginHolder* getInstance();
+
//==============================================================================
OptionalScopedPointer settings;
ScopedPointer processor;
@@ -328,7 +371,6 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StandalonePluginHolder)
};
-
//==============================================================================
/**
A class that can be used to run a simple standalone application containing your filter.
@@ -481,6 +523,8 @@ public:
optionsButton.setBounds (8, 6, 60, getTitleBarHeight() - 8);
}
+ virtual StandalonePluginHolder* getPluginHolder() { return pluginHolder; }
+
ScopedPointer pluginHolder;
private:
@@ -489,3 +533,20 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StandaloneFilterWindow)
};
+
+StandalonePluginHolder* StandalonePluginHolder::getInstance()
+{
+ #if JucePlugin_Enable_IAA || JucePlugin_Build_STANDALONE
+ if (PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone)
+ {
+ Desktop& desktop (Desktop::getInstance());
+ const int numTopLevelWindows = desktop.getNumComponents();
+
+ for (int i = 0; i < numTopLevelWindows; ++i)
+ if (auto window = dynamic_cast (desktop.getComponent (i)))
+ return window->getPluginHolder();
+ }
+ #endif
+
+ return nullptr;
+}
diff --git a/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h b/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h
index 8e34504fac..935c988986 100644
--- a/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h
+++ b/modules/juce_audio_plugin_client/utility/juce_PluginHostType.h
@@ -169,6 +169,14 @@ public:
return "Unknown";
}
+ //==============================================================================
+ bool isInterAppAudioConnected() const;
+ void switchToHostApplication() const;
+
+ #if JUCE_MODULE_AVAILABLE_juce_gui_basics
+ Image getHostIcon (int size) const;
+ #endif
+
//==============================================================================
static String getHostPath()
{
diff --git a/modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp b/modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp
index 80afc6c3f6..dea2574436 100644
--- a/modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp
+++ b/modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp
@@ -149,6 +149,15 @@ bool JUCE_API handleManufacturerSpecificVST2Opcode (int32 index, pointer_sized_i
*/
extern AudioProcessor* JUCE_CALLTYPE createPluginFilter();
+#if JucePlugin_Enable_IAA && JucePlugin_Build_STANDALONE && JUCE_IOS && (! JUCE_USE_CUSTOM_AU3_STANDALONE_APP)
+extern bool JUCE_CALLTYPE juce_isInterAppAudioConnected();
+extern void JUCE_CALLTYPE juce_switchToHostApplication();
+
+#if JUCE_MODULE_AVAILABLE_juce_gui_basics
+extern Image JUCE_CALLTYPE juce_getIAAHostIcon (int);
+#endif
+#endif
+
AudioProcessor* JUCE_API JUCE_CALLTYPE createPluginFilterOfType (AudioProcessor::WrapperType type)
{
AudioProcessor::setTypeOfNextNewPlugin (type);
@@ -160,3 +169,46 @@ AudioProcessor* JUCE_API JUCE_CALLTYPE createPluginFilterOfType (AudioProcessor:
return pluginInstance;
}
+
+bool PluginHostType::isInterAppAudioConnected() const
+{
+ #if JucePlugin_Enable_IAA && JucePlugin_Build_STANDALONE && JUCE_IOS && (! JUCE_USE_CUSTOM_AU3_STANDALONE_APP)
+ if (getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone)
+ return juce_isInterAppAudioConnected();
+ #endif
+
+ return false;
+}
+
+void PluginHostType::switchToHostApplication() const
+{
+ #if JucePlugin_Enable_IAA && JucePlugin_Build_STANDALONE && JUCE_IOS && (! JUCE_USE_CUSTOM_AU3_STANDALONE_APP)
+ if (getPluginLoadedAs() == AudioProcessor::wrapperType_Standalone)
+ juce_switchToHostApplication();
+ #endif
+}
+
+#if JUCE_MODULE_AVAILABLE_juce_gui_basics
+namespace juce {
+
+extern Image JUCE_API getIconFromApplication (const String&, const int);
+
+Image PluginHostType::getHostIcon (int size) const
+{
+ ignoreUnused (size);
+
+ #if JucePlugin_Enable_IAA && JucePlugin_Build_STANDALONE && JUCE_IOS && (! JUCE_USE_CUSTOM_AU3_STANDALONE_APP)
+ if (isInterAppAudioConnected())
+ return juce_getIAAHostIcon (size);
+ #endif
+
+ #if JUCE_MAC
+ String bundlePath (getHostPath().upToLastOccurrenceOf (".app", true, true));
+ return getIconFromApplication (bundlePath, size);
+ #endif
+
+ return Image();
+}
+
+}
+#endif
diff --git a/modules/juce_audio_processors/juce_audio_processors.h b/modules/juce_audio_processors/juce_audio_processors.h
index 0ec754fa6a..dcb76df6e4 100644
--- a/modules/juce_audio_processors/juce_audio_processors.h
+++ b/modules/juce_audio_processors/juce_audio_processors.h
@@ -102,7 +102,6 @@ namespace juce
{
class AudioProcessor;
-#include "processors/juce_AudioPlayHead.h"
#include "processors/juce_AudioProcessorEditor.h"
#include "processors/juce_AudioProcessorListener.h"
#include "processors/juce_AudioProcessorParameter.h"
diff --git a/modules/juce_graphics/image_formats/juce_JPEGLoader.cpp b/modules/juce_graphics/image_formats/juce_JPEGLoader.cpp
index cf32f3a546..4c4e0c3da8 100644
--- a/modules/juce_graphics/image_formats/juce_JPEGLoader.cpp
+++ b/modules/juce_graphics/image_formats/juce_JPEGLoader.cpp
@@ -223,13 +223,23 @@ bool JPEGImageFormat::usesFileExtension (const File& f) { return f.hasFileExte
bool JPEGImageFormat::canUnderstand (InputStream& in)
{
- const int bytesNeeded = 10;
+ const int bytesNeeded = 24;
uint8 header [bytesNeeded];
- return in.read (header, bytesNeeded) == bytesNeeded
+ if (in.read (header, bytesNeeded) == bytesNeeded
&& header[0] == 0xff
&& header[1] == 0xd8
- && header[2] == 0xff;
+ && header[2] == 0xff)
+ return true;
+
+ #if JUCE_USING_COREIMAGE_LOADER
+ return header[20] == 'j'
+ && header[21] == 'p'
+ && header[22] == '2'
+ && header[23] == ' ';
+ #endif
+
+ return false;
}
#if JUCE_USING_COREIMAGE_LOADER
diff --git a/modules/juce_graphics/juce_graphics.cpp b/modules/juce_graphics/juce_graphics.cpp
index 50a5d3f151..84dbe01e4f 100644
--- a/modules/juce_graphics/juce_graphics.cpp
+++ b/modules/juce_graphics/juce_graphics.cpp
@@ -144,21 +144,25 @@ namespace juce
#if JUCE_MAC || JUCE_IOS
#include "native/juce_mac_Fonts.mm"
#include "native/juce_mac_CoreGraphicsContext.mm"
+ #include "native/juce_mac_IconHelpers.cpp"
#elif JUCE_WINDOWS
#include "native/juce_win32_DirectWriteTypeface.cpp"
#include "native/juce_win32_DirectWriteTypeLayout.cpp"
#include "native/juce_win32_Fonts.cpp"
+ #include "native/juce_win32_IconHelpers.cpp"
#if JUCE_DIRECT2D
#include "native/juce_win32_Direct2DGraphicsContext.cpp"
#endif
#elif JUCE_LINUX
#include "native/juce_linux_Fonts.cpp"
+ #include "native/juce_linux_IconHelpers.cpp"
#elif JUCE_ANDROID
#include "native/juce_android_GraphicsContext.cpp"
#include "native/juce_android_Fonts.cpp"
+ #include "native/juce_android_IconHelpers.cpp"
#endif
}
diff --git a/modules/juce_graphics/juce_graphics.h b/modules/juce_graphics/juce_graphics.h
index 3a4f630d7c..c4b5defb43 100644
--- a/modules/juce_graphics/juce_graphics.h
+++ b/modules/juce_graphics/juce_graphics.h
@@ -41,7 +41,7 @@
dependencies: juce_events
OSXFrameworks: Cocoa QuartzCore
- iOSFrameworks: CoreGraphics CoreText QuartzCore
+ iOSFrameworks: CoreGraphics CoreImage CoreText QuartzCore
linuxPackages: x11 xinerama xext freetype2
END_JUCE_MODULE_DECLARATION
diff --git a/modules/juce_graphics/native/juce_android_IconHelpers.cpp b/modules/juce_graphics/native/juce_android_IconHelpers.cpp
new file mode 100644
index 0000000000..2fffd5e192
--- /dev/null
+++ b/modules/juce_graphics/native/juce_android_IconHelpers.cpp
@@ -0,0 +1,28 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library.
+ Copyright (c) 2017 - ROLI Ltd.
+
+ Permission is granted to use this software under the terms of either:
+ a) the GPL v2 (or any later version)
+ b) the Affero GPL v3
+
+ Details of these licenses can be found at: www.gnu.org/licenses
+
+ 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.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.juce.com for more information.
+
+ ==============================================================================
+*/
+
+Image JUCE_API getIconFromApplication (const String&, const int)
+{
+ return Image();
+}
diff --git a/modules/juce_graphics/native/juce_linux_IconHelpers.cpp b/modules/juce_graphics/native/juce_linux_IconHelpers.cpp
new file mode 100644
index 0000000000..2fffd5e192
--- /dev/null
+++ b/modules/juce_graphics/native/juce_linux_IconHelpers.cpp
@@ -0,0 +1,28 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library.
+ Copyright (c) 2017 - ROLI Ltd.
+
+ Permission is granted to use this software under the terms of either:
+ a) the GPL v2 (or any later version)
+ b) the Affero GPL v3
+
+ Details of these licenses can be found at: www.gnu.org/licenses
+
+ 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.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.juce.com for more information.
+
+ ==============================================================================
+*/
+
+Image JUCE_API getIconFromApplication (const String&, const int)
+{
+ return Image();
+}
diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm
index 957d9cfa26..93fdaf6f0c 100644
--- a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm
+++ b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm
@@ -876,7 +876,6 @@ Image juce_loadWithCoreImage (InputStream& input)
}
#endif
-#if JUCE_MAC
Image juce_createImageFromCIImage (CIImage*, int, int);
Image juce_createImageFromCIImage (CIImage* im, int w, int h)
{
@@ -904,4 +903,16 @@ CGContextRef juce_getImageContext (const Image& image)
return 0;
}
+#if JUCE_IOS
+Image juce_createImageFromUIImage (UIImage* img)
+{
+ CGImageRef image = [img CGImage];
+
+ Image retval (Image::ARGB, (int) CGImageGetWidth (image), (int) CGImageGetHeight (image), true);
+ CGContextRef ctx = juce_getImageContext (retval);
+
+ CGContextDrawImage (ctx, CGRectMake (0.0f, 0.0f, CGImageGetWidth (image), CGImageGetHeight (image)), image);
+
+ return retval;
+}
#endif
diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h b/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h
index e9fdeadad4..9c5551d454 100644
--- a/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h
+++ b/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h
@@ -55,3 +55,7 @@ namespace
extern CGImageRef juce_createCoreGraphicsImage (const Image&, CGColorSpaceRef, bool mustOutliveSource);
extern CGContextRef juce_getImageContext (const Image&);
+
+#if JUCE_IOS
+extern Image juce_createImageFromUIImage (UIImage*);
+#endif
diff --git a/modules/juce_graphics/native/juce_mac_IconHelpers.cpp b/modules/juce_graphics/native/juce_mac_IconHelpers.cpp
new file mode 100644
index 0000000000..a054093e9d
--- /dev/null
+++ b/modules/juce_graphics/native/juce_mac_IconHelpers.cpp
@@ -0,0 +1,135 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library.
+ Copyright (c) 2017 - ROLI Ltd.
+
+ Permission is granted to use this software under the terms of either:
+ a) the GPL v2 (or any later version)
+ b) the Affero GPL v3
+
+ Details of these licenses can be found at: www.gnu.org/licenses
+
+ 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.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.juce.com for more information.
+
+ ==============================================================================
+*/
+
+Image getIconFromIcnsFile (const File& icnsFile, const int size)
+{
+ FileInputStream stream (icnsFile);
+ if (! stream.openedOk())
+ return {};
+
+ const int numHeaderSectionBytes = 4;
+ char headerSection [numHeaderSectionBytes];
+
+ if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes
+ || headerSection[0] != 'i'
+ || headerSection[1] != 'c'
+ || headerSection[2] != 'n'
+ || headerSection[3] != 's')
+ return {};
+
+ if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes)
+ return {};
+
+ const auto dataSize = juce::ByteOrder::bigEndianInt (headerSection);
+ if (dataSize <= 0)
+ return {};
+
+ OwnedArray internalFormats;
+ internalFormats.add (new PNGImageFormat());
+ internalFormats.add (new JPEGImageFormat());
+
+ Array images;
+ auto maxWidth = 0;
+ auto maxWidthIndex = -1;
+
+ while (stream.getPosition() < dataSize)
+ {
+ const auto sectionStart = stream.getPosition();
+
+ if (! stream.setPosition (sectionStart + 4))
+ break;
+
+ if (stream.read (headerSection, numHeaderSectionBytes) != numHeaderSectionBytes)
+ break;
+
+ const auto sectionSize = ByteOrder::bigEndianInt (headerSection);
+ if (sectionSize <= 0)
+ break;
+
+ const auto sectionDataStart = stream.getPosition();
+
+ for (auto* fmt : internalFormats)
+ {
+ if (fmt->canUnderstand (stream))
+ {
+ stream.setPosition (sectionDataStart);
+
+ images.add (fmt->decodeImage (stream));
+
+ const auto lastImageIndex = images.size() - 1;
+ const auto lastWidth = images.getReference (lastImageIndex).getWidth();
+ if (lastWidth > maxWidth)
+ {
+ maxWidthIndex = lastImageIndex;
+ maxWidth = lastWidth;
+ }
+ }
+
+ stream.setPosition (sectionDataStart);
+ }
+
+ stream.setPosition (sectionStart + sectionSize);
+ }
+
+ return maxWidthIndex == -1 ? juce::Image()
+ : images.getReference (maxWidthIndex).rescaled (size, size, Graphics::ResamplingQuality::highResamplingQuality);
+}
+
+Image JUCE_API getIconFromApplication (const String& applicationPath, const int size)
+{
+ Image hostIcon;
+
+ if (CFStringRef pathCFString = CFStringCreateWithCString (kCFAllocatorDefault, applicationPath.toRawUTF8(), kCFStringEncodingUTF8))
+ {
+ if (CFURLRef url = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, pathCFString, kCFURLPOSIXPathStyle, 1))
+ {
+ if (CFBundleRef appBundle = CFBundleCreate (kCFAllocatorDefault, url))
+ {
+ if (CFTypeRef infoValue = CFBundleGetValueForInfoDictionaryKey (appBundle, CFSTR("CFBundleIconFile")))
+ {
+ if (CFGetTypeID (infoValue) == CFStringGetTypeID())
+ {
+ CFStringRef iconFilename = reinterpret_cast (infoValue);
+ CFStringRef resourceURLSuffix = CFStringHasSuffix (iconFilename, CFSTR(".icns")) ? nullptr : CFSTR("icns");
+ if (CFURLRef iconURL = CFBundleCopyResourceURL (appBundle, iconFilename, resourceURLSuffix, nullptr))
+ {
+ if (CFStringRef iconPath = CFURLCopyFileSystemPath (iconURL, kCFURLPOSIXPathStyle))
+ {
+ File icnsFile (CFStringGetCStringPtr (iconPath, CFStringGetSystemEncoding()));
+ hostIcon = getIconFromIcnsFile (icnsFile, size);
+ CFRelease (iconPath);
+ }
+ CFRelease (iconURL);
+ }
+ }
+ }
+ CFRelease (appBundle);
+ }
+ CFRelease (url);
+ }
+ CFRelease (pathCFString);
+ }
+
+ return hostIcon;
+}
diff --git a/modules/juce_graphics/native/juce_win32_IconHelpers.cpp b/modules/juce_graphics/native/juce_win32_IconHelpers.cpp
new file mode 100644
index 0000000000..2fffd5e192
--- /dev/null
+++ b/modules/juce_graphics/native/juce_win32_IconHelpers.cpp
@@ -0,0 +1,28 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library.
+ Copyright (c) 2017 - ROLI Ltd.
+
+ Permission is granted to use this software under the terms of either:
+ a) the GPL v2 (or any later version)
+ b) the Affero GPL v3
+
+ Details of these licenses can be found at: www.gnu.org/licenses
+
+ 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.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.juce.com for more information.
+
+ ==============================================================================
+*/
+
+Image JUCE_API getIconFromApplication (const String&, const int)
+{
+ return Image();
+}