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