@@ -0,0 +1,62 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
<plist> | |||
<dict> | |||
<key>LSRequiresIPhoneOS</key> | |||
<true/> | |||
<key>NSMicrophoneUsageDescription</key> | |||
<string>This app requires microphone input.</string> | |||
<key>UIViewControllerBasedStatusBarAppearance</key> | |||
<false/> | |||
<key>CFBundleExecutable</key> | |||
<string>${EXECUTABLE_NAME}</string> | |||
<key>CFBundleIdentifier</key> | |||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | |||
<key>CFBundleName</key> | |||
<string>InterAppAudioEffect</string> | |||
<key>CFBundleDisplayName</key> | |||
<string>InterAppAudioEffect</string> | |||
<key>CFBundlePackageType</key> | |||
<string>APPL</string> | |||
<key>CFBundleSignature</key> | |||
<string>????</string> | |||
<key>CFBundleShortVersionString</key> | |||
<string>1.0.0</string> | |||
<key>CFBundleVersion</key> | |||
<string>1.0.0</string> | |||
<key>NSHumanReadableCopyright</key> | |||
<string>ROLI Ltd.</string> | |||
<key>NSHighResolutionCapable</key> | |||
<true/> | |||
<key>UIRequiresFullScreen</key> | |||
<true/> | |||
<key>UIStatusBarHidden</key> | |||
<true/> | |||
<key>UISupportedInterfaceOrientations</key> | |||
<array> | |||
<string>UIInterfaceOrientationPortrait</string> | |||
<string>UIInterfaceOrientationLandscapeLeft</string> | |||
<string>UIInterfaceOrientationLandscapeRight</string> | |||
</array> | |||
<key>UIBackgroundModes</key> | |||
<array> | |||
<string>audio</string> | |||
</array> | |||
<key>AudioComponents</key> | |||
<array> | |||
<dict> | |||
<key>name</key> | |||
<string>ROLI Ltd.: InterAppAudioEffect</string> | |||
<key>manufacturer</key> | |||
<string>ROLI</string> | |||
<key>type</key> | |||
<string>aurx</string> | |||
<key>subtype</key> | |||
<string>IAAE</string> | |||
<key>version</key> | |||
<integer>65536</integer> | |||
</dict> | |||
</array> | |||
</dict> | |||
</plist> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
<plist version="1.0"> | |||
<dict> | |||
<key>inter-app-audio</key> | |||
<true/> | |||
</dict> | |||
</plist> |
@@ -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 = "<group>"; }; | |||
EB371D6195C6398C6F1946EF = {isa = PBXGroup; children = ( | |||
9D54126CE5CE65025DE4742F, ); name = InterAppAudioEffect; sourceTree = "<group>"; }; | |||
3CDCF2D2F9AA23710946CF21 = {isa = PBXGroup; children = ( | |||
CB7EB47782C231D8D6CD52FD, | |||
C6F57BB192F1BC9BE7D82F99, | |||
6E90633D52FCA2BC0B99F9F2, | |||
50724579E5DD043CD53B0C95, | |||
51A5B253018FC02A6AFB7416, | |||
EBA214D367A10FDDC99E8922, | |||
2A2D7663F8BC39E97FF490E3, | |||
54EEC3679EBFF5E6C7B580F1, | |||
78F41A05666E3B38C9FDE9D3, | |||
C1507624A4C7CFDCE375CEB6, | |||
FEBA6F6C0A62E2749D6ACC88, | |||
59469A0541A1B91E7968B8FC, ); name = "Juce Modules"; sourceTree = "<group>"; }; | |||
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 = "<group>"; }; | |||
E1CFC4C60E9EC5DBE60DB32F = {isa = PBXGroup; children = ( | |||
7B37ABD2C5B9FF909250C8DE, | |||
E5A657DE5A5B1516B3E35FA8, ); name = Resources; sourceTree = "<group>"; }; | |||
BF7815807DD5B5FAF4BC3669 = {isa = PBXGroup; children = ( | |||
67BBA32BE9EE1CAF8A105F6A, | |||
E43030B35C6CB127DC67FEE7, | |||
53BB9950BAA9E837613ED83B, | |||
212019C041EE17C23460CE02, | |||
C293562C310CB0B3259811F0, | |||
E4431E84242848EF9D250FC7, | |||
C43FC3A63342AA4CDE8F0906, | |||
AD9B42ED650058295A747510, | |||
F07FA71EC2B5FCA584FAA10B, | |||
41CB50701EE5BFDCE1F89BBA, | |||
B69C94CF64688C5270D8122C, | |||
82F310E23852E0C002F5A2D1, ); name = Frameworks; sourceTree = "<group>"; }; | |||
196E6AA022E8A0902AB15281 = {isa = PBXGroup; children = ( | |||
E9D6BA12BDD1947BDDAE08F7, | |||
873711620EC157BCCFFF80B1, ); name = Products; sourceTree = "<group>"; }; | |||
EC01685A042C62251C5AF093 = {isa = PBXGroup; children = ( | |||
3158E31C9E0DBE333E275FB1, | |||
EB371D6195C6398C6F1946EF, | |||
3CDCF2D2F9AA23710946CF21, | |||
C560791DA1D2E0CA6690BC9E, | |||
E1CFC4C60E9EC5DBE60DB32F, | |||
BF7815807DD5B5FAF4BC3669, | |||
196E6AA022E8A0902AB15281, ); name = Source; sourceTree = "<group>"; }; | |||
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; | |||
} |
@@ -0,0 +1,63 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<JUCERPROJECT id="rgYEL2" name="InterAppAudioEffect" projectType="audioplug" | |||
version="1.0.0" bundleIdentifier="com.yourcompany.InterAppAudioEffect" | |||
includeBinaryInAppConfig="1" buildVST="0" buildVST3="0" buildAU="0" | |||
buildAUv3="0" buildRTAS="0" buildAAX="0" enableIAA="1" pluginName="InterAppAudioEffect" | |||
pluginDesc="InterAppAudioEffect" pluginManufacturer="ROLI Ltd." | |||
pluginManufacturerCode="ROLI" pluginCode="IAAE" pluginChannelConfigs="" | |||
pluginIsSynth="0" pluginWantsMidiIn="0" pluginProducesMidiOut="0" | |||
pluginIsMidiEffectPlugin="0" pluginEditorRequiresKeys="0" pluginAUExportPrefix="InterAppAudioEffectAU" | |||
pluginRTASCategory="" aaxIdentifier="com.yourcompany.InterAppAudioEffect" | |||
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="4.3.1" | |||
companyName="ROLI Ltd." buildStandalone="1"> | |||
<MAINGROUP id="BhTVmm" name="InterAppAudioEffect"> | |||
<GROUP id="{79B2188B-B073-DD2F-F997-AFE1A88B5908}" name="Source"> | |||
<FILE id="s4nZon" name="IAAEffectProcessor.h" compile="0" resource="0" | |||
file="Source/IAAEffectProcessor.h"/> | |||
<FILE id="yg8oqf" name="IAAEffectProcessor.cpp" compile="1" resource="0" | |||
file="Source/IAAEffectProcessor.cpp"/> | |||
<FILE id="CRAxnV" name="IAAEffectEditor.h" compile="0" resource="0" | |||
file="Source/IAAEffectEditor.h"/> | |||
<FILE id="xALLmD" name="SimpleMeter.h" compile="0" resource="0" file="Source/SimpleMeter.h"/> | |||
</GROUP> | |||
</MAINGROUP> | |||
<EXPORTFORMATS> | |||
<XCODE_IPHONE targetFolder="Builds/iOS" iosScreenOrientation="portraitlandscape" | |||
microphonePermissionNeeded="1" iosBackgroundAudio="1" extraCompilerFlags="-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"> | |||
<CONFIGURATIONS> | |||
<CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="InterAppAudioEffect"/> | |||
<CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="InterAppAudioEffect"/> | |||
</CONFIGURATIONS> | |||
<MODULEPATHS> | |||
<MODULEPATH id="juce_core" path="../../../modules"/> | |||
<MODULEPATH id="juce_events" path="../../../modules"/> | |||
<MODULEPATH id="juce_graphics" path="../../../modules"/> | |||
<MODULEPATH id="juce_gui_basics" path="../../../modules"/> | |||
<MODULEPATH id="juce_audio_basics" path="../../../modules"/> | |||
<MODULEPATH id="juce_audio_devices" path="../../../modules"/> | |||
<MODULEPATH id="juce_audio_formats" path="../../../modules"/> | |||
<MODULEPATH id="juce_audio_processors" path="../../../modules"/> | |||
<MODULEPATH id="juce_audio_plugin_client" path="../../../modules"/> | |||
<MODULEPATH id="juce_audio_utils" path="../../../modules"/> | |||
<MODULEPATH id="juce_data_structures" path="../../../modules"/> | |||
<MODULEPATH id="juce_gui_extra" path="../../../modules"/> | |||
</MODULEPATHS> | |||
</XCODE_IPHONE> | |||
</EXPORTFORMATS> | |||
<MODULES> | |||
<MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_audio_devices" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_audio_formats" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_audio_plugin_client" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_audio_processors" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_audio_utils" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_core" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_data_structures" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_events" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_graphics" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_gui_basics" showAllCode="1" useLocalCopy="0"/> | |||
<MODULE id="juce_gui_extra" showAllCode="1" useLocalCopy="0"/> | |||
</MODULES> | |||
<JUCEOPTIONS JUCE_QUICKTIME="disabled"/> | |||
</JUCERPROJECT> |
@@ -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 |
@@ -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 <juce_audio_basics/juce_audio_basics.h> | |||
#include <juce_audio_devices/juce_audio_devices.h> | |||
#include <juce_audio_formats/juce_audio_formats.h> | |||
#include <juce_audio_plugin_client/juce_audio_plugin_client.h> | |||
#include <juce_audio_processors/juce_audio_processors.h> | |||
#include <juce_audio_utils/juce_audio_utils.h> | |||
#include <juce_core/juce_core.h> | |||
#include <juce_data_structures/juce_data_structures.h> | |||
#include <juce_events/juce_events.h> | |||
#include <juce_graphics/juce_graphics.h> | |||
#include <juce_gui_basics/juce_gui_basics.h> | |||
#include <juce_gui_extra/juce_gui_extra.h> | |||
#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 |
@@ -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). |
@@ -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 <juce_audio_basics/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 <juce_audio_basics/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 <juce_audio_devices/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 <juce_audio_devices/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 <juce_audio_formats/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 <juce_audio_formats/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_plugin_client/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 <juce_audio_processors/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 <juce_audio_processors/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 <juce_audio_utils/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 <juce_audio_utils/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 <juce_core/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 <juce_core/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 <juce_data_structures/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 <juce_data_structures/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 <juce_events/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 <juce_events/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 <juce_graphics/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 <juce_graphics/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 <juce_gui_basics/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 <juce_gui_basics/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 <juce_gui_extra/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 <juce_gui_extra/juce_gui_extra.mm> |
@@ -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<int> 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<SimpleMeter, 2> meters; | |||
ImageButton switchToHostButton; | |||
Label transportText, switchToHostButtonLabel; | |||
Image hostImage; | |||
AudioPlayHead::CurrentPositionInfo lastPosInfo; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IAAEffectEditor) | |||
}; | |||
#endif // IAAEFFECTEDITOR_H_INCLUDED |
@@ -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<float> (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<XmlElement> (parameters.state.createXml()); | |||
copyXmlToBinary (*xml, destData); | |||
} | |||
void IAAEffectProcessor::setStateInformation (const void* data, int sizeInBytes) | |||
{ | |||
auto xmlState = std::unique_ptr<XmlElement> (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(); | |||
} |
@@ -0,0 +1,78 @@ | |||
#ifndef PLUGINPROCESSOR_H_INCLUDED | |||
#define PLUGINPROCESSOR_H_INCLUDED | |||
#include "../JuceLibraryCode/JuceHeader.h" | |||
#include <array> | |||
// 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 <float, 2> 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<MeterListener> meterListeners; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IAAEffectProcessor) | |||
}; | |||
#endif // PLUGINPROCESSOR_H_INCLUDED |
@@ -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<float> 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 |
@@ -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 = | |||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | |||
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" | |||
"<plist version=\"1.0\">" | |||
"<dict>" | |||
" <key>com.apple.security.app-sandbox</key>" | |||
" <true/>" | |||
"</dict>" | |||
"</plist>"; | |||
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 = | |||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |||
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" | |||
"<plist version=\"1.0\">\n" | |||
"<dict>\n"; | |||
for (auto& key : keys) | |||
{ | |||
content += "\t<key>" + key + "</key>\n" | |||
"\t<true/>\n"; | |||
} | |||
content += "</dict>\n" | |||
"</plist>\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); | |||
@@ -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(); | |||
@@ -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()); | |||
@@ -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(); | |||
@@ -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() {}; | |||
}; |
@@ -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" | |||
} |
@@ -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" | |||
@@ -62,6 +62,10 @@ | |||
#include <juce_events/juce_events.h> | |||
#include <juce_audio_basics/juce_audio_basics.h> | |||
#if JUCE_MODULE_AVAILABLE_juce_gui_extra | |||
#include <juce_gui_extra/juce_gui_extra.h> | |||
#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" | |||
@@ -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 <juce_graphics/native/juce_mac_CoreGraphicsHelpers.h> | |||
#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<double> getAvailableSampleRates() override | |||
Array<double> getAvailableSampleRates() | |||
{ | |||
Array<double> 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<int> getAvailableBufferSizes() override | |||
Array<int> getAvailableBufferSizes() | |||
{ | |||
Array<int> 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<AudioSessionHolder> 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<iOSAudioIODevice*> (client)->process (flags, time, numFrames, data); | |||
return static_cast<Pimpl*> (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<int> (framesPerSlice) != actualBufferSize) | |||
&& dataSize == sizeof (framesPerSlice) && static_cast<int> (framesPerSlice) != owner.actualBufferSize) | |||
{ | |||
prepareFloatBuffers (static_cast<int> (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<iOSAudioIODevice*> (device)->handleStreamFormatChange(); | |||
static_cast<Pimpl*> (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<Pimpl*> (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<double> iOSAudioIODevice::getAvailableSampleRates() { return pimpl->getAvailableSampleRates(); } | |||
Array<int> 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 | |||
{ | |||
@@ -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<double> getAvailableSampleRates() override; | |||
Array<int> 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> pimpl; | |||
JUCE_DECLARE_NON_COPYABLE (iOSAudioIODevice) | |||
}; |
@@ -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 |
@@ -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<StandaloneFilterWindow> 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 |
@@ -182,6 +182,14 @@ public: | |||
void startPlaying() | |||
{ | |||
player.setProcessor (processor); | |||
#if JucePlugin_Enable_IAA && JUCE_IOS | |||
if (auto device = dynamic_cast<iOSAudioIODevice*> (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<iOSAudioIODevice*> (deviceManager.getCurrentAudioDevice())) | |||
device->switchApplication(); | |||
#endif | |||
} | |||
bool isInterAppAudioConnected() | |||
{ | |||
#if JUCE_IOS | |||
if (auto device = dynamic_cast<iOSAudioIODevice*> (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<iOSAudioIODevice*> (deviceManager.getCurrentAudioDevice())) | |||
return device->getIcon (size); | |||
#else | |||
ignoreUnused (size); | |||
#endif | |||
return Image(); | |||
} | |||
#endif | |||
static StandalonePluginHolder* getInstance(); | |||
//============================================================================== | |||
OptionalScopedPointer<PropertySet> settings; | |||
ScopedPointer<AudioProcessor> 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<StandalonePluginHolder> 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<StandaloneFilterWindow*> (desktop.getComponent (i))) | |||
return window->getPluginHolder(); | |||
} | |||
#endif | |||
return nullptr; | |||
} |
@@ -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() | |||
{ | |||
@@ -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 |
@@ -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" | |||
@@ -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 | |||
@@ -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 | |||
} | |||
@@ -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 | |||
@@ -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(); | |||
} |
@@ -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(); | |||
} |
@@ -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 |
@@ -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 |
@@ -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<juce::ImageFileFormat> internalFormats; | |||
internalFormats.add (new PNGImageFormat()); | |||
internalFormats.add (new JPEGImageFormat()); | |||
Array<Image> 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<CFStringRef> (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; | |||
} |
@@ -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(); | |||
} |