@@ -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 << "; "; | attributes << "DevelopmentTeam = " << developmentTeamID << "; "; | ||||
const int inAppPurchasesEnabled = (owner.iOS && owner.isInAppPurchasesEnabled()) ? 1 : 0; | 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); | const int sandboxEnabled = (type == Target::AudioUnitv3PlugIn ? 1 : 0); | ||||
attributes << "SystemCapabilities = {"; | attributes << "SystemCapabilities = {"; | ||||
attributes << "com.apple.InAppPurchase = { enabled = " << inAppPurchasesEnabled << "; }; "; | attributes << "com.apple.InAppPurchase = { enabled = " << inAppPurchasesEnabled << "; }; "; | ||||
attributes << "com.apple.InterAppAudio = { enabled = " << interAppAudioEnabled << "; }; "; | |||||
attributes << "com.apple.Sandbox = { enabled = " << sandboxEnabled << "; }; "; | attributes << "com.apple.Sandbox = { enabled = " << sandboxEnabled << "; }; "; | ||||
attributes << "}; };"; | attributes << "}; };"; | ||||
@@ -953,8 +957,10 @@ public: | |||||
s.add ("SEPARATE_STRIP = YES"); | 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)); | defines = mergePreprocessorDefs (defines, owner.getAllPreprocessorDefs (config, type)); | ||||
@@ -1112,14 +1118,36 @@ public: | |||||
if (owner.settings ["UIStatusBarHidden"] && type != AudioUnitv3PlugIn) | if (owner.settings ["UIStatusBarHidden"] && type != AudioUnitv3PlugIn) | ||||
addPlistDictionaryKeyBool (dict, "UIStatusBarHidden", true); | 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) | for (auto& e : xcodeExtraPListEntries) | ||||
@@ -1500,8 +1528,9 @@ private: | |||||
void addFilesAndGroupsToProject (StringArray& topLevelGroupIDs) const | 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()) | for (auto& group : getAllGroups()) | ||||
if (group.getNumChildren() > 0) | if (group.getNumChildren() > 0) | ||||
@@ -2188,20 +2217,41 @@ private: | |||||
return project.getProjectFilenameRoot() + String (".entitlements"); | 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()); | File entitlementsFile = getTargetFolder().getChildFile (getEntitlementsFileName()); | ||||
overwriteFileIfDifferentOrThrow (entitlementsFile, sandboxEntitlement); | |||||
overwriteFileIfDifferentOrThrow (entitlementsFile, content); | |||||
RelativePath plistPath (entitlementsFile, getTargetFolder(), RelativePath::buildTargetFolder); | RelativePath plistPath (entitlementsFile, getTargetFolder(), RelativePath::buildTargetFolder); | ||||
return addFile (plistPath, false, false, false, false, nullptr); | 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_RTAS", valueToBool (project.getShouldBuildRTASAsValue())); | ||||
flags.set ("JucePlugin_Build_AAX", valueToBool (project.getShouldBuildAAXAsValue())); | flags.set ("JucePlugin_Build_AAX", valueToBool (project.getShouldBuildAAXAsValue())); | ||||
flags.set ("JucePlugin_Build_STANDALONE", valueToBool (project.getShouldBuildStandalonePluginAsValue())); | 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_Name", valueToStringLiteral (project.getPluginName())); | ||||
flags.set ("JucePlugin_Desc", valueToStringLiteral (project.getPluginDesc())); | flags.set ("JucePlugin_Desc", valueToStringLiteral (project.getPluginDesc())); | ||||
flags.set ("JucePlugin_Manufacturer", valueToStringLiteral (project.getPluginManufacturer())); | flags.set ("JucePlugin_Manufacturer", valueToStringLiteral (project.getPluginManufacturer())); | ||||
@@ -114,6 +115,9 @@ void ProjectSaver::writePluginCharacteristicsFile() | |||||
flags.set ("JucePlugin_AAXCategory", project.getPluginAAXCategory().toString()); | flags.set ("JucePlugin_AAXCategory", project.getPluginAAXCategory().toString()); | ||||
flags.set ("JucePlugin_AAXDisableBypass", valueToBool (project.getPluginAAXBypassDisabled())); | flags.set ("JucePlugin_AAXDisableBypass", valueToBool (project.getPluginAAXBypassDisabled())); | ||||
flags.set ("JucePlugin_AAXDisableMultiMono", valueToBool (project.getPluginAAXMultiMonoDisabled())); | 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(); | String plugInChannelConfig = project.getPluginChannelConfigs().toString(); | ||||
@@ -153,6 +153,7 @@ void Project::setMissingAudioPluginDefaultValues() | |||||
setValueIfVoid (getShouldBuildRTASAsValue(), false); | setValueIfVoid (getShouldBuildRTASAsValue(), false); | ||||
setValueIfVoid (getShouldBuildAAXAsValue(), false); | setValueIfVoid (getShouldBuildAAXAsValue(), false); | ||||
setValueIfVoid (getShouldBuildStandalonePluginAsValue(), false); | setValueIfVoid (getShouldBuildStandalonePluginAsValue(), false); | ||||
setValueIfVoid (getShouldEnableIAAAsValue(), false); | |||||
setValueIfVoid (getPluginName(), getTitle()); | setValueIfVoid (getPluginName(), getTitle()); | ||||
setValueIfVoid (getPluginDesc(), getTitle()); | setValueIfVoid (getPluginDesc(), getTitle()); | ||||
@@ -629,6 +630,9 @@ void Project::createAudioPluginPropertyEditors (PropertyListBuilder& props) | |||||
"Whether the project should produce an AAX plugin."); | "Whether the project should produce an AAX plugin."); | ||||
props.add (new BooleanPropertyComponent (getShouldBuildStandalonePluginAsValue(), "Build Standalone Plug-In", "Enabled"), | props.add (new BooleanPropertyComponent (getShouldBuildStandalonePluginAsValue(), "Build Standalone Plug-In", "Enabled"), | ||||
"Whether the project should produce a standalone version of your plugin."); | "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), | props.add (new TextPropertyComponent (getPluginName(), "Plugin Name", 128, false), | ||||
"The name of your plugin (keep it short!)"); | "The name of your plugin (keep it short!)"); | ||||
@@ -1258,6 +1262,34 @@ String Project::getAUMainTypeCode() | |||||
return s; | 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 Project::getPluginVSTCategoryString() | ||||
{ | { | ||||
String s (getPluginVSTCategory().toString().trim()); | String s (getPluginVSTCategory().toString().trim()); | ||||
@@ -130,6 +130,7 @@ public: | |||||
Value getShouldBuildRTASAsValue() { return getProjectValue ("buildRTAS"); } | Value getShouldBuildRTASAsValue() { return getProjectValue ("buildRTAS"); } | ||||
Value getShouldBuildAAXAsValue() { return getProjectValue ("buildAAX"); } | Value getShouldBuildAAXAsValue() { return getProjectValue ("buildAAX"); } | ||||
Value getShouldBuildStandalonePluginAsValue() { return getProjectValue ("buildStandalone");} | Value getShouldBuildStandalonePluginAsValue() { return getProjectValue ("buildStandalone");} | ||||
Value getShouldEnableIAAAsValue() { return getProjectValue ("enableIAA"); } | |||||
bool shouldBuildVST() const { return getProjectVar ("buildVST"); } | bool shouldBuildVST() const { return getProjectVar ("buildVST"); } | ||||
bool shouldBuildVST3() const { return getProjectVar ("buildVST3"); } | bool shouldBuildVST3() const { return getProjectVar ("buildVST3"); } | ||||
@@ -138,6 +139,7 @@ public: | |||||
bool shouldBuildRTAS() const { return getProjectVar ("buildRTAS"); } | bool shouldBuildRTAS() const { return getProjectVar ("buildRTAS"); } | ||||
bool shouldBuildAAX() const { return getProjectVar ("buildAAX"); } | bool shouldBuildAAX() const { return getProjectVar ("buildAAX"); } | ||||
bool shouldBuildStandalonePlugin() const { return getProjectVar ("buildStandalone"); } | bool shouldBuildStandalonePlugin() const { return getProjectVar ("buildStandalone"); } | ||||
bool shouldEnableIAA() const { return getProjectVar ("enableIAA"); } | |||||
//============================================================================== | //============================================================================== | ||||
Value getPluginName() { return getProjectValue ("pluginName"); } | Value getPluginName() { return getProjectValue ("pluginName"); } | ||||
@@ -163,6 +165,8 @@ public: | |||||
String getPluginRTASCategoryCode(); | String getPluginRTASCategoryCode(); | ||||
String getAUMainTypeString(); | String getAUMainTypeString(); | ||||
String getAUMainTypeCode(); | String getAUMainTypeCode(); | ||||
String getIAATypeCode(); | |||||
String getIAAPluginName(); | |||||
String getPluginVSTCategoryString(); | String getPluginVSTCategoryString(); | ||||
bool isAUPluginHost(); | bool isAUPluginHost(); | ||||
@@ -137,4 +137,16 @@ public: | |||||
multithreading issues if it's not called on the audio thread. | multithreading issues if it's not called on the audio thread. | ||||
*/ | */ | ||||
virtual bool getCurrentPosition (CurrentPositionInfo& result) = 0; | 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_ReverbAudioSource.h" | ||||
#include "sources/juce_ToneGeneratorAudioSource.h" | #include "sources/juce_ToneGeneratorAudioSource.h" | ||||
#include "synthesisers/juce_Synthesiser.h" | #include "synthesisers/juce_Synthesiser.h" | ||||
#include "audio_play_head/juce_AudioPlayHead.h" | |||||
} | } |
@@ -182,6 +182,7 @@ namespace juce | |||||
//============================================================================== | //============================================================================== | ||||
#elif JUCE_IOS | #elif JUCE_IOS | ||||
#include "native/juce_ios_Audio.h" | |||||
#include "native/juce_ios_Audio.cpp" | #include "native/juce_ios_Audio.cpp" | ||||
#include "native/juce_mac_CoreMidi.cpp" | #include "native/juce_mac_CoreMidi.cpp" | ||||
@@ -62,6 +62,10 @@ | |||||
#include <juce_events/juce_events.h> | #include <juce_events/juce_events.h> | ||||
#include <juce_audio_basics/juce_audio_basics.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 | /** Config: JUCE_ASIO | ||||
Enables ASIO audio devices (MS Windows only). | Enables ASIO audio devices (MS Windows only). | ||||
@@ -147,12 +151,12 @@ | |||||
namespace juce | 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_MidiInput.h" | ||||
#include "midi_io/juce_MidiMessageCollector.h" | #include "midi_io/juce_MidiMessageCollector.h" | ||||
#include "midi_io/juce_MidiOutput.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_AudioSourcePlayer.h" | ||||
#include "sources/juce_AudioTransportSource.h" | #include "sources/juce_AudioTransportSource.h" | ||||
#include "audio_io/juce_AudioDeviceManager.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); } | #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: | 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) | static void setAudioSessionActive (bool enabled) | ||||
@@ -255,7 +244,7 @@ public: | |||||
return session.sampleRate; | return session.sampleRate; | ||||
} | } | ||||
Array<double> getAvailableSampleRates() override | |||||
Array<double> getAvailableSampleRates() | |||||
{ | { | ||||
Array<double> rates; | Array<double> rates; | ||||
@@ -279,7 +268,7 @@ public: | |||||
rate = jmax (rate, supportedRate); | rate = jmax (rate, supportedRate); | ||||
} | } | ||||
trySampleRate (getCurrentSampleRate()); | |||||
trySampleRate (owner.getCurrentSampleRate()); | |||||
AudioUnitAddPropertyListener (audioUnit, | AudioUnitAddPropertyListener (audioUnit, | ||||
kAudioUnitProperty_StreamFormat, | kAudioUnitProperty_StreamFormat, | ||||
@@ -295,7 +284,7 @@ public: | |||||
return rates; | return rates; | ||||
} | } | ||||
Array<int> getAvailableBufferSizes() override | |||||
Array<int> getAvailableBufferSizes() | |||||
{ | { | ||||
Array<int> r; | Array<int> r; | ||||
@@ -305,43 +294,33 @@ public: | |||||
return r; | return r; | ||||
} | } | ||||
int getDefaultBufferSize() override | |||||
{ | |||||
#if TARGET_IPHONE_SIMULATOR | |||||
return 512; | |||||
#else | |||||
return 256; | |||||
#endif | |||||
} | |||||
String open (const BigInteger& inputChannelsWanted, | String open (const BigInteger& inputChannelsWanted, | ||||
const BigInteger& outputChannelsWanted, | const BigInteger& outputChannelsWanted, | ||||
double targetSampleRate, int bufferSize) override | |||||
double targetSampleRate, int bufferSize) | |||||
{ | { | ||||
close(); | close(); | ||||
lastError.clear(); | |||||
preferredBufferSize = bufferSize <= 0 ? getDefaultBufferSize() | |||||
: bufferSize; | |||||
owner.lastError.clear(); | |||||
owner.preferredBufferSize = bufferSize <= 0 ? owner.getDefaultBufferSize() : bufferSize; | |||||
// xxx set up channel mapping | // 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); | setAudioSessionActive (true); | ||||
// Set the session category & options: | // Set the session category & options: | ||||
auto session = [AVAudioSession sharedInstance]; | auto session = [AVAudioSession sharedInstance]; | ||||
const bool useInputs = (numInputChannels > 0 && audioInputIsAvailable); | |||||
const bool useInputs = (owner.numInputChannels > 0 && owner.audioInputIsAvailable); | |||||
NSString* category = (useInputs ? AVAudioSessionCategoryPlayAndRecord : AVAudioSessionCategoryPlayback); | NSString* category = (useInputs ? AVAudioSessionCategoryPlayAndRecord : AVAudioSessionCategoryPlayback); | ||||
@@ -357,26 +336,26 @@ public: | |||||
// Set the sample rate | // Set the sample rate | ||||
trySampleRate (targetSampleRate); | trySampleRate (targetSampleRate); | ||||
updateSampleRateAndAudioInput(); | |||||
owner.updateSampleRateAndAudioInput(); | |||||
updateCurrentBufferSize(); | updateCurrentBufferSize(); | ||||
prepareFloatBuffers (actualBufferSize); | |||||
prepareFloatBuffers (owner.actualBufferSize); | |||||
isRunning = true; | |||||
owner.isRunning = true; | |||||
handleRouteChange ("Started AudioUnit"); | handleRouteChange ("Started AudioUnit"); | ||||
lastError = (audioUnit != 0 ? "" : "Couldn't open the device"); | |||||
owner.lastError = (audioUnit != 0 ? "" : "Couldn't open the device"); | |||||
setAudioSessionActive (true); | 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) | 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) | if (newCallback != nullptr) | ||||
newCallback->audioDeviceAboutToStart (this); | |||||
newCallback->audioDeviceAboutToStart (&owner); | |||||
const ScopedLock sl (callbackLock); | const ScopedLock sl (callbackLock); | ||||
callback = newCallback; | |||||
owner.callback = newCallback; | |||||
} | } | ||||
} | } | ||||
void stop() override | |||||
void stop() | |||||
{ | { | ||||
if (isRunning) | |||||
if (owner.isRunning) | |||||
{ | { | ||||
AudioIODeviceCallback* lastCallback; | AudioIODeviceCallback* lastCallback; | ||||
{ | { | ||||
const ScopedLock sl (callbackLock); | const ScopedLock sl (callbackLock); | ||||
lastCallback = callback; | |||||
callback = nullptr; | |||||
lastCallback = owner.callback; | |||||
owner.callback = nullptr; | |||||
} | } | ||||
if (lastCallback != 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]; | auto session = [AVAudioSession sharedInstance]; | ||||
@@ -446,12 +410,169 @@ public: | |||||
return session.mode == mode; | 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) | void invokeAudioDeviceErrorCallback (const String& reason) | ||||
{ | { | ||||
const ScopedLock sl (callbackLock); | 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) | void handleStatusChange (bool enabled, const char* reason) | ||||
@@ -460,7 +581,7 @@ public: | |||||
JUCE_IOS_AUDIO_LOG ("handleStatusChange: enabled: " << (int) enabled << ", reason: " << reason); | JUCE_IOS_AUDIO_LOG ("handleStatusChange: enabled: " << (int) enabled << ", reason: " << reason); | ||||
isRunning = enabled; | |||||
owner.isRunning = enabled; | |||||
setAudioSessionActive (enabled); | setAudioSessionActive (enabled); | ||||
if (enabled) | if (enabled) | ||||
@@ -480,10 +601,10 @@ public: | |||||
fixAudioRouteIfSetToReceiver(); | fixAudioRouteIfSetToReceiver(); | ||||
if (isRunning) | |||||
if (owner.isRunning) | |||||
{ | { | ||||
invokeAudioDeviceErrorCallback (reason); | invokeAudioDeviceErrorCallback (reason); | ||||
updateSampleRateAndAudioInput(); | |||||
owner.updateSampleRateAndAudioInput(); | |||||
updateCurrentBufferSize(); | updateCurrentBufferSize(); | ||||
createAudioUnit(); | createAudioUnit(); | ||||
@@ -496,29 +617,72 @@ public: | |||||
AudioOutputUnitStart (audioUnit); | 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: | private: | ||||
//============================================================================== | //============================================================================== | ||||
iOSAudioIODevice& owner; | |||||
SharedResourcePointer<AudioSessionHolder> sessionHolder; | SharedResourcePointer<AudioSessionHolder> sessionHolder; | ||||
CriticalSection callbackLock; | CriticalSection callbackLock; | ||||
NSTimeInterval sampleRate = 0; | |||||
int numInputChannels = 2, numOutputChannels = 2; | |||||
int preferredBufferSize = 0, actualBufferSize = 0; | |||||
bool isRunning = false; | |||||
String lastError; | |||||
AudioStreamBasicDescription format; | AudioStreamBasicDescription format; | ||||
AudioUnit audioUnit {}; | AudioUnit audioUnit {}; | ||||
bool audioInputIsAvailable = false; | |||||
AudioIODeviceCallback* callback = nullptr; | |||||
BigInteger activeOutputChans, activeInputChans; | |||||
AudioSampleBuffer floatData; | AudioSampleBuffer floatData; | ||||
float* inputChannels[3]; | float* inputChannels[3]; | ||||
@@ -527,17 +691,17 @@ private: | |||||
void prepareFloatBuffers (int bufferSize) | 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 (inputChannels, sizeof (inputChannels)); | ||||
zeromem (outputChannels, sizeof (outputChannels)); | zeromem (outputChannels, sizeof (outputChannels)); | ||||
for (int i = 0; i < numInputChannels; ++i) | |||||
for (int i = 0; i < owner.numInputChannels; ++i) | |||||
inputChannels[i] = floatData.getWritePointer (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; | OSStatus err = noErr; | ||||
if (audioInputIsAvailable && numInputChannels > 0) | |||||
if (owner.audioInputIsAvailable && owner.numInputChannels > 0) | |||||
err = AudioUnitRender (audioUnit, flags, time, 1, numFrames, data); | err = AudioUnitRender (audioUnit, flags, time, 1, numFrames, data); | ||||
const ScopedTryLock stl (callbackLock); | const ScopedTryLock stl (callbackLock); | ||||
if (stl.isLocked() && callback != nullptr) | |||||
if (stl.isLocked() && owner.callback != nullptr) | |||||
{ | { | ||||
if ((int) numFrames > floatData.getNumSamples()) | if ((int) numFrames > floatData.getNumSamples()) | ||||
prepareFloatBuffers ((int) numFrames); | prepareFloatBuffers ((int) numFrames); | ||||
if (audioInputIsAvailable && numInputChannels > 0) | |||||
if (owner.audioInputIsAvailable && owner.numInputChannels > 0) | |||||
{ | { | ||||
short* shortData = (short*) data->mBuffers[0].mData; | short* shortData = (short*) data->mBuffers[0].mData; | ||||
if (numInputChannels >= 2) | |||||
if (owner.numInputChannels >= 2) | |||||
{ | { | ||||
for (UInt32 i = 0; i < numFrames; ++i) | for (UInt32 i = 0; i < numFrames; ++i) | ||||
{ | { | ||||
@@ -583,17 +747,17 @@ private: | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
for (int i = numInputChannels; --i >= 0;) | |||||
for (int i = owner.numInputChannels; --i >= 0;) | |||||
zeromem (inputChannels[i], sizeof (float) * numFrames); | 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; | short* const shortData = (short*) data->mBuffers[0].mData; | ||||
int n = 0; | int n = 0; | ||||
if (numOutputChannels >= 2) | |||||
if (owner.numOutputChannels >= 2) | |||||
{ | { | ||||
for (UInt32 i = 0; i < numFrames; ++i) | for (UInt32 i = 0; i < numFrames; ++i) | ||||
{ | { | ||||
@@ -601,7 +765,7 @@ private: | |||||
shortData [n++] = (short) (outputChannels[1][i] * 32767.0f); | shortData [n++] = (short) (outputChannels[1][i] * 32767.0f); | ||||
} | } | ||||
} | } | ||||
else if (numOutputChannels == 1) | |||||
else if (owner.numOutputChannels == 1) | |||||
{ | { | ||||
for (UInt32 i = 0; i < numFrames; ++i) | for (UInt32 i = 0; i < numFrames; ++i) | ||||
{ | { | ||||
@@ -623,25 +787,13 @@ private: | |||||
return err; | 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() | 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 | JUCE_NSERROR_CHECK ([[AVAudioSession sharedInstance] setPreferredIOBufferDuration: bufferDuration | ||||
error: &error]); | error: &error]); | ||||
updateSampleRateAndAudioInput(); | |||||
owner.updateSampleRateAndAudioInput(); | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
@@ -649,7 +801,7 @@ private: | |||||
UInt32 /*busNumber*/, UInt32 numFrames, AudioBufferList* data) | 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) | if (audioUnit == 0) | ||||
return false; | 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; | const UInt32 one = 1; | ||||
AudioUnitSetProperty (audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof (one)); | AudioUnitSetProperty (audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof (one)); | ||||
@@ -721,7 +898,7 @@ private: | |||||
if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, | if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, | ||||
kAudioUnitScope_Global, 0, &framesPerSlice, &dataSize) == noErr | 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)); | prepareFloatBuffers (static_cast<int> (framesPerSlice)); | ||||
} | } | ||||
@@ -731,6 +908,26 @@ private: | |||||
return true; | 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 | // 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. | // to make it loud. Needed because by default when using an input + output, the output is kept quiet. | ||||
static void fixAudioRouteIfSetToReceiver() | static void fixAudioRouteIfSetToReceiver() | ||||
@@ -768,14 +965,14 @@ private: | |||||
0, | 0, | ||||
&desc, | &desc, | ||||
&dataSize); | &dataSize); | ||||
if (desc.mSampleRate != getCurrentSampleRate()) | |||||
if (desc.mSampleRate != owner.getCurrentSampleRate()) | |||||
{ | { | ||||
updateSampleRateAndAudioInput(); | |||||
owner.updateSampleRateAndAudioInput(); | |||||
const ScopedLock sl (callbackLock); | 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) | AudioUnitElement element) | ||||
{ | { | ||||
if (scope == kAudioUnitScope_Output && element == 0) | 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 | 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(); } | - (void)viewDidLayoutSubviews { return cpp->viewDidLayoutSubviews(); } | ||||
@end | @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 | #pragma clang diagnostic pop | ||||
#endif | #endif |
@@ -43,6 +43,10 @@ extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); | |||||
namespace juce | namespace juce | ||||
{ | { | ||||
#if JucePlugin_Enable_IAA && JUCE_IOS | |||||
#include "../../juce_audio_devices/native/juce_ios_Audio.h" | |||||
#endif | |||||
#include "juce_StandaloneFilterWindow.h" | #include "juce_StandaloneFilterWindow.h" | ||||
} | } | ||||
@@ -107,4 +111,31 @@ protected: | |||||
ScopedPointer<StandaloneFilterWindow> mainWindow; | 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 | #endif |
@@ -182,6 +182,14 @@ public: | |||||
void startPlaying() | void startPlaying() | ||||
{ | { | ||||
player.setProcessor (processor); | 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() | 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; | OptionalScopedPointer<PropertySet> settings; | ||||
ScopedPointer<AudioProcessor> processor; | ScopedPointer<AudioProcessor> processor; | ||||
@@ -328,7 +371,6 @@ private: | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StandalonePluginHolder) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StandalonePluginHolder) | ||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
/** | /** | ||||
A class that can be used to run a simple standalone application containing your filter. | 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); | optionsButton.setBounds (8, 6, 60, getTitleBarHeight() - 8); | ||||
} | } | ||||
virtual StandalonePluginHolder* getPluginHolder() { return pluginHolder; } | |||||
ScopedPointer<StandalonePluginHolder> pluginHolder; | ScopedPointer<StandalonePluginHolder> pluginHolder; | ||||
private: | private: | ||||
@@ -489,3 +533,20 @@ private: | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StandaloneFilterWindow) | 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"; | return "Unknown"; | ||||
} | } | ||||
//============================================================================== | |||||
bool isInterAppAudioConnected() const; | |||||
void switchToHostApplication() const; | |||||
#if JUCE_MODULE_AVAILABLE_juce_gui_basics | |||||
Image getHostIcon (int size) const; | |||||
#endif | |||||
//============================================================================== | //============================================================================== | ||||
static String getHostPath() | static String getHostPath() | ||||
{ | { | ||||
@@ -149,6 +149,15 @@ bool JUCE_API handleManufacturerSpecificVST2Opcode (int32 index, pointer_sized_i | |||||
*/ | */ | ||||
extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); | 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* JUCE_API JUCE_CALLTYPE createPluginFilterOfType (AudioProcessor::WrapperType type) | ||||
{ | { | ||||
AudioProcessor::setTypeOfNextNewPlugin (type); | AudioProcessor::setTypeOfNextNewPlugin (type); | ||||
@@ -160,3 +169,46 @@ AudioProcessor* JUCE_API JUCE_CALLTYPE createPluginFilterOfType (AudioProcessor: | |||||
return pluginInstance; | 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; | class AudioProcessor; | ||||
#include "processors/juce_AudioPlayHead.h" | |||||
#include "processors/juce_AudioProcessorEditor.h" | #include "processors/juce_AudioProcessorEditor.h" | ||||
#include "processors/juce_AudioProcessorListener.h" | #include "processors/juce_AudioProcessorListener.h" | ||||
#include "processors/juce_AudioProcessorParameter.h" | #include "processors/juce_AudioProcessorParameter.h" | ||||
@@ -223,13 +223,23 @@ bool JPEGImageFormat::usesFileExtension (const File& f) { return f.hasFileExte | |||||
bool JPEGImageFormat::canUnderstand (InputStream& in) | bool JPEGImageFormat::canUnderstand (InputStream& in) | ||||
{ | { | ||||
const int bytesNeeded = 10; | |||||
const int bytesNeeded = 24; | |||||
uint8 header [bytesNeeded]; | uint8 header [bytesNeeded]; | ||||
return in.read (header, bytesNeeded) == bytesNeeded | |||||
if (in.read (header, bytesNeeded) == bytesNeeded | |||||
&& header[0] == 0xff | && header[0] == 0xff | ||||
&& header[1] == 0xd8 | && 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 | #if JUCE_USING_COREIMAGE_LOADER | ||||
@@ -144,21 +144,25 @@ namespace juce | |||||
#if JUCE_MAC || JUCE_IOS | #if JUCE_MAC || JUCE_IOS | ||||
#include "native/juce_mac_Fonts.mm" | #include "native/juce_mac_Fonts.mm" | ||||
#include "native/juce_mac_CoreGraphicsContext.mm" | #include "native/juce_mac_CoreGraphicsContext.mm" | ||||
#include "native/juce_mac_IconHelpers.cpp" | |||||
#elif JUCE_WINDOWS | #elif JUCE_WINDOWS | ||||
#include "native/juce_win32_DirectWriteTypeface.cpp" | #include "native/juce_win32_DirectWriteTypeface.cpp" | ||||
#include "native/juce_win32_DirectWriteTypeLayout.cpp" | #include "native/juce_win32_DirectWriteTypeLayout.cpp" | ||||
#include "native/juce_win32_Fonts.cpp" | #include "native/juce_win32_Fonts.cpp" | ||||
#include "native/juce_win32_IconHelpers.cpp" | |||||
#if JUCE_DIRECT2D | #if JUCE_DIRECT2D | ||||
#include "native/juce_win32_Direct2DGraphicsContext.cpp" | #include "native/juce_win32_Direct2DGraphicsContext.cpp" | ||||
#endif | #endif | ||||
#elif JUCE_LINUX | #elif JUCE_LINUX | ||||
#include "native/juce_linux_Fonts.cpp" | #include "native/juce_linux_Fonts.cpp" | ||||
#include "native/juce_linux_IconHelpers.cpp" | |||||
#elif JUCE_ANDROID | #elif JUCE_ANDROID | ||||
#include "native/juce_android_GraphicsContext.cpp" | #include "native/juce_android_GraphicsContext.cpp" | ||||
#include "native/juce_android_Fonts.cpp" | #include "native/juce_android_Fonts.cpp" | ||||
#include "native/juce_android_IconHelpers.cpp" | |||||
#endif | #endif | ||||
} | } | ||||
@@ -41,7 +41,7 @@ | |||||
dependencies: juce_events | dependencies: juce_events | ||||
OSXFrameworks: Cocoa QuartzCore | OSXFrameworks: Cocoa QuartzCore | ||||
iOSFrameworks: CoreGraphics CoreText QuartzCore | |||||
iOSFrameworks: CoreGraphics CoreImage CoreText QuartzCore | |||||
linuxPackages: x11 xinerama xext freetype2 | linuxPackages: x11 xinerama xext freetype2 | ||||
END_JUCE_MODULE_DECLARATION | 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 | #endif | ||||
#if JUCE_MAC | |||||
Image juce_createImageFromCIImage (CIImage*, int, int); | Image juce_createImageFromCIImage (CIImage*, int, int); | ||||
Image juce_createImageFromCIImage (CIImage* im, int w, int h) | Image juce_createImageFromCIImage (CIImage* im, int w, int h) | ||||
{ | { | ||||
@@ -904,4 +903,16 @@ CGContextRef juce_getImageContext (const Image& image) | |||||
return 0; | 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 | #endif |
@@ -55,3 +55,7 @@ namespace | |||||
extern CGImageRef juce_createCoreGraphicsImage (const Image&, CGColorSpaceRef, bool mustOutliveSource); | extern CGImageRef juce_createCoreGraphicsImage (const Image&, CGColorSpaceRef, bool mustOutliveSource); | ||||
extern CGContextRef juce_getImageContext (const Image&); | 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(); | |||||
} |