From 2cecf92a0e27f4c117e1ee6ecae5f1fd614eb910 Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 18 Aug 2015 10:16:25 +0100 Subject: [PATCH] Embedded the Apple CoreAudio support files inside the juce_audio_plugin module, so that users no longer need to install or patch these files themselves! --- doxygen/Doxyfile | 1 + .../JuceDemoPlugin.xcodeproj/project.pbxproj | 236 +- .../Source/Project/jucer_AudioPluginModule.h | 89 - .../juce_audio_plugin_client/AU/AUResources.r | 140 + .../AU/CoreAudioUtilityClasses/AUBase.cpp | 2392 +++++++++++++++++ .../AU/CoreAudioUtilityClasses/AUBase.h | 1048 ++++++++ .../AU/CoreAudioUtilityClasses/AUBaseHelper.h | 75 + .../AU/CoreAudioUtilityClasses/AUBuffer.cpp | 219 ++ .../AU/CoreAudioUtilityClasses/AUBuffer.h | 267 ++ .../AUCarbonViewBase.cpp | 403 +++ .../AUCarbonViewBase.h | 188 ++ .../AUCarbonViewControl.cpp | 710 +++++ .../AUCarbonViewControl.h | 230 ++ .../AUCarbonViewDispatch.cpp | 125 + .../AU/CoreAudioUtilityClasses/AUDispatch.cpp | 438 +++ .../AU/CoreAudioUtilityClasses/AUDispatch.h | 82 + .../CoreAudioUtilityClasses/AUEffectBase.cpp | 465 ++++ .../AU/CoreAudioUtilityClasses/AUEffectBase.h | 377 +++ .../AUInputElement.cpp | 151 ++ .../CoreAudioUtilityClasses/AUInputElement.h | 119 + .../AUInputFormatConverter.h | 155 ++ .../AU/CoreAudioUtilityClasses/AUMIDIBase.cpp | 495 ++++ .../AU/CoreAudioUtilityClasses/AUMIDIBase.h | 213 ++ .../AUMIDIEffectBase.cpp | 164 ++ .../AUMIDIEffectBase.h | 104 + .../CoreAudioUtilityClasses/AUOutputBase.cpp | 76 + .../AU/CoreAudioUtilityClasses/AUOutputBase.h | 82 + .../AUOutputElement.cpp | 62 + .../CoreAudioUtilityClasses/AUOutputElement.h | 66 + .../AUPlugInDispatch.cpp | 668 +++++ .../AUPlugInDispatch.h | 144 + .../AUScopeElement.cpp | 565 ++++ .../CoreAudioUtilityClasses/AUScopeElement.h | 553 ++++ .../CoreAudioUtilityClasses/AUSilentTimeout.h | 93 + .../AUTimestampGenerator.h | 163 ++ .../AUViewLocalizedStringKeys.h | 88 + .../CoreAudioUtilityClasses/CAAUParameter.cpp | 400 +++ .../CoreAudioUtilityClasses/CAAUParameter.h | 191 ++ .../AU/CoreAudioUtilityClasses/CAAtomic.h | 305 +++ .../CoreAudioUtilityClasses/CAAtomicStack.h | 239 ++ .../CAAudioChannelLayout.cpp | 153 ++ .../CAAudioChannelLayout.h | 199 ++ .../CoreAudioUtilityClasses/CAAutoDisposer.h | 508 ++++ .../CoreAudioUtilityClasses/CADebugMacros.h | 581 ++++ .../CoreAudioUtilityClasses/CADebugPrintf.h | 115 + .../AU/CoreAudioUtilityClasses/CAException.h | 83 + .../CoreAudioUtilityClasses/CAHostTimeBase.h | 234 ++ .../AU/CoreAudioUtilityClasses/CAMath.h | 68 + .../AU/CoreAudioUtilityClasses/CAMutex.cpp | 345 +++ .../AU/CoreAudioUtilityClasses/CAMutex.h | 163 ++ .../CAReferenceCounted.h | 97 + .../CAStreamBasicDescription.cpp | 879 ++++++ .../CAStreamBasicDescription.h | 424 +++ .../CAThreadSafeList.h | 233 ++ .../CoreAudioUtilityClasses/CAVectorUnit.cpp | 194 ++ .../AU/CoreAudioUtilityClasses/CAVectorUnit.h | 101 + .../CAVectorUnitTypes.h | 60 + .../AU/CoreAudioUtilityClasses/CAXException.h | 361 +++ .../CarbonEventHandler.cpp | 90 + .../CarbonEventHandler.h | 71 + .../CoreAudioUtilityClasses/ComponentBase.cpp | 369 +++ .../CoreAudioUtilityClasses/ComponentBase.h | 353 +++ .../MusicDeviceBase.cpp | 354 +++ .../CoreAudioUtilityClasses/MusicDeviceBase.h | 126 + .../AU/juce_AU_Wrapper.mm | 8 +- .../juce_audio_plugin_client/juce_module_info | 21 + 66 files changed, 18530 insertions(+), 241 deletions(-) create mode 100644 modules/juce_audio_plugin_client/AU/AUResources.r create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBaseHelper.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBuffer.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBuffer.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewBase.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewBase.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewControl.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewControl.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewDispatch.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUDispatch.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUDispatch.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUEffectBase.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUEffectBase.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputElement.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputElement.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputFormatConverter.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIBase.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIBase.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIEffectBase.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIEffectBase.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputBase.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputBase.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputElement.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputElement.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUPlugInDispatch.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUPlugInDispatch.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUScopeElement.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUScopeElement.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUSilentTimeout.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUTimestampGenerator.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUViewLocalizedStringKeys.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAUParameter.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAUParameter.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAtomic.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAtomicStack.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAudioChannelLayout.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAudioChannelLayout.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAutoDisposer.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CADebugMacros.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CADebugPrintf.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAException.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAHostTimeBase.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMath.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMutex.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMutex.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAReferenceCounted.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAStreamBasicDescription.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAStreamBasicDescription.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAThreadSafeList.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnit.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnit.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnitTypes.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAXException.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CarbonEventHandler.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CarbonEventHandler.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/ComponentBase.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/ComponentBase.h create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/MusicDeviceBase.cpp create mode 100644 modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/MusicDeviceBase.h diff --git a/doxygen/Doxyfile b/doxygen/Doxyfile index d05264a0ed..08084575d8 100644 --- a/doxygen/Doxyfile +++ b/doxygen/Doxyfile @@ -806,6 +806,7 @@ EXCLUDE = ../modules/juce_graphics/image_formats \ ../modules/juce_audio_formats/juce_audio_formats.h \ ../modules/juce_audio_formats/juce_audio_formats.cpp \ ../modules/juce_audio_plugin_client/juce_audio_plugin_client.h \ + ../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses \ ../modules/juce_audio_processors/juce_audio_processors.h \ ../modules/juce_audio_processors/juce_audio_processors.cpp \ ../modules/juce_audio_utils/juce_audio_utils.h \ diff --git a/examples/audio plugin demo/Builds/MacOSX/JuceDemoPlugin.xcodeproj/project.pbxproj b/examples/audio plugin demo/Builds/MacOSX/JuceDemoPlugin.xcodeproj/project.pbxproj index 9b66b20864..69eec51047 100644 --- a/examples/audio plugin demo/Builds/MacOSX/JuceDemoPlugin.xcodeproj/project.pbxproj +++ b/examples/audio plugin demo/Builds/MacOSX/JuceDemoPlugin.xcodeproj/project.pbxproj @@ -21,27 +21,26 @@ B003460B11C0B7C1CC07E666 = {isa = PBXBuildFile; fileRef = 0926E36205F4D676343AB6E7; }; 8265E59547F2C5DDD10F58BF = {isa = PBXBuildFile; fileRef = 682D51082D9FE9859F364A10; }; E32999B782F688D3746FEB08 = {isa = PBXBuildFile; fileRef = 9EC0C4C02099C656EEF39DA9; }; - F04FAA69AC50147EA624EC1F = {isa = PBXBuildFile; fileRef = 2B2D54521D69CF4407471A56; settings = {COMPILER_FLAGS = "-w"; }; }; - BE7B7AD7F8A22C21CE836999 = {isa = PBXBuildFile; fileRef = 5E90DDA49E067C3DF60891AA; settings = {COMPILER_FLAGS = "-w"; }; }; - 03978B040325C64F1A301026 = {isa = PBXBuildFile; fileRef = 6A593B7ADFAC09D547EA809D; settings = {COMPILER_FLAGS = "-w"; }; }; - 64CC64872B50899D0C1965A4 = {isa = PBXBuildFile; fileRef = E08045246EF1A84C7A4D9DF5; settings = {COMPILER_FLAGS = "-w"; }; }; - B3C70DEC14A0F3C68BFABAB3 = {isa = PBXBuildFile; fileRef = 5631EA8ECD79655B6BEDF8A3; settings = {COMPILER_FLAGS = "-w"; }; }; - 672ABA87BCE2AC50A10DEC8B = {isa = PBXBuildFile; fileRef = 374740EFBC17343E10F66F4C; settings = {COMPILER_FLAGS = "-w"; }; }; - AAAF1BFC19F4CE7BBD8FA43A = {isa = PBXBuildFile; fileRef = 969CF69D90AC73918B9BB0CD; settings = {COMPILER_FLAGS = "-w"; }; }; - F075907E84874848BF0BB205 = {isa = PBXBuildFile; fileRef = E0A48CA97D4C946F632C0DB7; settings = {COMPILER_FLAGS = "-w"; }; }; - A1AF669E9F10B2BE0FE3ECD8 = {isa = PBXBuildFile; fileRef = 2E19A0C6793FD28085F7A256; settings = {COMPILER_FLAGS = "-w"; }; }; - 64AD03BB3A52EC9E2C030B8E = {isa = PBXBuildFile; fileRef = 0906F59C839873ADC151A188; settings = {COMPILER_FLAGS = "-w"; }; }; - 7B4173581D4B03969E995CA5 = {isa = PBXBuildFile; fileRef = 4A6A465D7BC825BB91F562C3; settings = {COMPILER_FLAGS = "-w"; }; }; - F979285E6636E6CD0669E164 = {isa = PBXBuildFile; fileRef = ED5C52722B9653FA3B009C01; settings = {COMPILER_FLAGS = "-w"; }; }; - 5677D9A2B913014EB1B3E3B3 = {isa = PBXBuildFile; fileRef = 3031159E3E89066250B1D48A; settings = {COMPILER_FLAGS = "-w"; }; }; - C74F334B15AD60AC06A086B7 = {isa = PBXBuildFile; fileRef = 534561E5F94B5D7A093485DF; settings = {COMPILER_FLAGS = "-w"; }; }; - CB8698D8E9F64AD71C0608E4 = {isa = PBXBuildFile; fileRef = A5985F8B03893AA7EFD0273A; settings = {COMPILER_FLAGS = "-w"; }; }; - A5C8DB9F33F2934B307C105C = {isa = PBXBuildFile; fileRef = 3C003D01B67D75E4D745A9B0; settings = {COMPILER_FLAGS = "-w"; }; }; - E42B91C4C0B68D26493D8586 = {isa = PBXBuildFile; fileRef = F7AF91E09A9EB00EA5438730; settings = {COMPILER_FLAGS = "-w"; }; }; - 8DBCF6059F7B99ED17E39C3A = {isa = PBXBuildFile; fileRef = BC369095BAEED8707D12F63B; settings = {COMPILER_FLAGS = "-w"; }; }; - 71BEA1E8715EC77F3BA35BAE = {isa = PBXBuildFile; fileRef = 79B958A028493E0DB0133E2B; settings = {COMPILER_FLAGS = "-w"; }; }; - 4E76293207C599EF3F0E9D66 = {isa = PBXBuildFile; fileRef = 71CDD3C8D311F7994DD5CC8F; settings = {COMPILER_FLAGS = "-w"; }; }; - 899A05A18F62ABBFF66B554E = {isa = PBXBuildFile; fileRef = EFCF0633FF23B5F88112A200; settings = {COMPILER_FLAGS = "-w"; }; }; + 05D1398458CDB00C236D7553 = {isa = PBXBuildFile; fileRef = 3AA0960DF09414DBA0A2255B; settings = {COMPILER_FLAGS = "-w"; }; }; + EDC1CED5C7F88E1142F4A46A = {isa = PBXBuildFile; fileRef = AABC1F4E7D9DA3C6B6DC0F05; settings = {COMPILER_FLAGS = "-w"; }; }; + B02F742C6DE19F5415457993 = {isa = PBXBuildFile; fileRef = 95FF785BAEC4F2799A75D2FF; settings = {COMPILER_FLAGS = "-w"; }; }; + B89DA74BC8384D744F20B8CB = {isa = PBXBuildFile; fileRef = E0657C5A5A08F4B5BE55034A; settings = {COMPILER_FLAGS = "-w"; }; }; + BF903CF8AFDA8D74E3A9D023 = {isa = PBXBuildFile; fileRef = 5DAA9288D1FC19812E6ABA3D; settings = {COMPILER_FLAGS = "-w"; }; }; + 9EDD2E63820FA844B4237F1F = {isa = PBXBuildFile; fileRef = 2051F23DC1B2A76D3B110616; settings = {COMPILER_FLAGS = "-w"; }; }; + 65EF022632E1E7967860DD5E = {isa = PBXBuildFile; fileRef = 88F2FC5C63F1BA3184DC38BD; settings = {COMPILER_FLAGS = "-w"; }; }; + 15885D9F3F3CB8EFDC29A40F = {isa = PBXBuildFile; fileRef = 31E15E7A0FBD027D83A28DFF; settings = {COMPILER_FLAGS = "-w"; }; }; + C9C1F85E79851CE3F2EA0560 = {isa = PBXBuildFile; fileRef = E42198F571F1BB1C5203F3D2; settings = {COMPILER_FLAGS = "-w"; }; }; + 10803DD1A2511511C9A2CEC5 = {isa = PBXBuildFile; fileRef = 739336D279C585C749F3039A; settings = {COMPILER_FLAGS = "-w"; }; }; + EDE82B3320CC03F38226AA50 = {isa = PBXBuildFile; fileRef = B6394C38B7A283DE86213FAE; settings = {COMPILER_FLAGS = "-w"; }; }; + C3C922FB2D069BB6DE3ECAA1 = {isa = PBXBuildFile; fileRef = AFE00126A5FEF419332CD2B9; settings = {COMPILER_FLAGS = "-w"; }; }; + 48D94EBEB2D48D0DCC1394C9 = {isa = PBXBuildFile; fileRef = EB38777DCA28E40FF364EAE1; settings = {COMPILER_FLAGS = "-w"; }; }; + D2B29F3448FA79AB8C47B3D8 = {isa = PBXBuildFile; fileRef = 0D4E3861B5EE21765BDEE2A3; settings = {COMPILER_FLAGS = "-w"; }; }; + D5E7114B2C484F13A51DCBC3 = {isa = PBXBuildFile; fileRef = 28FD98C78FE1E918553D4C3D; settings = {COMPILER_FLAGS = "-w"; }; }; + 9B39F1EE70A26791804DA55E = {isa = PBXBuildFile; fileRef = 87DBD7450AE0FDD762712620; settings = {COMPILER_FLAGS = "-w"; }; }; + 0A7276E46524FC5FD796F27D = {isa = PBXBuildFile; fileRef = 3AA5D4AF03A0689BF8385319; settings = {COMPILER_FLAGS = "-w"; }; }; + 9EA2528254AA35DBDDFEA601 = {isa = PBXBuildFile; fileRef = AC4612F7E064ECEC2E95B129; settings = {COMPILER_FLAGS = "-w"; }; }; + 68B259347BBF52B12FD6900D = {isa = PBXBuildFile; fileRef = E521DD6592FA0F7828161360; settings = {COMPILER_FLAGS = "-w"; }; }; + 91CCE2D40B3D71F3126A1043 = {isa = PBXBuildFile; fileRef = A8BA67A9567A51069D275EBB; settings = {COMPILER_FLAGS = "-w"; }; }; 74CF5671532851FFA52E9D0C = {isa = PBXBuildFile; fileRef = 1BAAB47A9C5B1D76D28FA282; }; E20B98D0BD4CB959779121EF = {isa = PBXBuildFile; fileRef = DCF6DECFAD7F4D907C0458A5; }; BF6B9A47774C03C34559CAFE = {isa = PBXBuildFile; fileRef = 8F59D489139F78A729CED9E5; }; @@ -67,6 +66,7 @@ BCFB9D694F4DD8A76C6B9878 = {isa = PBXBuildFile; fileRef = 8EB324480D60B3E3A81541E5; }; 080999E86692B638CD108D70 = {isa = PBXBuildFile; fileRef = 6CEFF94C7852DB3BFA5E29EB; }; BFD65DA4F2FE24DF532304DA = {isa = PBXBuildFile; fileRef = 7D08D5465E74DF02EA4E7410; }; + A4996F8A30110B5EDB801516 = {isa = PBXBuildFile; fileRef = 1CF9C794D7A955EA89D8B5CB; settings = {COMPILER_FLAGS = "-w"; }; }; 002643D66417E4FFF5CC516A = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MathsFunctions.h"; path = "../../../../modules/juce_core/maths/juce_MathsFunctions.h"; sourceTree = "SOURCE_ROOT"; }; 0045658D26F88B490908C99B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_DirectoryIterator.cpp"; path = "../../../../modules/juce_core/files/juce_DirectoryIterator.cpp"; sourceTree = "SOURCE_ROOT"; }; 00A45583A3FEF005232FE1BE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_UndoManager.cpp"; path = "../../../../modules/juce_data_structures/undomanager/juce_UndoManager.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -108,7 +108,6 @@ 07C4AC0C62F94DDFA1FA0E31 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_mac_CarbonViewWrapperComponent.h"; path = "../../../../modules/juce_gui_extra/native/juce_mac_CarbonViewWrapperComponent.h"; sourceTree = "SOURCE_ROOT"; }; 07FBBCECF4C212D67AD71FFD = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_SpinLock.h"; path = "../../../../modules/juce_core/threads/juce_SpinLock.h"; sourceTree = "SOURCE_ROOT"; }; 080D19E24AE4FDC135F58B86 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ModalComponentManager.h"; path = "../../../../modules/juce_gui_basics/components/juce_ModalComponentManager.h"; sourceTree = "SOURCE_ROOT"; }; - 0906F59C839873ADC151A188 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUMIDIEffectBase.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.cpp; sourceTree = "DEVELOPER_DIR"; }; 090E68CDF051FAE89936CF61 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ActionListener.h"; path = "../../../../modules/juce_events/broadcasters/juce_ActionListener.h"; sourceTree = "SOURCE_ROOT"; }; 0926E36205F4D676343AB6E7 = {isa = PBXFileReference; lastKnownFileType = file.nib; name = RecentFilesMenuTemplate.nib; path = RecentFilesMenuTemplate.nib; sourceTree = "SOURCE_ROOT"; }; 0977400450E451AD1BE80E77 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_FileChooser.cpp"; path = "../../../../modules/juce_gui_basics/native/juce_win32_FileChooser.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -128,6 +127,7 @@ 0CD474E9C69F05868EF8D9EA = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_CommonFile.cpp"; path = "../../../../modules/juce_core/native/juce_linux_CommonFile.cpp"; sourceTree = "SOURCE_ROOT"; }; 0CF861C9A12A38A47B7BC43C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LagrangeInterpolator.h"; path = "../../../../modules/juce_audio_basics/effects/juce_LagrangeInterpolator.h"; sourceTree = "SOURCE_ROOT"; }; 0D06541766ED7D5D99E403C8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DrawableButton.h"; path = "../../../../modules/juce_gui_basics/buttons/juce_DrawableButton.h"; sourceTree = "SOURCE_ROOT"; }; + 0D4E3861B5EE21765BDEE2A3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAAudioChannelLayout.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAudioChannelLayout.cpp"; sourceTree = "SOURCE_ROOT"; }; 0D7BAB3BA700850A464A9F83 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_mac_CoreMidi.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp"; sourceTree = "SOURCE_ROOT"; }; 0E87CC46EB3070AD4D904EF5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CustomTypeface.h"; path = "../../../../modules/juce_graphics/fonts/juce_CustomTypeface.h"; sourceTree = "SOURCE_ROOT"; }; 0ED9A27A7166BC016CB8909C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DrawableComposite.h"; path = "../../../../modules/juce_gui_basics/drawables/juce_DrawableComposite.h"; sourceTree = "SOURCE_ROOT"; }; @@ -137,7 +137,6 @@ 0FFE9DEC94D4019882CE3F85 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Base64.h"; path = "../../../../modules/juce_core/text/juce_Base64.h"; sourceTree = "SOURCE_ROOT"; }; 100EFA05982C05972AC7861B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_audio_processors.mm"; path = "../../../../modules/juce_audio_processors/juce_audio_processors.mm"; sourceTree = "SOURCE_ROOT"; }; 103C7BCDA3ABA3AD615794F0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_TableHeaderComponent.cpp"; path = "../../../../modules/juce_gui_basics/widgets/juce_TableHeaderComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; - 103FA4C6C505052C818A4829 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUTimestampGenerator.h; path = Extras/CoreAudio/AudioUnits/AUPublic/Utility/AUTimestampGenerator.h; sourceTree = "DEVELOPER_DIR"; }; 104CC5F094E0B3D1D3055D04 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioUnitPluginFormat.h"; path = "../../../../modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h"; sourceTree = "SOURCE_ROOT"; }; 10A49DD74F3FB9E69FC989B9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_JPEGLoader.cpp"; path = "../../../../modules/juce_graphics/image_formats/juce_JPEGLoader.cpp"; sourceTree = "SOURCE_ROOT"; }; 10C46E275C321A3974729DA6 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_LookAndFeel_V2.cpp"; path = "../../../../modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -151,7 +150,6 @@ 1345DCB37CEF3DCB146FE70F = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioFormatWriter.h"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.h"; sourceTree = "SOURCE_ROOT"; }; 137EEC7324A15E7724AEB4C7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ImageCache.cpp"; path = "../../../../modules/juce_graphics/images/juce_ImageCache.cpp"; sourceTree = "SOURCE_ROOT"; }; 13EACB731E5573BC68744B5E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioCDReader.cpp"; path = "../../../../modules/juce_audio_devices/audio_cd/juce_AudioCDReader.cpp"; sourceTree = "SOURCE_ROOT"; }; - 141FD2E7828F2F2BE0EE9506 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUInputElement.h; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUInputElement.h; sourceTree = "DEVELOPER_DIR"; }; 1460DF86692852CBB0840F87 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_KeyboardFocusTraverser.cpp"; path = "../../../../modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp"; sourceTree = "SOURCE_ROOT"; }; 14A221649E68BA8FD0EADAE7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_SplashScreen.h"; path = "../../../../modules/juce_gui_extra/misc/juce_SplashScreen.h"; sourceTree = "SOURCE_ROOT"; }; 1519F1DAEF1445EEBC1D75DD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PropertyComponent.cpp"; path = "../../../../modules/juce_gui_basics/properties/juce_PropertyComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -183,7 +181,7 @@ 1BE2A39FBE87B3DA36C02468 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PluginDirectoryScanner.cpp"; path = "../../../../modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp"; sourceTree = "SOURCE_ROOT"; }; 1C7E45B063CBDED867290BE4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LeakedObjectDetector.h"; path = "../../../../modules/juce_core/memory/juce_LeakedObjectDetector.h"; sourceTree = "SOURCE_ROOT"; }; 1CC63825EF38EC63EE2196E1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_PlatformDefs.h"; path = "../../../../modules/juce_core/system/juce_PlatformDefs.h"; sourceTree = "SOURCE_ROOT"; }; - 1D133744B523A61401D587D8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAVectorUnit.h; path = Extras/CoreAudio/PublicUtility/CAVectorUnit.h; sourceTree = "DEVELOPER_DIR"; }; + 1CF9C794D7A955EA89D8B5CB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MusicDeviceBase.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/MusicDeviceBase.cpp"; sourceTree = "SOURCE_ROOT"; }; 1D3A49572FAAB491744428C5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileInputStream.cpp"; path = "../../../../modules/juce_core/files/juce_FileInputStream.cpp"; sourceTree = "SOURCE_ROOT"; }; 1D4AFBEC703C6F373B292D9A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RTAS_Wrapper.cpp"; path = "../../../../modules/juce_audio_plugin_client/RTAS/juce_RTAS_Wrapper.cpp"; sourceTree = "SOURCE_ROOT"; }; 1DBB870CC15ABC104A9AA5C7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AbstractFifo.h"; path = "../../../../modules/juce_core/containers/juce_AbstractFifo.h"; sourceTree = "SOURCE_ROOT"; }; @@ -197,7 +195,7 @@ 1FBFF2D9043296E1E09DE156 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_BigInteger.cpp"; path = "../../../../modules/juce_core/maths/juce_BigInteger.cpp"; sourceTree = "SOURCE_ROOT"; }; 201F62BBDF90DC3F1C9684C3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileOutputStream.cpp"; path = "../../../../modules/juce_core/files/juce_FileOutputStream.cpp"; sourceTree = "SOURCE_ROOT"; }; 2036975FC5AA528303B4E837 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_IPAddress.cpp"; path = "../../../../modules/juce_core/network/juce_IPAddress.cpp"; sourceTree = "SOURCE_ROOT"; }; - 206544B2ADA604E3A68FEF85 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUBuffer.h; path = Extras/CoreAudio/AudioUnits/AUPublic/Utility/AUBuffer.h; sourceTree = "DEVELOPER_DIR"; }; + 2051F23DC1B2A76D3B110616 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUDispatch.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUDispatch.cpp"; sourceTree = "SOURCE_ROOT"; }; 20881BC337B715DEC96E7976 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_module_info"; path = "../../../../modules/juce_audio_formats/juce_module_info"; sourceTree = "SOURCE_ROOT"; }; 20E3F95E25915E7F53F37113 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Colour.cpp"; path = "../../../../modules/juce_graphics/colour/juce_Colour.cpp"; sourceTree = "SOURCE_ROOT"; }; 210FC90993B49F9206A62F02 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Logger.cpp"; path = "../../../../modules/juce_core/logging/juce_Logger.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -219,6 +217,7 @@ 27C9A17C04B5426D28A92DF5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_KeyListener.cpp"; path = "../../../../modules/juce_gui_basics/keyboard/juce_KeyListener.cpp"; sourceTree = "SOURCE_ROOT"; }; 28C68586E6A2C95B2BC007DA = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LowLevelGraphicsSoftwareRenderer.h"; path = "../../../../modules/juce_graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h"; sourceTree = "SOURCE_ROOT"; }; 28F65EEAFB3B971E8EDB10F3 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiscRecording.framework; path = System/Library/Frameworks/DiscRecording.framework; sourceTree = SDKROOT; }; + 28FD98C78FE1E918553D4C3D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAAUParameter.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAUParameter.cpp"; sourceTree = "SOURCE_ROOT"; }; 291947B7C7CCCF7029BA0C78 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileSearchPathListComponent.cpp"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_FileSearchPathListComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; 2956FA046400383FC705C1CE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_WebBrowserComponent.mm"; path = "../../../../modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm"; sourceTree = "SOURCE_ROOT"; }; 29917AAA580F21BF2798D071 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DirectoryContentsDisplayComponent.h"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.h"; sourceTree = "SOURCE_ROOT"; }; @@ -226,12 +225,10 @@ 2A073A793701BE742D5D8CA9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioThumbnailBase.h"; path = "../../../../modules/juce_audio_utils/gui/juce_AudioThumbnailBase.h"; sourceTree = "SOURCE_ROOT"; }; 2AA4939A70E1E1D6B907DA87 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ImageConvolutionKernel.h"; path = "../../../../modules/juce_graphics/images/juce_ImageConvolutionKernel.h"; sourceTree = "SOURCE_ROOT"; }; 2AA92DC1171DAF0BA4BB0E63 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_audio_formats.h"; path = "../../../../modules/juce_audio_formats/juce_audio_formats.h"; sourceTree = "SOURCE_ROOT"; }; - 2B2D54521D69CF4407471A56 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUBase.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUBase.cpp; sourceTree = "DEVELOPER_DIR"; }; 2BEBB7EB22A689648A381ECA = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_TabbedComponent.cpp"; path = "../../../../modules/juce_gui_basics/layout/juce_TabbedComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; 2CAFB89BC62E47429CC04AEA = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_LookAndFeel_V1.cpp"; path = "../../../../modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V1.cpp"; sourceTree = "SOURCE_ROOT"; }; 2D4B766DA1C66FA2857D80F7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RTAS_DigiCode3.cpp"; path = "../../../../modules/juce_audio_plugin_client/RTAS/juce_RTAS_DigiCode3.cpp"; sourceTree = "SOURCE_ROOT"; }; 2D799F4BCA83847DEACB505D = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Info.plist; sourceTree = "SOURCE_ROOT"; }; - 2E19A0C6793FD28085F7A256 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUMIDIBase.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/OtherBases/AUMIDIBase.cpp; sourceTree = "DEVELOPER_DIR"; }; 2E57B46569DAD42A3E53460E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ApplicationCommandInfo.h"; path = "../../../../modules/juce_gui_basics/commands/juce_ApplicationCommandInfo.h"; sourceTree = "SOURCE_ROOT"; }; 2E58109147CCFC780F10C23D = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; }; 2E742E5F322F63D5E8C48C0D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_JSON.cpp"; path = "../../../../modules/juce_core/javascript/juce_JSON.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -242,12 +239,12 @@ 2F7B9CC35EEC12DF96E43229 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ColourGradient.h"; path = "../../../../modules/juce_graphics/colour/juce_ColourGradient.h"; sourceTree = "SOURCE_ROOT"; }; 2FADC0AA0043A3C87DF25E0D = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_IncludeModuleHeaders.h"; path = "../../../../modules/juce_audio_plugin_client/utility/juce_IncludeModuleHeaders.h"; sourceTree = "SOURCE_ROOT"; }; 2FBEA375F39FFA44911F043B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_GZIPCompressorOutputStream.cpp"; path = "../../../../modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp"; sourceTree = "SOURCE_ROOT"; }; - 3031159E3E89066250B1D48A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUScopeElement.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUScopeElement.cpp; sourceTree = "DEVELOPER_DIR"; }; 30351F38509A67AC97C51072 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FillType.cpp"; path = "../../../../modules/juce_graphics/colour/juce_FillType.cpp"; sourceTree = "SOURCE_ROOT"; }; 30789700DDE033623673B969 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ToggleButton.cpp"; path = "../../../../modules/juce_gui_basics/buttons/juce_ToggleButton.cpp"; sourceTree = "SOURCE_ROOT"; }; 318F416CA5367D312EDEB440 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_SelectedItemSet.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_SelectedItemSet.h"; sourceTree = "SOURCE_ROOT"; }; 31ACD81C791C0D6A394B7602 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PropertyPanel.cpp"; path = "../../../../modules/juce_gui_basics/properties/juce_PropertyPanel.cpp"; sourceTree = "SOURCE_ROOT"; }; 31CF7913899F89982EFBFE3E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextLayout.h"; path = "../../../../modules/juce_graphics/fonts/juce_TextLayout.h"; sourceTree = "SOURCE_ROOT"; }; + 31E15E7A0FBD027D83A28DFF = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUInputElement.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputElement.cpp"; sourceTree = "SOURCE_ROOT"; }; 32080C8AC923C34CCE673F1F = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioFormat.h"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormat.h"; sourceTree = "SOURCE_ROOT"; }; 322A19A7DAB9F2840598D2E6 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ApplicationBase.h"; path = "../../../../modules/juce_events/messages/juce_ApplicationBase.h"; sourceTree = "SOURCE_ROOT"; }; 322DE76903F886C1711EB272 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_freetype_Fonts.cpp"; path = "../../../../modules/juce_graphics/native/juce_freetype_Fonts.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -264,9 +261,7 @@ 35F57A1FB7A15A5374251F97 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_GlowEffect.h"; path = "../../../../modules/juce_graphics/effects/juce_GlowEffect.h"; sourceTree = "SOURCE_ROOT"; }; 36EDB9DCF2D5260319028905 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_String.cpp"; path = "../../../../modules/juce_core/text/juce_String.cpp"; sourceTree = "SOURCE_ROOT"; }; 371CABFCE28A273E9150F537 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DrawablePath.h"; path = "../../../../modules/juce_gui_basics/drawables/juce_DrawablePath.h"; sourceTree = "SOURCE_ROOT"; }; - 374740EFBC17343E10F66F4C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUDispatch.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUDispatch.cpp; sourceTree = "DEVELOPER_DIR"; }; 3755479207D218969425F91F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_RTAS_MacUtilities.mm"; path = "../../../../modules/juce_audio_plugin_client/RTAS/juce_RTAS_MacUtilities.mm"; sourceTree = "SOURCE_ROOT"; }; - 375A031244EED3B21A609984 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAStreamBasicDescription.h; path = Extras/CoreAudio/PublicUtility/CAStreamBasicDescription.h; sourceTree = "DEVELOPER_DIR"; }; 376742758A9CEDA05995AF51 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Logger.h"; path = "../../../../modules/juce_core/logging/juce_Logger.h"; sourceTree = "SOURCE_ROOT"; }; 379E6C7C71E680936EF723F4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioDataConverters.h"; path = "../../../../modules/juce_audio_basics/buffers/juce_AudioDataConverters.h"; sourceTree = "SOURCE_ROOT"; }; 37A7FEF55D2A1043B57E076F = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MouseCursor.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_MouseCursor.h"; sourceTree = "SOURCE_ROOT"; }; @@ -280,6 +275,8 @@ 39AD51EB5E59758E6FC4F313 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CPlusPlusCodeTokeniser.h"; path = "../../../../modules/juce_gui_extra/code_editor/juce_CPlusPlusCodeTokeniser.h"; sourceTree = "SOURCE_ROOT"; }; 39D0873583E797FEA1F40BBD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Windowing.cpp"; path = "../../../../modules/juce_gui_basics/native/juce_android_Windowing.cpp"; sourceTree = "SOURCE_ROOT"; }; 3A6A7BBEB5E04AE75D24BAF6 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioCDReader.h"; path = "../../../../modules/juce_audio_devices/audio_cd/juce_AudioCDReader.h"; sourceTree = "SOURCE_ROOT"; }; + 3AA0960DF09414DBA0A2255B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUBase.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.cpp"; sourceTree = "SOURCE_ROOT"; }; + 3AA5D4AF03A0689BF8385319 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CarbonEventHandler.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CarbonEventHandler.cpp"; sourceTree = "SOURCE_ROOT"; }; 3AA84EBD59A4CBE7E32FB0F3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_PluginDescription.h"; path = "../../../../modules/juce_audio_processors/processors/juce_PluginDescription.h"; sourceTree = "SOURCE_ROOT"; }; 3ABB924AB5490C97118B8CE4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_AudioCDBurner.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_win32_AudioCDBurner.cpp"; sourceTree = "SOURCE_ROOT"; }; 3AD4F35998A668F9C4D585B2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RelativeCoordinate.h"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinate.h"; sourceTree = "SOURCE_ROOT"; }; @@ -288,7 +285,6 @@ 3B22E720E83CBDCC315A038F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_InputStream.cpp"; path = "../../../../modules/juce_core/streams/juce_InputStream.cpp"; sourceTree = "SOURCE_ROOT"; }; 3B6F2FAF5ADD1BE0014C7952 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ImageEffectFilter.h"; path = "../../../../modules/juce_graphics/effects/juce_ImageEffectFilter.h"; sourceTree = "SOURCE_ROOT"; }; 3B9EA2905AC4A9924B9AC3FF = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RecentlyOpenedFilesList.h"; path = "../../../../modules/juce_gui_extra/misc/juce_RecentlyOpenedFilesList.h"; sourceTree = "SOURCE_ROOT"; }; - 3C003D01B67D75E4D745A9B0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAMutex.cpp; path = Extras/CoreAudio/PublicUtility/CAMutex.cpp; sourceTree = "DEVELOPER_DIR"; }; 3C00BD826FCACC11EC9CF6D0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PluginListComponent.cpp"; path = "../../../../modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; 3C3B97E53D481B74892572D5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Messaging.cpp"; path = "../../../../modules/juce_events/native/juce_android_Messaging.cpp"; sourceTree = "SOURCE_ROOT"; }; 3C6E8B705C53294638807FC4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_IncludeSystemHeaders.h"; path = "../../../../modules/juce_audio_plugin_client/utility/juce_IncludeSystemHeaders.h"; sourceTree = "SOURCE_ROOT"; }; @@ -305,7 +301,6 @@ 3FE7F76D4D023295BCEC0E65 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ApplicationCommandTarget.h"; path = "../../../../modules/juce_gui_basics/commands/juce_ApplicationCommandTarget.h"; sourceTree = "SOURCE_ROOT"; }; 4010F841656A5089C77590C6 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_InterprocessConnection.h"; path = "../../../../modules/juce_events/interprocess/juce_InterprocessConnection.h"; sourceTree = "SOURCE_ROOT"; }; 40C5B7300EBBF52E3B7FD402 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CriticalSection.h"; path = "../../../../modules/juce_core/threads/juce_CriticalSection.h"; sourceTree = "SOURCE_ROOT"; }; - 416D1E80C31864739829BBD3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MusicDeviceBase.h; path = Extras/CoreAudio/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.h; sourceTree = "DEVELOPER_DIR"; }; 417401D474422540C54F7700 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StretchableLayoutManager.h"; path = "../../../../modules/juce_gui_basics/layout/juce_StretchableLayoutManager.h"; sourceTree = "SOURCE_ROOT"; }; 41EE7512746D88ACB108362B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ToolbarButton.cpp"; path = "../../../../modules/juce_gui_basics/buttons/juce_ToolbarButton.cpp"; sourceTree = "SOURCE_ROOT"; }; 42458330B018CCF81D0931CA = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_PathStrokeType.h"; path = "../../../../modules/juce_graphics/geometry/juce_PathStrokeType.h"; sourceTree = "SOURCE_ROOT"; }; @@ -319,7 +314,6 @@ 44B6E666E32F637DF7823CF2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_MouseCursor.mm"; path = "../../../../modules/juce_gui_basics/native/juce_mac_MouseCursor.mm"; sourceTree = "SOURCE_ROOT"; }; 44DF2CBDEE1E27DBF3FFD639 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Initialisation.h"; path = "../../../../modules/juce_events/messages/juce_Initialisation.h"; sourceTree = "SOURCE_ROOT"; }; 4514B5F7DBC9B5A3E014C4CA = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Point.h"; path = "../../../../modules/juce_graphics/geometry/juce_Point.h"; sourceTree = "SOURCE_ROOT"; }; - 4550EB50BD17ADECC674C83C = {isa = PBXFileReference; lastKnownFileType = file.r; name = AUResources.r; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUResources.r; sourceTree = "DEVELOPER_DIR"; }; 45C2C296C9A745B292F49C65 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Atomic.h"; path = "../../../../modules/juce_core/memory/juce_Atomic.h"; sourceTree = "SOURCE_ROOT"; }; 460FC41A761B1DBEF6DE8C8B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MidiMessageSequence.h"; path = "../../../../modules/juce_audio_basics/midi/juce_MidiMessageSequence.h"; sourceTree = "SOURCE_ROOT"; }; 464FB7FCF24EAA87AE670472 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FileInputSource.h"; path = "../../../../modules/juce_core/streams/juce_FileInputSource.h"; sourceTree = "SOURCE_ROOT"; }; @@ -334,14 +328,12 @@ 4912E679D7789579BDF68CBE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_TextDiff.cpp"; path = "../../../../modules/juce_core/text/juce_TextDiff.cpp"; sourceTree = "SOURCE_ROOT"; }; 499974142017D18C15D5AE2A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioProcessor.cpp"; path = "../../../../modules/juce_audio_processors/processors/juce_AudioProcessor.cpp"; sourceTree = "SOURCE_ROOT"; }; 4999A3C6B9B1FCE2FA75E26B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MemoryOutputStream.cpp"; path = "../../../../modules/juce_core/streams/juce_MemoryOutputStream.cpp"; sourceTree = "SOURCE_ROOT"; }; - 4A6A465D7BC825BB91F562C3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUOutputBase.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/OtherBases/AUOutputBase.cpp; sourceTree = "DEVELOPER_DIR"; }; 4AB9AA07703E3BAE99B586C3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_GroupComponent.cpp"; path = "../../../../modules/juce_gui_basics/layout/juce_GroupComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; 4B01C1EF1219C6405CD9A061 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_WebBrowserComponent.cpp"; path = "../../../../modules/juce_gui_extra/native/juce_linux_WebBrowserComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; 4B13AFACB5B6B81347E6652D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RecentlyOpenedFilesList.cpp"; path = "../../../../modules/juce_gui_extra/misc/juce_RecentlyOpenedFilesList.cpp"; sourceTree = "SOURCE_ROOT"; }; 4B7CE8D596B3F3901B2A7826 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_audio_basics.h"; path = "../../../../modules/juce_audio_basics/juce_audio_basics.h"; sourceTree = "SOURCE_ROOT"; }; 4BDFDEDCF05F480BB99EE8A2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MouseListener.cpp"; path = "../../../../modules/juce_gui_basics/mouse/juce_MouseListener.cpp"; sourceTree = "SOURCE_ROOT"; }; 4BEE40628E4C3581FF774383 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AnimatedAppComponent.cpp"; path = "../../../../modules/juce_gui_extra/misc/juce_AnimatedAppComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; - 4C4DA110B4ABCD9A9CBE93E1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUViewLocalizedStringKeys.h; path = Extras/CoreAudio/AudioUnits/AUPublic/AUViewBase/AUViewLocalizedStringKeys.h; sourceTree = "DEVELOPER_DIR"; }; 4CE2C5B8F3B9176330D7E38D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_NamedPipe.cpp"; path = "../../../../modules/juce_core/network/juce_NamedPipe.cpp"; sourceTree = "SOURCE_ROOT"; }; 4D57626C71E0A81969B64FFD = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioIODeviceType.h"; path = "../../../../modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h"; sourceTree = "SOURCE_ROOT"; }; 4D669F9349F7061E90B1DCDC = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PopupMenu.cpp"; path = "../../../../modules/juce_gui_basics/menus/juce_PopupMenu.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -361,12 +353,10 @@ 50F1E35F917489F92521D617 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ResizableCornerComponent.cpp"; path = "../../../../modules/juce_gui_basics/layout/juce_ResizableCornerComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; 513637A8BE7D94200DCBD1F2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LowLevelGraphicsContext.h"; path = "../../../../modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h"; sourceTree = "SOURCE_ROOT"; }; 513BA2176B24BC61831B58FD = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LookAndFeel_V2.h"; path = "../../../../modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h"; sourceTree = "SOURCE_ROOT"; }; - 519C6BF83160A6B581905C58 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUOutputElement.h; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUOutputElement.h; sourceTree = "DEVELOPER_DIR"; }; 522D22FEB38D52304F01508D = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TooltipClient.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_TooltipClient.h"; sourceTree = "SOURCE_ROOT"; }; 525EF648F69C3D42DA9B06E3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_AudioCDBurner.mm"; path = "../../../../modules/juce_audio_devices/native/juce_mac_AudioCDBurner.mm"; sourceTree = "SOURCE_ROOT"; }; 528C0C08C23994B09945896C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Colours.h"; path = "../../../../modules/juce_graphics/colour/juce_Colours.h"; sourceTree = "SOURCE_ROOT"; }; 52CEDC13A7802C7CD55F01A5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioTransportSource.cpp"; path = "../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp"; sourceTree = "SOURCE_ROOT"; }; - 534561E5F94B5D7A093485DF = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAAudioChannelLayout.cpp; path = Extras/CoreAudio/PublicUtility/CAAudioChannelLayout.cpp; sourceTree = "DEVELOPER_DIR"; }; 534F8743733885F462809C8F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ComponentPeer.cpp"; path = "../../../../modules/juce_gui_basics/windows/juce_ComponentPeer.cpp"; sourceTree = "SOURCE_ROOT"; }; 537D65EF3BBBDFC4651D389D = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 538BF18F9D29A2A60EF6A6CE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_DirectoryContentsDisplayComponent.cpp"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_DirectoryContentsDisplayComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -374,7 +364,6 @@ 5535A6B1099BB113B17C42DF = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_AudioCDReader.mm"; path = "../../../../modules/juce_audio_devices/native/juce_mac_AudioCDReader.mm"; sourceTree = "SOURCE_ROOT"; }; 55607B89BB15CE19B6E397E2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ApplicationProperties.h"; path = "../../../../modules/juce_data_structures/app_properties/juce_ApplicationProperties.h"; sourceTree = "SOURCE_ROOT"; }; 5585BCF8B17AD03D9FB4A32A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MenuBarComponent.cpp"; path = "../../../../modules/juce_gui_basics/menus/juce_MenuBarComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; - 5631EA8ECD79655B6BEDF8A3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUCarbonViewDispatch.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewDispatch.cpp; sourceTree = "DEVELOPER_DIR"; }; 5647736926AE116B8C392630 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ConcertinaPanel.h"; path = "../../../../modules/juce_gui_basics/layout/juce_ConcertinaPanel.h"; sourceTree = "SOURCE_ROOT"; }; 56A295F04B7F248D0A52B878 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_Fonts.mm"; path = "../../../../modules/juce_graphics/native/juce_mac_Fonts.mm"; sourceTree = "SOURCE_ROOT"; }; 56BFD67859B81D9E53F5B727 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_URL.cpp"; path = "../../../../modules/juce_core/network/juce_URL.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -395,15 +384,14 @@ 5B1CD485D0BA99FEA4B09BC6 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BooleanPropertyComponent.h"; path = "../../../../modules/juce_gui_basics/properties/juce_BooleanPropertyComponent.h"; sourceTree = "SOURCE_ROOT"; }; 5B50BE8BDF7AE3C403DEF232 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Colours.cpp"; path = "../../../../modules/juce_graphics/colour/juce_Colours.cpp"; sourceTree = "SOURCE_ROOT"; }; 5BE5D2C8BD79AA4B1D2A24D3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextDiff.h"; path = "../../../../modules/juce_core/text/juce_TextDiff.h"; sourceTree = "SOURCE_ROOT"; }; - 5C407CFD81A7E81FA35D5544 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUSilentTimeout.h; path = Extras/CoreAudio/AudioUnits/AUPublic/Utility/AUSilentTimeout.h; sourceTree = "DEVELOPER_DIR"; }; 5C49246ADF3F5AA9639EF915 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AlertWindow.h"; path = "../../../../modules/juce_gui_basics/windows/juce_AlertWindow.h"; sourceTree = "SOURCE_ROOT"; }; 5C5E3AF3EB9BE171FD53666A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_audio_utils.mm"; path = "../../../../modules/juce_audio_utils/juce_audio_utils.mm"; sourceTree = "SOURCE_ROOT"; }; 5C7825FEE1CBF90AC0E3FE84 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_Messaging.cpp"; path = "../../../../modules/juce_events/native/juce_win32_Messaging.cpp"; sourceTree = "SOURCE_ROOT"; }; 5C9E323856342E63607189B9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FileInputStream.h"; path = "../../../../modules/juce_core/files/juce_FileInputStream.h"; sourceTree = "SOURCE_ROOT"; }; 5CC9E5327AB45BC5E12E7C49 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MACAddress.h"; path = "../../../../modules/juce_core/network/juce_MACAddress.h"; sourceTree = "SOURCE_ROOT"; }; + 5DAA9288D1FC19812E6ABA3D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUCarbonViewDispatch.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewDispatch.cpp"; sourceTree = "SOURCE_ROOT"; }; 5E354B48397B1478736E6F0D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_mac_CoreAudio.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp"; sourceTree = "SOURCE_ROOT"; }; 5E69C0346462512B115AE7BD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ios_Audio.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_ios_Audio.cpp"; sourceTree = "SOURCE_ROOT"; }; - 5E90DDA49E067C3DF60891AA = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUBuffer.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/Utility/AUBuffer.cpp; sourceTree = "DEVELOPER_DIR"; }; 5EA72D1F22006B0CC17B081E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileChooserDialogBox.cpp"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp"; sourceTree = "SOURCE_ROOT"; }; 5EB55A7484EFAF1FE8C5BADD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_DrawablePath.cpp"; path = "../../../../modules/juce_gui_basics/drawables/juce_DrawablePath.cpp"; sourceTree = "SOURCE_ROOT"; }; 5EE4BB25075E3ACDCFCE14D2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Rectangle.h"; path = "../../../../modules/juce_graphics/geometry/juce_Rectangle.h"; sourceTree = "SOURCE_ROOT"; }; @@ -438,7 +426,6 @@ 69BA49B5D5F563FF8918C64C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextDragAndDropTarget.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h"; sourceTree = "SOURCE_ROOT"; }; 6A2DA68C812379D32A014951 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_Files.cpp"; path = "../../../../modules/juce_core/native/juce_win32_Files.cpp"; sourceTree = "SOURCE_ROOT"; }; 6A3C840E1B6CD34CA8C8DB4B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_GroupComponent.h"; path = "../../../../modules/juce_gui_basics/layout/juce_GroupComponent.h"; sourceTree = "SOURCE_ROOT"; }; - 6A593B7ADFAC09D547EA809D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUCarbonViewBase.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.cpp; sourceTree = "DEVELOPER_DIR"; }; 6A72E46DBDCFAD6F7039E739 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_VST3Headers.h"; path = "../../../../modules/juce_audio_processors/format_types/juce_VST3Headers.h"; sourceTree = "SOURCE_ROOT"; }; 6A7D750E4C8BF2580F262F76 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_XMLCodeTokeniser.cpp"; path = "../../../../modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.cpp"; sourceTree = "SOURCE_ROOT"; }; 6AAAA6BD093B9CCD11BC26EC = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ListenerList.h"; path = "../../../../modules/juce_events/broadcasters/juce_ListenerList.h"; sourceTree = "SOURCE_ROOT"; }; @@ -446,14 +433,11 @@ 6C4AD1B0CA254C16E38609DD = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextEditorKeyMapper.h"; path = "../../../../modules/juce_gui_basics/keyboard/juce_TextEditorKeyMapper.h"; sourceTree = "SOURCE_ROOT"; }; 6C5452492262FE01944BE60C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TableHeaderComponent.h"; path = "../../../../modules/juce_gui_basics/widgets/juce_TableHeaderComponent.h"; sourceTree = "SOURCE_ROOT"; }; 6C8619FFBFA374CE3A374481 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MidiMessage.cpp"; path = "../../../../modules/juce_audio_basics/midi/juce_MidiMessage.cpp"; sourceTree = "SOURCE_ROOT"; }; - 6CE9C1799C65E997A35E22CD = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAAUParameter.h; path = Extras/CoreAudio/PublicUtility/CAAUParameter.h; sourceTree = "DEVELOPER_DIR"; }; 6CEFF94C7852DB3BFA5E29EB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_VST3_Wrapper.cpp"; path = "../../../../modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp"; sourceTree = "SOURCE_ROOT"; }; - 6D085AD80CA57F2F8A5C393B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUDispatch.h; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUDispatch.h; sourceTree = "DEVELOPER_DIR"; }; 6DD7B1CA8F5F2857F2210D04 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ImageConvolutionKernel.cpp"; path = "../../../../modules/juce_graphics/images/juce_ImageConvolutionKernel.cpp"; sourceTree = "SOURCE_ROOT"; }; 6E79399429D2A1B149CCB022 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FileBrowserComponent.h"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h"; sourceTree = "SOURCE_ROOT"; }; 6EA0F6E82CE987903D0C7B13 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_WavAudioFormat.cpp"; path = "../../../../modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp"; sourceTree = "SOURCE_ROOT"; }; 6EC7B55CE9A1E68A89CED63D = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ResizableCornerComponent.h"; path = "../../../../modules/juce_gui_basics/layout/juce_ResizableCornerComponent.h"; sourceTree = "SOURCE_ROOT"; }; - 6EDD3878142839D368B64F31 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUEffectBase.h; path = Extras/CoreAudio/AudioUnits/AUPublic/OtherBases/AUEffectBase.h; sourceTree = "DEVELOPER_DIR"; }; 6F381D0C54E869B237830DC7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_CodeDocument.cpp"; path = "../../../../modules/juce_gui_extra/code_editor/juce_CodeDocument.cpp"; sourceTree = "SOURCE_ROOT"; }; 6F3D3E06535036A4B1779FDD = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_NormalisableRange.h"; path = "../../../../modules/juce_core/maths/juce_NormalisableRange.h"; sourceTree = "SOURCE_ROOT"; }; 6F80E669C5CD62B01B4047A0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Button.cpp"; path = "../../../../modules/juce_gui_basics/buttons/juce_Button.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -466,10 +450,8 @@ 70D7F049EE6F03FCF08AFB11 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Label.cpp"; path = "../../../../modules/juce_gui_basics/widgets/juce_Label.cpp"; sourceTree = "SOURCE_ROOT"; }; 71182371710295A8E05E1536 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MP3AudioFormat.h"; path = "../../../../modules/juce_audio_formats/codecs/juce_MP3AudioFormat.h"; sourceTree = "SOURCE_ROOT"; }; 71BDE6A5BAEA81ACAE4CDC28 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SliderPropertyComponent.cpp"; path = "../../../../modules/juce_gui_basics/properties/juce_SliderPropertyComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; - 71CDD3C8D311F7994DD5CC8F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ComponentBase.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/ComponentBase.cpp; sourceTree = "DEVELOPER_DIR"; }; 71D1E59DD8BD9FAFF42659AF = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MidiFile.cpp"; path = "../../../../modules/juce_audio_basics/midi/juce_MidiFile.cpp"; sourceTree = "SOURCE_ROOT"; }; 7224CC95ABFD72D07AEC0A9D = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ToolbarItemFactory.h"; path = "../../../../modules/juce_gui_basics/widgets/juce_ToolbarItemFactory.h"; sourceTree = "SOURCE_ROOT"; }; - 728F423CEB1B9E6CA8545895 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUOutputBase.h; path = Extras/CoreAudio/AudioUnits/AUPublic/OtherBases/AUOutputBase.h; sourceTree = "DEVELOPER_DIR"; }; 72C93E5C4D67FBDA352C4F08 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_DocumentWindow.cpp"; path = "../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.cpp"; sourceTree = "SOURCE_ROOT"; }; 732FA0A6EBB881C0D5085541 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_EdgeTable.h"; path = "../../../../modules/juce_graphics/geometry/juce_EdgeTable.h"; sourceTree = "SOURCE_ROOT"; }; 733D78081DDEDCBA60B26614 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioProcessorListener.h"; path = "../../../../modules/juce_audio_processors/processors/juce_AudioProcessorListener.h"; sourceTree = "SOURCE_ROOT"; }; @@ -477,11 +459,11 @@ 736524AA87397E0C2C9C8817 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MidiMessageCollector.h"; path = "../../../../modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.h"; sourceTree = "SOURCE_ROOT"; }; 7368195ADDFA8909053F98D4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_osx_ObjCHelpers.h"; path = "../../../../modules/juce_core/native/juce_osx_ObjCHelpers.h"; sourceTree = "SOURCE_ROOT"; }; 7368B0046A2F265498F9DD5E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_KeyMappingEditorComponent.h"; path = "../../../../modules/juce_gui_extra/misc/juce_KeyMappingEditorComponent.h"; sourceTree = "SOURCE_ROOT"; }; + 739336D279C585C749F3039A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUMIDIEffectBase.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIEffectBase.cpp"; sourceTree = "SOURCE_ROOT"; }; 745D6A06B95F8E9CAFBB0CC8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioProcessorPlayer.cpp"; path = "../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp"; sourceTree = "SOURCE_ROOT"; }; 74BB4F18BE439D41BFBA36A7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Line.h"; path = "../../../../modules/juce_graphics/geometry/juce_Line.h"; sourceTree = "SOURCE_ROOT"; }; 74BD335259545B5C8FAE3942 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BorderSize.h"; path = "../../../../modules/juce_graphics/geometry/juce_BorderSize.h"; sourceTree = "SOURCE_ROOT"; }; 74F2DCF770F5C64372FD4247 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AiffAudioFormat.cpp"; path = "../../../../modules/juce_audio_formats/codecs/juce_AiffAudioFormat.cpp"; sourceTree = "SOURCE_ROOT"; }; - 74F64B7ADDA82099E04331FF = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ComponentBase.h; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/ComponentBase.h; sourceTree = "DEVELOPER_DIR"; }; 750F3B1989AEC12FF245BE70 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginEditor.h; path = ../../Source/PluginEditor.h; sourceTree = "SOURCE_ROOT"; }; 753D44FB980D9BAD93995C1C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioProcessorParameter.h"; path = "../../../../modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h"; sourceTree = "SOURCE_ROOT"; }; 7541F65B3F7500294E6F528F = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_PropertySet.h"; path = "../../../../modules/juce_core/containers/juce_PropertySet.h"; sourceTree = "SOURCE_ROOT"; }; @@ -500,12 +482,10 @@ 78959840E3EF9DC06998BB42 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_Fonts.cpp"; path = "../../../../modules/juce_graphics/native/juce_win32_Fonts.cpp"; sourceTree = "SOURCE_ROOT"; }; 7997E4EB2706B00B44880412 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_gui_extra.h"; path = "../../../../modules/juce_gui_extra/juce_gui_extra.h"; sourceTree = "SOURCE_ROOT"; }; 79B3B7E2DD82AB16C411D9E0 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_module_info"; path = "../../../../modules/juce_graphics/juce_module_info"; sourceTree = "SOURCE_ROOT"; }; - 79B958A028493E0DB0133E2B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAVectorUnit.cpp; path = Extras/CoreAudio/PublicUtility/CAVectorUnit.cpp; sourceTree = "DEVELOPER_DIR"; }; 7A1CD659BB507996CC7EE951 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AnimatedAppComponent.h"; path = "../../../../modules/juce_gui_extra/misc/juce_AnimatedAppComponent.h"; sourceTree = "SOURCE_ROOT"; }; 7A56C13F02DFBCBC0375F0F2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_curl_Network.cpp"; path = "../../../../modules/juce_core/native/juce_curl_Network.cpp"; sourceTree = "SOURCE_ROOT"; }; 7AC8B40A09251FDC9D75053A = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_GZIPCompressorOutputStream.h"; path = "../../../../modules/juce_core/zip/juce_GZIPCompressorOutputStream.h"; sourceTree = "SOURCE_ROOT"; }; 7B2A0D30289D548DCF3AC985 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PropertiesFile.cpp"; path = "../../../../modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp"; sourceTree = "SOURCE_ROOT"; }; - 7B491514CCDB29EBB9674F9E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CADebugMacros.h; path = Extras/CoreAudio/PublicUtility/CADebugMacros.h; sourceTree = "DEVELOPER_DIR"; }; 7B7DC20A834735F004A8A0C0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ColourSelector.cpp"; path = "../../../../modules/juce_gui_extra/misc/juce_ColourSelector.cpp"; sourceTree = "SOURCE_ROOT"; }; 7B870EE6D43B984CADE69C28 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CarbonVisibility.h"; path = "../../../../modules/juce_audio_plugin_client/utility/juce_CarbonVisibility.h"; sourceTree = "SOURCE_ROOT"; }; 7C6A0C6C2914BD052CB4702A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_DragAndDropContainer.cpp"; path = "../../../../modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -560,8 +540,10 @@ 8718970FF3F3F2AC38191F53 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TabbedComponent.h"; path = "../../../../modules/juce_gui_basics/layout/juce_TabbedComponent.h"; sourceTree = "SOURCE_ROOT"; }; 87755AF25BF68EE19666A135 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_graphics.mm"; path = "../../../../modules/juce_graphics/juce_graphics.mm"; sourceTree = "SOURCE_ROOT"; }; 87BE12FCBC4C554059FA344F = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioPluginFormat.h"; path = "../../../../modules/juce_audio_processors/format/juce_AudioPluginFormat.h"; sourceTree = "SOURCE_ROOT"; }; + 87DBD7450AE0FDD762712620 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAMutex.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMutex.cpp"; sourceTree = "SOURCE_ROOT"; }; 87FA97D4268B5DAE05BAD596 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CompilerSupport.h"; path = "../../../../modules/juce_core/system/juce_CompilerSupport.h"; sourceTree = "SOURCE_ROOT"; }; 88336AF4E2605BF6518D758B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MessageManager.h"; path = "../../../../modules/juce_events/messages/juce_MessageManager.h"; sourceTree = "SOURCE_ROOT"; }; + 88F2FC5C63F1BA3184DC38BD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUEffectBase.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUEffectBase.cpp"; sourceTree = "SOURCE_ROOT"; }; 890AA995A158C4D9E7738A40 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioSampleBuffer.h"; path = "../../../../modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h"; sourceTree = "SOURCE_ROOT"; }; 8916485BFFBA840EF46760CC = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CodeDocument.h"; path = "../../../../modules/juce_gui_extra/code_editor/juce_CodeDocument.h"; sourceTree = "SOURCE_ROOT"; }; 894982322611830C62233292 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_PositionableAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_PositionableAudioSource.h"; sourceTree = "SOURCE_ROOT"; }; @@ -571,7 +553,6 @@ 89E2E6BA6057311E66E8A8BF = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ArrayAllocationBase.h"; path = "../../../../modules/juce_core/containers/juce_ArrayAllocationBase.h"; sourceTree = "SOURCE_ROOT"; }; 8AE97D16E9DA460011B379BA = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DropShadower.h"; path = "../../../../modules/juce_gui_basics/misc/juce_DropShadower.h"; sourceTree = "SOURCE_ROOT"; }; 8AEC8C684E53D6E14FC97605 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_win32_HiddenMessageWindow.h"; path = "../../../../modules/juce_events/native/juce_win32_HiddenMessageWindow.h"; sourceTree = "SOURCE_ROOT"; }; - 8B184C08A51AA14F56E42152 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUBase.h; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUBase.h; sourceTree = "DEVELOPER_DIR"; }; 8BBD921B5A82DB52E6842A1B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ScopedPointer.h"; path = "../../../../modules/juce_core/memory/juce_ScopedPointer.h"; sourceTree = "SOURCE_ROOT"; }; 8C0D1A1E000E47D09B771963 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PluginUtilities.cpp"; path = "../../../../modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp"; sourceTree = "SOURCE_ROOT"; }; 8C1A068D665727680931F85C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_UndoManager.h"; path = "../../../../modules/juce_data_structures/undomanager/juce_UndoManager.h"; sourceTree = "SOURCE_ROOT"; }; @@ -615,9 +596,9 @@ 93F82D964A8C329766946277 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_mac_CoreGraphicsContext.h"; path = "../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h"; sourceTree = "SOURCE_ROOT"; }; 94AA9AF4939F914AD00CEE1F = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CheckSettingMacros.h"; path = "../../../../modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h"; sourceTree = "SOURCE_ROOT"; }; 94D07EE2982807A4BB2E0CBB = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ChildProcess.h"; path = "../../../../modules/juce_core/threads/juce_ChildProcess.h"; sourceTree = "SOURCE_ROOT"; }; + 95FF785BAEC4F2799A75D2FF = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUCarbonViewBase.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewBase.cpp"; sourceTree = "SOURCE_ROOT"; }; 963140B9984908CF118F92F1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ResizableWindow.h"; path = "../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h"; sourceTree = "SOURCE_ROOT"; }; 965F7DCC8CF46085A636D851 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Desktop.cpp"; path = "../../../../modules/juce_gui_basics/components/juce_Desktop.cpp"; sourceTree = "SOURCE_ROOT"; }; - 969CF69D90AC73918B9BB0CD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUEffectBase.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/OtherBases/AUEffectBase.cpp; sourceTree = "DEVELOPER_DIR"; }; 96C79B505CA4FD6FFDC28D94 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_GlowEffect.cpp"; path = "../../../../modules/juce_graphics/effects/juce_GlowEffect.cpp"; sourceTree = "SOURCE_ROOT"; }; 988CB13161D84307D53770D7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StringPairArray.h"; path = "../../../../modules/juce_core/text/juce_StringPairArray.h"; sourceTree = "SOURCE_ROOT"; }; 990E71F1F4EB7B98AEEE3D05 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentPeer.h"; path = "../../../../modules/juce_gui_basics/windows/juce_ComponentPeer.h"; sourceTree = "SOURCE_ROOT"; }; @@ -625,7 +606,6 @@ 996E86CC90360798D87EE1A0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RelativePoint.h"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativePoint.h"; sourceTree = "SOURCE_ROOT"; }; 99E71BE7C7C30E6BDFAAFA32 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextInputTarget.h"; path = "../../../../modules/juce_gui_basics/keyboard/juce_TextInputTarget.h"; sourceTree = "SOURCE_ROOT"; }; 9A097CC9A7C64CB8958F89B8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Midi.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_android_Midi.cpp"; sourceTree = "SOURCE_ROOT"; }; - 9A1D1CECCBA42358E4E62859 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUCarbonViewBase.h; path = Extras/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.h; sourceTree = "DEVELOPER_DIR"; }; 9A6686BC6FC38F6D1917D7C7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LADSPAPluginFormat.h"; path = "../../../../modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.h"; sourceTree = "SOURCE_ROOT"; }; 9B3F11DD2E09FC8F63555D30 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_audio_devices.mm"; path = "../../../../modules/juce_audio_devices/juce_audio_devices.mm"; sourceTree = "SOURCE_ROOT"; }; 9B7A0A69E4002D6C125F895D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_ALSA.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_linux_ALSA.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -645,24 +625,21 @@ 9F6A1FA82A8C412622129993 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ComponentMovementWatcher.cpp"; path = "../../../../modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp"; sourceTree = "SOURCE_ROOT"; }; 9F9AC54CF90FDB770E5FCA03 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_WeakReference.h"; path = "../../../../modules/juce_core/memory/juce_WeakReference.h"; sourceTree = "SOURCE_ROOT"; }; A0AB27A8CE89B12B37EF8FA4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MP3AudioFormat.cpp"; path = "../../../../modules/juce_audio_formats/codecs/juce_MP3AudioFormat.cpp"; sourceTree = "SOURCE_ROOT"; }; - A10B7B85424CB38AE344D7DC = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAVectorUnitTypes.h; path = Extras/CoreAudio/PublicUtility/CAVectorUnitTypes.h; sourceTree = "DEVELOPER_DIR"; }; A11F51909BE2463C28099C0B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ActiveXControlComponent.h"; path = "../../../../modules/juce_gui_extra/embedding/juce_ActiveXControlComponent.h"; sourceTree = "SOURCE_ROOT"; }; A122A2AB08B82B5AF1FF4D0A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_KnownPluginList.cpp"; path = "../../../../modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp"; sourceTree = "SOURCE_ROOT"; }; A1A74C33F871DF7D5E3C4B65 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RectangleList.h"; path = "../../../../modules/juce_graphics/geometry/juce_RectangleList.h"; sourceTree = "SOURCE_ROOT"; }; A206765795252391D3F60EA4 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; A21E0C7AD5B7950C37912A31 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Variant.cpp"; path = "../../../../modules/juce_core/containers/juce_Variant.cpp"; sourceTree = "SOURCE_ROOT"; }; A2605C2C8D583851AD65025E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ReadWriteLock.h"; path = "../../../../modules/juce_core/threads/juce_ReadWriteLock.h"; sourceTree = "SOURCE_ROOT"; }; - A2BAB9DD00DF8E30A6DF756E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUMIDIBase.h; path = Extras/CoreAudio/AudioUnits/AUPublic/OtherBases/AUMIDIBase.h; sourceTree = "DEVELOPER_DIR"; }; A2F1B4E1DE5CAA9FB76C01B6 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CharPointer_UTF32.h"; path = "../../../../modules/juce_core/text/juce_CharPointer_UTF32.h"; sourceTree = "SOURCE_ROOT"; }; A31CE7177BF947DB60F72D94 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_BubbleMessageComponent.cpp"; path = "../../../../modules/juce_gui_extra/misc/juce_BubbleMessageComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; A52038A2E61AB03CF55A3B0F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_BufferingAudioFormatReader.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp"; sourceTree = "SOURCE_ROOT"; }; - A5985F8B03893AA7EFD0273A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAAUParameter.cpp; path = Extras/CoreAudio/PublicUtility/CAAUParameter.cpp; sourceTree = "DEVELOPER_DIR"; }; A59A08DCC76EE0FC7EBE1203 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; - A62DF2CD31D7890E1B54B18C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUScopeElement.h; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUScopeElement.h; sourceTree = "DEVELOPER_DIR"; }; A722B041FD2540D1380C4D02 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_AudioCDReader.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_linux_AudioCDReader.cpp"; sourceTree = "SOURCE_ROOT"; }; A7A527D783D3B38F455964D4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_InterprocessConnectionServer.h"; path = "../../../../modules/juce_events/interprocess/juce_InterprocessConnectionServer.h"; sourceTree = "SOURCE_ROOT"; }; A7EE73FF3A5962BBF41DC2AB = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Component.h"; path = "../../../../modules/juce_gui_basics/components/juce_Component.h"; sourceTree = "SOURCE_ROOT"; }; A7FD436305E19DF69A7AF446 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_DragAndDrop.cpp"; path = "../../../../modules/juce_gui_basics/native/juce_win32_DragAndDrop.cpp"; sourceTree = "SOURCE_ROOT"; }; + A8BA67A9567A51069D275EBB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ComponentBase.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/ComponentBase.cpp"; sourceTree = "SOURCE_ROOT"; }; A8F3FC233163016FE3B23543 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PathIterator.cpp"; path = "../../../../modules/juce_graphics/geometry/juce_PathIterator.cpp"; sourceTree = "SOURCE_ROOT"; }; A90A45FB8790A91DF1A78BE7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentBuilder.h"; path = "../../../../modules/juce_gui_basics/layout/juce_ComponentBuilder.h"; sourceTree = "SOURCE_ROOT"; }; A90E41C0C52BDF0CC82161C9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_AppleRemote.mm"; path = "../../../../modules/juce_gui_extra/native/juce_mac_AppleRemote.mm"; sourceTree = "SOURCE_ROOT"; }; @@ -672,6 +649,7 @@ A9C466FBA4FCF6484BCF86A2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_VSTMidiEventList.h"; path = "../../../../modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h"; sourceTree = "SOURCE_ROOT"; }; AA29B047C1A1904618B410D5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StretchableObjectResizer.h"; path = "../../../../modules/juce_gui_basics/layout/juce_StretchableObjectResizer.h"; sourceTree = "SOURCE_ROOT"; }; AAA122282581E6425F5D9405 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_OggVorbisAudioFormat.cpp"; path = "../../../../modules/juce_audio_formats/codecs/juce_OggVorbisAudioFormat.cpp"; sourceTree = "SOURCE_ROOT"; }; + AABC1F4E7D9DA3C6B6DC0F05 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUBuffer.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBuffer.cpp"; sourceTree = "SOURCE_ROOT"; }; AB7726FF34DB2E7FA75ECC19 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ToolbarItemComponent.cpp"; path = "../../../../modules/juce_gui_basics/widgets/juce_ToolbarItemComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; AB87317D90A518C8A886EE9D = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioDeviceSelectorComponent.h"; path = "../../../../modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.h"; sourceTree = "SOURCE_ROOT"; }; ABC394D5E03B690404E80E1E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_MessageManager.mm"; path = "../../../../modules/juce_events/native/juce_mac_MessageManager.mm"; sourceTree = "SOURCE_ROOT"; }; @@ -699,8 +677,7 @@ AAEC41BFA57E45EBF94ED3C1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_DrawableImage.cpp"; path = "../../../../modules/juce_gui_basics/drawables/juce_DrawableImage.cpp"; sourceTree = "SOURCE_ROOT"; }; AB0E8347C9AC7E4A861C0252 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_IIRFilterAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_IIRFilterAudioSource.h"; sourceTree = "SOURCE_ROOT"; }; AB10327C69AAE4AACCFC81EB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_DrawableText.cpp"; path = "../../../../modules/juce_gui_basics/drawables/juce_DrawableText.cpp"; sourceTree = "SOURCE_ROOT"; }; - AB7BCFBC4B2CB784F57A0FBC = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUInputFormatConverter.h; path = Extras/CoreAudio/AudioUnits/AUPublic/Utility/AUInputFormatConverter.h; sourceTree = "DEVELOPER_DIR"; }; - AB9AD07EF899B75AC4CF01DA = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAMutex.h; path = Extras/CoreAudio/PublicUtility/CAMutex.h; sourceTree = "DEVELOPER_DIR"; }; + AC4612F7E064ECEC2E95B129 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAStreamBasicDescription.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAStreamBasicDescription.cpp"; sourceTree = "SOURCE_ROOT"; }; AC5452F5122E3A4B670B5185 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioThumbnail.h"; path = "../../../../modules/juce_audio_utils/gui/juce_AudioThumbnail.h"; sourceTree = "SOURCE_ROOT"; }; ACC4E765AD4BF1D025FB4E83 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_Network.cpp"; path = "../../../../modules/juce_core/native/juce_linux_Network.cpp"; sourceTree = "SOURCE_ROOT"; }; ACDF0E99B316A7C266F6EFFD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_LAMEEncoderAudioFormat.cpp"; path = "../../../../modules/juce_audio_formats/codecs/juce_LAMEEncoderAudioFormat.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -709,13 +686,13 @@ AE3C497B58239EA75FD18AD9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_GlyphArrangement.h"; path = "../../../../modules/juce_graphics/fonts/juce_GlyphArrangement.h"; sourceTree = "SOURCE_ROOT"; }; AEE273E29C5B07B96BAFFA46 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ReferenceCountedArray.h"; path = "../../../../modules/juce_core/containers/juce_ReferenceCountedArray.h"; sourceTree = "SOURCE_ROOT"; }; AF14FDB3693F569F275C1A8C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_Files.mm"; path = "../../../../modules/juce_core/native/juce_mac_Files.mm"; sourceTree = "SOURCE_ROOT"; }; + AFE00126A5FEF419332CD2B9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUOutputElement.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputElement.cpp"; sourceTree = "SOURCE_ROOT"; }; B0381BEAE259ABDDE18A64B0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioFormat.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormat.cpp"; sourceTree = "SOURCE_ROOT"; }; B1426528BB892D5736D80404 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RelativeParallelogram.h"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativeParallelogram.h"; sourceTree = "SOURCE_ROOT"; }; B2067C8614967BECF8B198D1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_gui_extra.mm"; path = "../../../../modules/juce_gui_extra/juce_gui_extra.mm"; sourceTree = "SOURCE_ROOT"; }; B23CBCBBD05E21AEA76FB9E8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_PluginDirectoryScanner.h"; path = "../../../../modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.h"; sourceTree = "SOURCE_ROOT"; }; B287E8FA86ED37F618F0ABC2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SubregionStream.cpp"; path = "../../../../modules/juce_core/streams/juce_SubregionStream.cpp"; sourceTree = "SOURCE_ROOT"; }; B2B54E113A80EC53D5D71A38 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_module_info"; path = "../../../../modules/juce_gui_basics/juce_module_info"; sourceTree = "SOURCE_ROOT"; }; - B318D50696B303889BDCF072 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUMIDIEffectBase.h; path = Extras/CoreAudio/AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.h; sourceTree = "DEVELOPER_DIR"; }; B34E109560D77640B7648C4D = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ScopedWriteLock.h"; path = "../../../../modules/juce_core/threads/juce_ScopedWriteLock.h"; sourceTree = "SOURCE_ROOT"; }; B45645B3B2E19FB1D72B91B6 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AiffAudioFormat.h"; path = "../../../../modules/juce_audio_formats/codecs/juce_AiffAudioFormat.h"; sourceTree = "SOURCE_ROOT"; }; B532D9954FB106B6095AE0C8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FilenameComponent.h"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_FilenameComponent.h"; sourceTree = "SOURCE_ROOT"; }; @@ -723,6 +700,7 @@ B57C430D154C1C86350F246A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_CustomTypeface.cpp"; path = "../../../../modules/juce_graphics/fonts/juce_CustomTypeface.cpp"; sourceTree = "SOURCE_ROOT"; }; B57D00796D30ECB2DE58035F = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_module_info"; path = "../../../../modules/juce_audio_utils/juce_module_info"; sourceTree = "SOURCE_ROOT"; }; B5FF7C5554FC26100CB08626 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_FillType.h"; path = "../../../../modules/juce_graphics/colour/juce_FillType.h"; sourceTree = "SOURCE_ROOT"; }; + B6394C38B7A283DE86213FAE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUOutputBase.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputBase.cpp"; sourceTree = "SOURCE_ROOT"; }; B65F0500A687634E095C17E7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MouseInactivityDetector.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.h"; sourceTree = "SOURCE_ROOT"; }; B6938F0B102875B8B0BEBC44 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PreferencesPanel.cpp"; path = "../../../../modules/juce_gui_extra/misc/juce_PreferencesPanel.cpp"; sourceTree = "SOURCE_ROOT"; }; B72762B6ACA5F73EF9F0A220 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_GenericAudioProcessorEditor.cpp"; path = "../../../../modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -737,7 +715,6 @@ BBBE74C4A9FA85B5F29FF346 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ButtonPropertyComponent.cpp"; path = "../../../../modules/juce_gui_basics/properties/juce_ButtonPropertyComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; BBECA9EB9DD3C9B6CB04B10A = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Uuid.h"; path = "../../../../modules/juce_core/misc/juce_Uuid.h"; sourceTree = "SOURCE_ROOT"; }; BBF88983012D33EFEF11EA81 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_Network.cpp"; path = "../../../../modules/juce_core/native/juce_win32_Network.cpp"; sourceTree = "SOURCE_ROOT"; }; - BC369095BAEED8707D12F63B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAStreamBasicDescription.cpp; path = Extras/CoreAudio/PublicUtility/CAStreamBasicDescription.cpp; sourceTree = "DEVELOPER_DIR"; }; BCB54D2E4C0C3357DACFD29B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_NSViewComponent.h"; path = "../../../../modules/juce_gui_extra/embedding/juce_NSViewComponent.h"; sourceTree = "SOURCE_ROOT"; }; BCE8039887ABB9343A257AFC = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioProcessor.h"; path = "../../../../modules/juce_audio_processors/processors/juce_AudioProcessor.h"; sourceTree = "SOURCE_ROOT"; }; BD1EC91E61ECEAB657C78D5C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Toolbar.cpp"; path = "../../../../modules/juce_gui_basics/widgets/juce_Toolbar.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -799,7 +776,6 @@ CF5FA6C569EF0D70C967EE90 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SVGParser.cpp"; path = "../../../../modules/juce_gui_basics/drawables/juce_SVGParser.cpp"; sourceTree = "SOURCE_ROOT"; }; CF82A46D7CDDAFC5B46AFBC5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextEditor.h"; path = "../../../../modules/juce_gui_basics/widgets/juce_TextEditor.h"; sourceTree = "SOURCE_ROOT"; }; CF9911FF44333EF9154A6141 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_HighResolutionTimer.cpp"; path = "../../../../modules/juce_core/threads/juce_HighResolutionTimer.cpp"; sourceTree = "SOURCE_ROOT"; }; - D010985AB6D7A05BA96EB868 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CarbonEventHandler.h; path = Extras/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.h; sourceTree = "DEVELOPER_DIR"; }; D0406C91AA87E22F071648A8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CharacterFunctions.h"; path = "../../../../modules/juce_core/text/juce_CharacterFunctions.h"; sourceTree = "SOURCE_ROOT"; }; D120181C3218F30A0102BC17 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_CaretComponent.cpp"; path = "../../../../modules/juce_gui_basics/keyboard/juce_CaretComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; D18B1676A7BB2890B81717FD = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentMovementWatcher.h"; path = "../../../../modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.h"; sourceTree = "SOURCE_ROOT"; }; @@ -866,8 +842,7 @@ DFF5523D4F5396F98114B642 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AffineTransform.h"; path = "../../../../modules/juce_graphics/geometry/juce_AffineTransform.h"; sourceTree = "SOURCE_ROOT"; }; E0461DEB1F6D01A42E288646 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Button.h"; path = "../../../../modules/juce_gui_basics/buttons/juce_Button.h"; sourceTree = "SOURCE_ROOT"; }; E04D8B4BAEB817D520C2EF4A = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_OptionalScopedPointer.h"; path = "../../../../modules/juce_core/memory/juce_OptionalScopedPointer.h"; sourceTree = "SOURCE_ROOT"; }; - E08045246EF1A84C7A4D9DF5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUCarbonViewControl.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.cpp; sourceTree = "DEVELOPER_DIR"; }; - E0A48CA97D4C946F632C0DB7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUInputElement.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUInputElement.cpp; sourceTree = "DEVELOPER_DIR"; }; + E0657C5A5A08F4B5BE55034A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUCarbonViewControl.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewControl.cpp"; sourceTree = "SOURCE_ROOT"; }; E0DDE45DB4B87F9311191965 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MidiFile.h"; path = "../../../../modules/juce_audio_basics/midi/juce_MidiFile.h"; sourceTree = "SOURCE_ROOT"; }; E0EE8480E1438F1521ABC0DB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_LookAndFeel.cpp"; path = "../../../../modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.cpp"; sourceTree = "SOURCE_ROOT"; }; E15C0D3B2B648FE732D07ABD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_BubbleComponent.cpp"; path = "../../../../modules/juce_gui_basics/misc/juce_BubbleComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -878,12 +853,13 @@ E398182BD8543E6B845F2255 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RelativePoint.cpp"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativePoint.cpp"; sourceTree = "SOURCE_ROOT"; }; E3A38E6B33797818F62CD77E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RelativeCoordinatePositioner.cpp"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinatePositioner.cpp"; sourceTree = "SOURCE_ROOT"; }; E3F3133499175DC014FC149B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FFT.cpp"; path = "../../../../modules/juce_audio_basics/effects/juce_FFT.cpp"; sourceTree = "SOURCE_ROOT"; }; + E42198F571F1BB1C5203F3D2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUMIDIBase.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIBase.cpp"; sourceTree = "SOURCE_ROOT"; }; E4606F21F965427E694C1132 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Reverb.h"; path = "../../../../modules/juce_audio_basics/effects/juce_Reverb.h"; sourceTree = "SOURCE_ROOT"; }; + E521DD6592FA0F7828161360 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAVectorUnit.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnit.cpp"; sourceTree = "SOURCE_ROOT"; }; E52A19CA27A82BB3ECD76B63 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CharPointer_UTF16.h"; path = "../../../../modules/juce_core/text/juce_CharPointer_UTF16.h"; sourceTree = "SOURCE_ROOT"; }; E57F57DB7857820B9FC7BCFF = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DeletedAtShutdown.h"; path = "../../../../modules/juce_events/messages/juce_DeletedAtShutdown.h"; sourceTree = "SOURCE_ROOT"; }; E5A17AB02D7926E004207D38 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ComboBox.cpp"; path = "../../../../modules/juce_gui_basics/widgets/juce_ComboBox.cpp"; sourceTree = "SOURCE_ROOT"; }; E5CD2295E0A994C362D85800 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MidiMessageSequence.cpp"; path = "../../../../modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp"; sourceTree = "SOURCE_ROOT"; }; - E5EDE1797446522FADDF78B5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAAudioChannelLayout.h; path = Extras/CoreAudio/PublicUtility/CAAudioChannelLayout.h; sourceTree = "DEVELOPER_DIR"; }; E65E231978B796AA7868DC4A = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_audio_plugin_client.h"; path = "../../../../modules/juce_audio_plugin_client/juce_audio_plugin_client.h"; sourceTree = "SOURCE_ROOT"; }; E695834F7C3FC81BB41044C0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_PropertyPanel.h"; path = "../../../../modules/juce_gui_basics/properties/juce_PropertyPanel.h"; sourceTree = "SOURCE_ROOT"; }; E7A0D2A3AAD8192B65EB0141 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioAppComponent.cpp"; path = "../../../../modules/juce_audio_utils/gui/juce_AudioAppComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -901,6 +877,7 @@ EA6921266422F00734EF49B9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_data_structures.h"; path = "../../../../modules/juce_data_structures/juce_data_structures.h"; sourceTree = "SOURCE_ROOT"; }; EA906B8480C7585912B627B1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ByteOrder.h"; path = "../../../../modules/juce_core/memory/juce_ByteOrder.h"; sourceTree = "SOURCE_ROOT"; }; EB3444A4CFC3864FF3F7E4FC = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PropertySet.cpp"; path = "../../../../modules/juce_core/containers/juce_PropertySet.cpp"; sourceTree = "SOURCE_ROOT"; }; + EB38777DCA28E40FF364EAE1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUScopeElement.cpp; path = "../../../../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUScopeElement.cpp"; sourceTree = "SOURCE_ROOT"; }; EB8C7BDEF743331241D8BDE3 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Label.h"; path = "../../../../modules/juce_gui_basics/widgets/juce_Label.h"; sourceTree = "SOURCE_ROOT"; }; EBF5AAA742C6D9C3DE7BA2CC = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Identifier.cpp"; path = "../../../../modules/juce_core/text/juce_Identifier.cpp"; sourceTree = "SOURCE_ROOT"; }; EC155D21E24BFC61E5205344 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MountedVolumeListChangeDetector.h"; path = "../../../../modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h"; sourceTree = "SOURCE_ROOT"; }; @@ -908,17 +885,14 @@ EC401439D56540696500FB09 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DrawableText.h"; path = "../../../../modules/juce_gui_basics/drawables/juce_DrawableText.h"; sourceTree = "SOURCE_ROOT"; }; EC704EDAD7A2015D623B0429 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ApplicationCommandID.h"; path = "../../../../modules/juce_gui_basics/commands/juce_ApplicationCommandID.h"; sourceTree = "SOURCE_ROOT"; }; ED3F8B6AC260A35F53658415 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ButtonPropertyComponent.h"; path = "../../../../modules/juce_gui_basics/properties/juce_ButtonPropertyComponent.h"; sourceTree = "SOURCE_ROOT"; }; - ED5C52722B9653FA3B009C01 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AUOutputElement.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/AUBase/AUOutputElement.cpp; sourceTree = "DEVELOPER_DIR"; }; ED5E2A6E19327A0F73876C42 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_Files.cpp"; path = "../../../../modules/juce_core/native/juce_linux_Files.cpp"; sourceTree = "SOURCE_ROOT"; }; EDC019B897AE281105783BFD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_StringPairArray.cpp"; path = "../../../../modules/juce_core/text/juce_StringPairArray.cpp"; sourceTree = "SOURCE_ROOT"; }; EDD6B4608C8E4C7E7581489D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RectanglePlacement.cpp"; path = "../../../../modules/juce_graphics/placement/juce_RectanglePlacement.cpp"; sourceTree = "SOURCE_ROOT"; }; EE149F9075819C0132879D4C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_AU_Wrapper.mm"; path = "../../../../modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm"; sourceTree = "SOURCE_ROOT"; }; EE1708227B48B586BE17D06B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Fonts.cpp"; path = "../../../../modules/juce_graphics/native/juce_android_Fonts.cpp"; sourceTree = "SOURCE_ROOT"; }; EE6030D7677731D8C2B14CA9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CharPointer_UTF8.h"; path = "../../../../modules/juce_core/text/juce_CharPointer_UTF8.h"; sourceTree = "SOURCE_ROOT"; }; - EE88F9B9461BEE0D11D3EB92 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AUCarbonViewControl.h; path = Extras/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.h; sourceTree = "DEVELOPER_DIR"; }; EECBEDF7C26CF9597CC601D2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FlacAudioFormat.cpp"; path = "../../../../modules/juce_audio_formats/codecs/juce_FlacAudioFormat.cpp"; sourceTree = "SOURCE_ROOT"; }; EED2AEDB27E7562C4DCFA637 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TimeSliceThread.h"; path = "../../../../modules/juce_core/threads/juce_TimeSliceThread.h"; sourceTree = "SOURCE_ROOT"; }; - EFCF0633FF23B5F88112A200 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MusicDeviceBase.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.cpp; sourceTree = "DEVELOPER_DIR"; }; EFD8E22899758751230A8590 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MemoryOutputStream.h"; path = "../../../../modules/juce_core/streams/juce_MemoryOutputStream.h"; sourceTree = "SOURCE_ROOT"; }; F04CF5D4410243EF3DEDBEB8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Font.cpp"; path = "../../../../modules/juce_graphics/fonts/juce_Font.cpp"; sourceTree = "SOURCE_ROOT"; }; F0DC1A84185952857B3DCAE8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_LagrangeInterpolator.cpp"; path = "../../../../modules/juce_audio_basics/effects/juce_LagrangeInterpolator.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -951,7 +925,6 @@ F79C97D63C8C542CFEB404DB = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioFormatReaderSource.h"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormatReaderSource.h"; sourceTree = "SOURCE_ROOT"; }; F79F2406B1605D94EEC822DF = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DynamicObject.h"; path = "../../../../modules/juce_core/containers/juce_DynamicObject.h"; sourceTree = "SOURCE_ROOT"; }; F7AD604135D04469C920F456 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ReverbAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_ReverbAudioSource.h"; sourceTree = "SOURCE_ROOT"; }; - F7AF91E09A9EB00EA5438730 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CarbonEventHandler.cpp; path = Extras/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.cpp; sourceTree = "DEVELOPER_DIR"; }; F7E2FB533BCB2C8831276D22 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StringArray.h"; path = "../../../../modules/juce_core/text/juce_StringArray.h"; sourceTree = "SOURCE_ROOT"; }; F7EC22087BE9304F03690131 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileListComponent.cpp"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_FileListComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; F80CC5FB6425D6B5DD1BBC59 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_WebBrowserComponent.cpp"; path = "../../../../modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -2006,58 +1979,28 @@ F0F89564A3784EB052CEE01B, 3B12C460FF1466EAEDD258A8, 777B3EE5ECE5A0B4799E842E, ); name = "Juce Modules"; sourceTree = ""; }; - A8A516552AE9B51F35B89B2C = {isa = PBXGroup; children = ( - 2B2D54521D69CF4407471A56, - 8B184C08A51AA14F56E42152, - 5E90DDA49E067C3DF60891AA, - 206544B2ADA604E3A68FEF85, - 6A593B7ADFAC09D547EA809D, - 9A1D1CECCBA42358E4E62859, - E08045246EF1A84C7A4D9DF5, - EE88F9B9461BEE0D11D3EB92, - 5631EA8ECD79655B6BEDF8A3, - 374740EFBC17343E10F66F4C, - 6D085AD80CA57F2F8A5C393B, - 969CF69D90AC73918B9BB0CD, - 6EDD3878142839D368B64F31, - E0A48CA97D4C946F632C0DB7, - 141FD2E7828F2F2BE0EE9506, - AB7BCFBC4B2CB784F57A0FBC, - 2E19A0C6793FD28085F7A256, - A2BAB9DD00DF8E30A6DF756E, - 0906F59C839873ADC151A188, - B318D50696B303889BDCF072, - 4A6A465D7BC825BB91F562C3, - 728F423CEB1B9E6CA8545895, - ED5C52722B9653FA3B009C01, - 519C6BF83160A6B581905C58, - 4550EB50BD17ADECC674C83C, - 3031159E3E89066250B1D48A, - A62DF2CD31D7890E1B54B18C, - 5C407CFD81A7E81FA35D5544, - 103FA4C6C505052C818A4829, - 4C4DA110B4ABCD9A9CBE93E1, - 534561E5F94B5D7A093485DF, - E5EDE1797446522FADDF78B5, - A5985F8B03893AA7EFD0273A, - 6CE9C1799C65E997A35E22CD, - 7B491514CCDB29EBB9674F9E, - 3C003D01B67D75E4D745A9B0, - AB9AD07EF899B75AC4CF01DA, - F7AF91E09A9EB00EA5438730, - D010985AB6D7A05BA96EB868, - BC369095BAEED8707D12F63B, - 375A031244EED3B21A609984, - 79B958A028493E0DB0133E2B, - 1D133744B523A61401D587D8, - A10B7B85424CB38AE344D7DC, - 71CDD3C8D311F7994DD5CC8F, - 74F64B7ADDA82099E04331FF, - EFCF0633FF23B5F88112A200, - 416D1E80C31864739829BBD3, ); name = "Juce AU Wrapper"; sourceTree = ""; }; 83470AD511CD6CC1E485F29B = {isa = PBXGroup; children = ( - A8A516552AE9B51F35B89B2C, 844343AA474A10F4CD613ACF, + 3AA0960DF09414DBA0A2255B, + AABC1F4E7D9DA3C6B6DC0F05, + 95FF785BAEC4F2799A75D2FF, + E0657C5A5A08F4B5BE55034A, + 5DAA9288D1FC19812E6ABA3D, + 2051F23DC1B2A76D3B110616, + 88F2FC5C63F1BA3184DC38BD, + 31E15E7A0FBD027D83A28DFF, + E42198F571F1BB1C5203F3D2, + 739336D279C585C749F3039A, + B6394C38B7A283DE86213FAE, + AFE00126A5FEF419332CD2B9, + EB38777DCA28E40FF364EAE1, + 0D4E3861B5EE21765BDEE2A3, + 28FD98C78FE1E918553D4C3D, + 87DBD7450AE0FDD762712620, + 3AA5D4AF03A0689BF8385319, + AC4612F7E064ECEC2E95B129, + E521DD6592FA0F7828161360, + A8BA67A9567A51069D275EBB, 1BAAB47A9C5B1D76D28FA282, DCF6DECFAD7F4D907C0458A5, 8F59D489139F78A729CED9E5, @@ -2083,7 +2026,8 @@ 8EB324480D60B3E3A81541E5, 6CEFF94C7852DB3BFA5E29EB, 7D08D5465E74DF02EA4E7410, - 8FB68CA43E49DD39E013DB82, ); name = "Juce Library Code"; sourceTree = ""; }; + 8FB68CA43E49DD39E013DB82, + 1CF9C794D7A955EA89D8B5CB, ); name = "Juce Library Code"; sourceTree = ""; }; 239B4D5DE50B3B7A16114C15 = {isa = PBXGroup; children = ( 2D799F4BCA83847DEACB505D, 0926E36205F4D676343AB6E7, ); name = Resources; sourceTree = ""; }; @@ -2116,8 +2060,6 @@ COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; COPY_PHASE_STRIP = NO; - EXCLUDED_SOURCE_FILE_NAMES = "$(EXCLUDED_SOURCE_FILE_NAMES_$(CURRENT_ARCH))"; - EXCLUDED_SOURCE_FILE_NAMES_x86_64 = "*Carbon*.cpp"; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -2128,7 +2070,7 @@ "JUCE_APP_VERSION_HEX=0x10000", ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("\"~/SDKs/VST3 SDK\"", "~/SDKs/vstsdk2.4", "../../JuceLibraryCode", "../../../../modules", "$(DEVELOPER_DIR)/Extras/CoreAudio/PublicUtility", "$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/Utility", "$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase", "$(inherited)"); + HEADER_SEARCH_PATHS = ("\"~/SDKs/VST3 SDK\"", "~/SDKs/vstsdk2.4", "../../JuceLibraryCode", "../../../../modules", "$(inherited)"); INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Library/Audio/Plug-Ins/Components/"; LIBRARY_STYLE = Bundle; @@ -2144,8 +2086,6 @@ COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; DEAD_CODE_STRIPPING = YES; - EXCLUDED_SOURCE_FILE_NAMES = "$(EXCLUDED_SOURCE_FILE_NAMES_$(CURRENT_ARCH))"; - EXCLUDED_SOURCE_FILE_NAMES_x86_64 = "*Carbon*.cpp"; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -2157,7 +2097,7 @@ GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GENERATE_PKGINFO_FILE = YES; - HEADER_SEARCH_PATHS = ("\"~/SDKs/VST3 SDK\"", "~/SDKs/vstsdk2.4", "../../JuceLibraryCode", "../../../../modules", "$(DEVELOPER_DIR)/Extras/CoreAudio/PublicUtility", "$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/Utility", "$(DEVELOPER_DIR)/Extras/CoreAudio/AudioUnits/AUPublic/AUBase", "$(inherited)"); + HEADER_SEARCH_PATHS = ("\"~/SDKs/VST3 SDK\"", "~/SDKs/vstsdk2.4", "../../JuceLibraryCode", "../../../../modules", "$(inherited)"); INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Library/Audio/Plug-Ins/Components/"; LIBRARY_STYLE = Bundle; @@ -2209,27 +2149,26 @@ E032EB514708440DE9B7FF2A = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 8265E59547F2C5DDD10F58BF, E32999B782F688D3746FEB08, - F04FAA69AC50147EA624EC1F, - BE7B7AD7F8A22C21CE836999, - 03978B040325C64F1A301026, - 64CC64872B50899D0C1965A4, - B3C70DEC14A0F3C68BFABAB3, - 672ABA87BCE2AC50A10DEC8B, - AAAF1BFC19F4CE7BBD8FA43A, - F075907E84874848BF0BB205, - A1AF669E9F10B2BE0FE3ECD8, - 64AD03BB3A52EC9E2C030B8E, - 7B4173581D4B03969E995CA5, - F979285E6636E6CD0669E164, - 5677D9A2B913014EB1B3E3B3, - C74F334B15AD60AC06A086B7, - CB8698D8E9F64AD71C0608E4, - A5C8DB9F33F2934B307C105C, - E42B91C4C0B68D26493D8586, - 8DBCF6059F7B99ED17E39C3A, - 71BEA1E8715EC77F3BA35BAE, - 4E76293207C599EF3F0E9D66, - 899A05A18F62ABBFF66B554E, + 05D1398458CDB00C236D7553, + EDC1CED5C7F88E1142F4A46A, + B02F742C6DE19F5415457993, + B89DA74BC8384D744F20B8CB, + BF903CF8AFDA8D74E3A9D023, + 9EDD2E63820FA844B4237F1F, + 65EF022632E1E7967860DD5E, + 15885D9F3F3CB8EFDC29A40F, + C9C1F85E79851CE3F2EA0560, + 10803DD1A2511511C9A2CEC5, + EDE82B3320CC03F38226AA50, + C3C922FB2D069BB6DE3ECAA1, + 48D94EBEB2D48D0DCC1394C9, + D2B29F3448FA79AB8C47B3D8, + D5E7114B2C484F13A51DCBC3, + 9B39F1EE70A26791804DA55E, + 0A7276E46524FC5FD796F27D, + 9EA2528254AA35DBDDFEA601, + 68B259347BBF52B12FD6900D, + 91CCE2D40B3D71F3126A1043, 74CF5671532851FFA52E9D0C, E20B98D0BD4CB959779121EF, C838DDB6686561401CFD352E, @@ -2253,7 +2192,8 @@ 6AAB8C946DA0E3E1B96EEF7E, BCFB9D694F4DD8A76C6B9878, 080999E86692B638CD108D70, - BFD65DA4F2FE24DF532304DA, ); runOnlyForDeploymentPostprocessing = 0; }; + BFD65DA4F2FE24DF532304DA, + A4996F8A30110B5EDB801516, ); runOnlyForDeploymentPostprocessing = 0; }; 95E57A758351FE57067B605F = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 221B97F3CD062F71EBEBA165, A068599CF7E166847EE45D5F, diff --git a/extras/Introjucer/Source/Project/jucer_AudioPluginModule.h b/extras/Introjucer/Source/Project/jucer_AudioPluginModule.h index ee342b99dd..f2e9c9bcd9 100644 --- a/extras/Introjucer/Source/Project/jucer_AudioPluginModule.h +++ b/extras/Introjucer/Source/Project/jucer_AudioPluginModule.h @@ -475,96 +475,7 @@ namespace AUHelpers if (exporter.isXcode()) { - String sdkLocation (getPluginAUSDKLocation (projectSaver.project).toString()); - - if (sdkLocation.trim().isEmpty()) - sdkLocation = "$(DEVELOPER_DIR)/Extras/CoreAudio/"; - - if (! sdkLocation.endsWithChar ('/')) - sdkLocation << '/'; - - { - String relativeSDK (exporter.rebaseFromProjectFolderToBuildTarget (RelativePath (sdkLocation, RelativePath::projectFolder)) - .toUnixStyle()); - - if (! relativeSDK.endsWithChar ('/')) - relativeSDK << '/'; - - exporter.extraSearchPaths.add (relativeSDK + "PublicUtility"); - exporter.extraSearchPaths.add (relativeSDK + "AudioUnits/AUPublic/Utility"); - exporter.extraSearchPaths.add (relativeSDK + "AudioUnits/AUPublic/AUBase"); - } - exporter.xcodeFrameworks.addTokens ("AudioUnit CoreAudioKit", false); - exporter.xcodeExcludedFiles64Bit = "\"*Carbon*.cpp\""; - - Project::Item subGroup (projectSaver.getGeneratedCodeGroup().addNewSubGroup ("Juce AU Wrapper", -1)); - subGroup.setID ("__juceappleaufiles"); - - { - static const char* appleAUFiles[] = - { - "PublicUtility/CADebugMacros.h", - "PublicUtility/CAAUParameter.cpp", - "PublicUtility/CAAUParameter.h", - "PublicUtility/CAAudioChannelLayout.cpp", - "PublicUtility/CAAudioChannelLayout.h", - "PublicUtility/CAMutex.cpp", - "PublicUtility/CAMutex.h", - "PublicUtility/CAStreamBasicDescription.cpp", - "PublicUtility/CAStreamBasicDescription.h", - "PublicUtility/CAVectorUnitTypes.h", - "PublicUtility/CAVectorUnit.cpp", - "PublicUtility/CAVectorUnit.h", - "AudioUnits/AUPublic/AUViewBase/AUViewLocalizedStringKeys.h", - "AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewDispatch.cpp", - "AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.cpp", - "AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.h", - "AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.cpp", - "AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.h", - "AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.cpp", - "AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.h", - "AudioUnits/AUPublic/AUBase/AUBase.cpp", - "AudioUnits/AUPublic/AUBase/AUBase.h", - "AudioUnits/AUPublic/AUBase/AUDispatch.cpp", - "AudioUnits/AUPublic/AUBase/AUDispatch.h", - "AudioUnits/AUPublic/AUBase/AUInputElement.cpp", - "AudioUnits/AUPublic/AUBase/AUInputElement.h", - "AudioUnits/AUPublic/AUBase/AUOutputElement.cpp", - "AudioUnits/AUPublic/AUBase/AUOutputElement.h", - "AudioUnits/AUPublic/AUBase/AUResources.r", - "AudioUnits/AUPublic/AUBase/AUScopeElement.cpp", - "AudioUnits/AUPublic/AUBase/AUScopeElement.h", - "AudioUnits/AUPublic/AUBase/ComponentBase.cpp", - "AudioUnits/AUPublic/AUBase/ComponentBase.h", - "AudioUnits/AUPublic/OtherBases/AUMIDIBase.cpp", - "AudioUnits/AUPublic/OtherBases/AUMIDIBase.h", - "AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.cpp", - "AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.h", - "AudioUnits/AUPublic/OtherBases/AUOutputBase.cpp", - "AudioUnits/AUPublic/OtherBases/AUOutputBase.h", - "AudioUnits/AUPublic/OtherBases/MusicDeviceBase.cpp", - "AudioUnits/AUPublic/OtherBases/MusicDeviceBase.h", - "AudioUnits/AUPublic/OtherBases/AUEffectBase.cpp", - "AudioUnits/AUPublic/OtherBases/AUEffectBase.h", - "AudioUnits/AUPublic/Utility/AUBuffer.cpp", - "AudioUnits/AUPublic/Utility/AUBuffer.h", - "AudioUnits/AUPublic/Utility/AUInputFormatConverter.h", - "AudioUnits/AUPublic/Utility/AUSilentTimeout.h", - "AudioUnits/AUPublic/Utility/AUTimestampGenerator.h", - nullptr - }; - - // This converts things like $(DEVELOPER_DIR) to ${DEVELOPER_DIR} - sdkLocation = sdkLocation.replaceCharacters ("()", "{}"); - - for (const char** f = appleAUFiles; *f != nullptr; ++f) - { - const RelativePath file (sdkLocation + *f, RelativePath::projectFolder); - subGroup.addRelativeFile (file, -1, file.hasFileExtension ("cpp;mm")); - subGroup.getChild (subGroup.getNumChildren() - 1).getShouldInhibitWarningsValue() = true; - } - } XmlElement plistKey ("key"); plistKey.addTextElement ("AudioComponents"); diff --git a/modules/juce_audio_plugin_client/AU/AUResources.r b/modules/juce_audio_plugin_client/AU/AUResources.r new file mode 100644 index 0000000000..55040fc396 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/AUResources.r @@ -0,0 +1,140 @@ +/* + File: AUResources.r + Abstract: AUResources.r + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// AUResources.r +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +/* sample macro definitions -- all of these symbols must be defined +#define RES_ID kHALOutputResID +#define COMP_TYPE kAudioUnitComponentType +#define COMP_SUBTYPE kAudioUnitOutputSubType +#define COMP_MANUF kAudioUnitAudioHardwareOutputSubSubType +#define VERSION 0x00010000 +#define NAME "AudioHALOutput" +#define DESCRIPTION "Audio hardware output AudioUnit" +#define ENTRY_POINT "AUHALEntry" +*/ +#define UseExtendedThingResource 1 + +#include + +// this is a define used to indicate that a component has no static data that would mean +// that no more than one instance could be open at a time - never been true for AUs +#ifndef cmpThreadSafeOnMac +#define cmpThreadSafeOnMac 0x10000000 +#endif + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +resource 'STR ' (RES_ID, purgeable) { + NAME +}; + +resource 'STR ' (RES_ID + 1, purgeable) { + DESCRIPTION +}; + +resource 'dlle' (RES_ID) { + ENTRY_POINT +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +resource 'thng' (RES_ID, NAME) { + COMP_TYPE, + COMP_SUBTYPE, + COMP_MANUF, + 0, 0, 0, 0, // no 68K + 'STR ', RES_ID, + 'STR ', RES_ID + 1, + 0, 0, /* icon */ + VERSION, + componentHasMultiplePlatforms | componentDoAutoVersion, + 0, + { + #if defined(ppc_YES) + cmpThreadSafeOnMac, + 'dlle', RES_ID, platformPowerPCNativeEntryPoint + #define NeedLeadingComma 1 + #endif + #if defined(ppc64_YES) + #if defined(NeedLeadingComma) + , + #endif + cmpThreadSafeOnMac, + 'dlle', RES_ID, platformPowerPC64NativeEntryPoint + #define NeedLeadingComma 1 + #endif + #if defined(i386_YES) + #if defined(NeedLeadingComma) + , + #endif + cmpThreadSafeOnMac, + 'dlle', RES_ID, platformIA32NativeEntryPoint + #define NeedLeadingComma 1 + #endif + #if defined(x86_64_YES) + #if defined(NeedLeadingComma) + , + #endif + cmpThreadSafeOnMac, + 'dlle', RES_ID, 8 + #define NeedLeadingComma 1 + #endif + } +}; + +#undef RES_ID +#undef COMP_TYPE +#undef COMP_SUBTYPE +#undef COMP_MANUF +#undef VERSION +#undef NAME +#undef DESCRIPTION +#undef ENTRY_POINT +#undef NeedLeadingComma diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.cpp new file mode 100644 index 0000000000..53c684f61b --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.cpp @@ -0,0 +1,2392 @@ +/* + File: AUBase.cpp + Abstract: AUBase.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUBase.h" +#include "AUDispatch.h" +#include "AUInputElement.h" +#include "AUOutputElement.h" +#include +#include +#include "CAAudioChannelLayout.h" +#include "CAHostTimeBase.h" +#include "CAVectorUnit.h" +#include "CAXException.h" + + + +#if TARGET_OS_MAC && (TARGET_CPU_X86 || TARGET_CPU_X86_64) + // our compiler does ALL floating point with SSE + inline int GETCSR () { int _result; asm volatile ("stmxcsr %0" : "=m" (*&_result) ); return _result; } + inline void SETCSR (int a) { int _temp = a; asm volatile( "ldmxcsr %0" : : "m" (*&_temp ) ); } + + #define DISABLE_DENORMALS int _savemxcsr = GETCSR(); SETCSR(_savemxcsr | 0x8040); + #define RESTORE_DENORMALS SETCSR(_savemxcsr); +#else + #define DISABLE_DENORMALS + #define RESTORE_DENORMALS +#endif + +static bool sAUBaseCFStringsInitialized = false; +// this is used for the presets +static CFStringRef kUntitledString = NULL; +//these are the current keys for the class info document +static CFStringRef kVersionString = NULL; +static CFStringRef kTypeString = NULL; +static CFStringRef kSubtypeString = NULL; +static CFStringRef kManufacturerString = NULL; +static CFStringRef kDataString = NULL; +static CFStringRef kNameString = NULL; +static CFStringRef kRenderQualityString = NULL; +static CFStringRef kCPULoadString = NULL; +static CFStringRef kElementNameString = NULL; +static CFStringRef kPartString = NULL; + +SInt32 AUBase::sVectorUnitType = kVecUninitialized; + +//_____________________________________________________________________________ +// +AUBase::AUBase( AudioComponentInstance inInstance, + UInt32 numInputElements, + UInt32 numOutputElements, + UInt32 numGroupElements) : + ComponentBase(inInstance), + mElementsCreated(false), + mInitialized(false), + mHasBegunInitializing(false), + mInitNumInputEls(numInputElements), mInitNumOutputEls(numOutputElements), +#if !CA_BASIC_AU_FEATURES + mInitNumGroupEls(numGroupElements), +#endif + mRenderCallbacksTouched(false), + mRenderThreadID (NULL), + mWantsRenderThreadID (false), + mLastRenderError(0), + mUsesFixedBlockSize(false), + mBuffersAllocated(false), + mLogString (NULL), + mNickName (NULL), + mAUMutex(NULL) + #if !CA_NO_AU_UI_FEATURES + , + mContextName(NULL) + #endif +{ + ResetRenderTime (); + + if(!sAUBaseCFStringsInitialized) + { + kUntitledString = CFSTR("Untitled"); + kVersionString = CFSTR(kAUPresetVersionKey); + kTypeString = CFSTR(kAUPresetTypeKey); + kSubtypeString = CFSTR(kAUPresetSubtypeKey); + kManufacturerString = CFSTR(kAUPresetManufacturerKey); + kDataString = CFSTR(kAUPresetDataKey); + kNameString = CFSTR(kAUPresetNameKey); + kRenderQualityString = CFSTR(kAUPresetRenderQualityKey); + kCPULoadString = CFSTR(kAUPresetCPULoadKey); + kElementNameString = CFSTR(kAUPresetElementNameKey); + kPartString = CFSTR(kAUPresetPartKey); + sAUBaseCFStringsInitialized = true; + } + + if (sVectorUnitType == kVecUninitialized) { + sVectorUnitType = CAVectorUnit::GetVectorUnitType() ; + } + + mAudioUnitAPIVersion = 2; + + SetMaxFramesPerSlice(kAUDefaultMaxFramesPerSlice); + + GlobalScope().Initialize(this, kAudioUnitScope_Global, 1); + +#if !CA_NO_AU_UI_FEATURES + memset (&mHostCallbackInfo, 0, sizeof (mHostCallbackInfo)); +#endif + + + mCurrentPreset.presetNumber = -1; + mCurrentPreset.presetName = kUntitledString; + CFRetain (mCurrentPreset.presetName); +} + +//_____________________________________________________________________________ +// +AUBase::~AUBase() +{ + if (mCurrentPreset.presetName) CFRelease (mCurrentPreset.presetName); +#if !CA_NO_AU_UI_FEATURES + if (mContextName) CFRelease (mContextName); +#endif + if (mLogString) delete [] mLogString; + if (mNickName) CFRelease(mNickName); +} + +//_____________________________________________________________________________ +// +void AUBase::CreateElements() +{ + if (!mElementsCreated) { + Inputs().Initialize(this, kAudioUnitScope_Input, mInitNumInputEls); + Outputs().Initialize(this, kAudioUnitScope_Output, mInitNumOutputEls); +#if !CA_BASIC_AU_FEATURES + Groups().Initialize(this, kAudioUnitScope_Group, mInitNumGroupEls); +#endif + CreateExtendedElements(); + + mElementsCreated = true; + } +} + +//_____________________________________________________________________________ +// +void AUBase::SetMaxFramesPerSlice(UInt32 nFrames) +{ + mMaxFramesPerSlice = nFrames; + if (mBuffersAllocated) + ReallocateBuffers(); + PropertyChanged(kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0); +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::CanSetMaxFrames() const +{ + return IsInitialized() ? kAudioUnitErr_Initialized : OSStatus(noErr); +} + +//_____________________________________________________________________________ +// +void AUBase::ReallocateBuffers() +{ + CreateElements(); + + UInt32 nOutputs = Outputs().GetNumberOfElements(); + for (UInt32 i = 0; i < nOutputs; ++i) { + AUOutputElement *output = GetOutput(i); + output->AllocateBuffer(); // does no work if already allocated + } + UInt32 nInputs = Inputs().GetNumberOfElements(); + for (UInt32 i = 0; i < nInputs; ++i) { + AUInputElement *input = GetInput(i); + input->AllocateBuffer(); // does no work if already allocated + } + mBuffersAllocated = true; +} + +//_____________________________________________________________________________ +// +void AUBase::DeallocateIOBuffers() +{ + if (!mBuffersAllocated) + return; + + UInt32 nOutputs = Outputs().GetNumberOfElements(); + for (UInt32 i = 0; i < nOutputs; ++i) { + AUOutputElement *output = GetOutput(i); + output->DeallocateBuffer(); + } + UInt32 nInputs = Inputs().GetNumberOfElements(); + for (UInt32 i = 0; i < nInputs; ++i) { + AUInputElement *input = GetInput(i); + input->DeallocateBuffer(); + } + mBuffersAllocated = false; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::DoInitialize() +{ + OSStatus result = noErr; + + if (!mInitialized) { + result = Initialize(); + if (result == noErr) { + if (CanScheduleParameters()) + mParamList.reserve(24); + mHasBegunInitializing = true; + ReallocateBuffers(); // calls CreateElements() + mInitialized = true; // signal that it's okay to render + CAMemoryBarrier(); + } + } + + return result; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::Initialize() +{ + return noErr; +} + +//_____________________________________________________________________________ +// +void AUBase::PreDestructor() +{ + // this is called from the ComponentBase dispatcher, which doesn't know anything about our (optional) lock + CAMutex::Locker lock(mAUMutex); + DoCleanup(); +} + +//_____________________________________________________________________________ +// +void AUBase::DoCleanup() +{ + if (mInitialized) + Cleanup(); + + DeallocateIOBuffers(); + ResetRenderTime (); + + mInitialized = false; + mHasBegunInitializing = false; +} + +//_____________________________________________________________________________ +// +void AUBase::Cleanup() +{ +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::Reset( AudioUnitScope inScope, + AudioUnitElement inElement) +{ + ResetRenderTime (); + return noErr; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::DispatchGetPropertyInfo(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable) +{ + OSStatus result = noErr; + bool validateElement = true; + + switch (inID) { + case kAudioUnitProperty_MakeConnection: + ca_require(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(AudioUnitConnection); + outWritable = true; + break; + + + case kAudioUnitProperty_SetRenderCallback: + ca_require(AudioUnitAPIVersion() > 1, InvalidProperty); + ca_require(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(AURenderCallbackStruct); + outWritable = true; + break; + + case kAudioUnitProperty_StreamFormat: + outDataSize = sizeof(CAStreamBasicDescription); + outWritable = IsStreamFormatWritable(inScope, inElement); + break; + + case kAudioUnitProperty_SampleRate: + outDataSize = sizeof(Float64); + outWritable = IsStreamFormatWritable(inScope, inElement); + break; + + case kAudioUnitProperty_ClassInfo: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(CFPropertyListRef); + outWritable = true; + break; + + case kAudioUnitProperty_FactoryPresets: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + result = GetPresets(NULL); + if (!result) { + outDataSize = sizeof(CFArrayRef); + outWritable = false; + } + break; + + case kAudioUnitProperty_PresentPreset: +#if !CA_USE_AUDIO_PLUGIN_ONLY +#ifndef __LP64__ + case kAudioUnitProperty_CurrentPreset: +#endif +#endif + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(AUPreset); + outWritable = true; + break; + + case kAudioUnitProperty_ElementName: + outDataSize = sizeof (CFStringRef); + outWritable = true; + break; + + case kAudioUnitProperty_ParameterList: + { + UInt32 nparams = 0; + result = GetParameterList(inScope, NULL, nparams); + + outDataSize = sizeof(AudioUnitParameterID) * nparams; + outWritable = false; + validateElement = false; + } + break; + + case kAudioUnitProperty_ParameterInfo: + outDataSize = sizeof(AudioUnitParameterInfo); + outWritable = false; + validateElement = false; + break; + + case kAudioUnitProperty_ParameterHistoryInfo: + outDataSize = sizeof(AudioUnitParameterHistoryInfo); + outWritable = false; + validateElement = false; + break; + + case kAudioUnitProperty_ElementCount: + outDataSize = sizeof(UInt32); + outWritable = BusCountWritable(inScope); + validateElement = false; + break; + + case kAudioUnitProperty_Latency: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(Float64); + outWritable = false; + break; + + case kAudioUnitProperty_TailTime: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + if (SupportsTail()) { + outDataSize = sizeof(Float64); + outWritable = false; + } else + goto InvalidProperty; + break; + + case kAudioUnitProperty_MaximumFramesPerSlice: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(UInt32); + outWritable = true; + break; + + case kAudioUnitProperty_LastRenderError: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(OSStatus); + outWritable = false; + break; + + case kAudioUnitProperty_SupportedNumChannels: + { + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + UInt32 num = SupportedNumChannels (NULL); + if (num) { + outDataSize = sizeof (AUChannelInfo) * num; + result = noErr; + } else + goto InvalidProperty; + outWritable = false; + break; + } + + case kAudioUnitProperty_SupportedChannelLayoutTags: + { + UInt32 numLayouts = GetChannelLayoutTags(inScope, inElement, NULL); + if (numLayouts) { + outDataSize = numLayouts * sizeof(AudioChannelLayoutTag); + result = noErr; + } else + goto InvalidProperty; + outWritable = false; + validateElement = false; //already done it + break; + } + + case kAudioUnitProperty_AudioChannelLayout: + { + outWritable = false; + outDataSize = GetAudioChannelLayout(inScope, inElement, NULL, outWritable); + if (outDataSize) { + result = noErr; + } else { + if (GetChannelLayoutTags(inScope, inElement, NULL) == 0) + goto InvalidProperty; + else + result = kAudioUnitErr_InvalidPropertyValue; + } + validateElement = false; //already done it + break; + } + +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE + case kAudioUnitProperty_ShouldAllocateBuffer: + ca_require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output), InvalidScope); + outWritable = true; + outDataSize = sizeof(UInt32); + break; +#endif + +#if !CA_USE_AUDIO_PLUGIN_ONLY + case kAudioUnitProperty_FastDispatch: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + if (!IsCMgrObject()) goto InvalidProperty; + outDataSize = sizeof(void *); + outWritable = false; + validateElement = false; + break; + + case kAudioUnitProperty_GetUIComponentList: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = GetNumCustomUIComponents(); + if (outDataSize == 0) + goto InvalidProperty; + outDataSize *= sizeof (AudioComponentDescription); + + outWritable = false; + break; +#endif + + case kAudioUnitProperty_ParameterValueStrings: + result = GetParameterValueStrings(inScope, inElement, NULL); + if (result == noErr) { + outDataSize = sizeof(CFArrayRef); + outWritable = false; + validateElement = false; + } + break; + +#if !CA_NO_AU_HOST_CALLBACKS + case kAudioUnitProperty_HostCallbacks: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(mHostCallbackInfo); + outWritable = true; + break; +#endif +#if !CA_NO_AU_UI_FEATURES + case kAudioUnitProperty_ContextName: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(CFStringRef); + outWritable = true; + break; + + case kAudioUnitProperty_IconLocation: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outWritable = false; + if (!HasIcon()) + goto InvalidProperty; + outDataSize = sizeof(CFURLRef); + break; + + case kAudioUnitProperty_ParameterClumpName: + outDataSize = sizeof(AudioUnitParameterNameInfo ); + outWritable = false; + break; + +#endif // !CA_NO_AU_UI_FEATURES + + case 'lrst' : // kAudioUnitProperty_LastRenderedSampleTime + outDataSize = sizeof(Float64); + outWritable = false; + break; + + case kAudioUnitProperty_NickName: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(CFStringRef); + outWritable = true; + break; + + default: + result = GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable); + validateElement = false; + break; + } + + if (result == noErr && validateElement) { + ca_require(GetElement(inScope, inElement) != NULL, InvalidElement); + } + + return result; +InvalidProperty: + return kAudioUnitErr_InvalidProperty; +InvalidScope: + return kAudioUnitErr_InvalidScope; +InvalidElement: + return kAudioUnitErr_InvalidElement; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::DispatchGetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData) +{ + // NOTE: We're currently only called from AUBase::ComponentEntryDispatch, which + // calls DispatchGetPropertyInfo first, which performs validation of the scope/element, + // and ensures that the outData buffer is non-null and large enough. + OSStatus result = noErr; + + switch (inID) { + case kAudioUnitProperty_StreamFormat: + *(CAStreamBasicDescription *)outData = GetStreamFormat(inScope, inElement); + break; + + case kAudioUnitProperty_SampleRate: + *(Float64 *)outData = GetStreamFormat(inScope, inElement).mSampleRate; + break; + + case kAudioUnitProperty_ParameterList: + { + UInt32 nparams = 0; + result = GetParameterList(inScope, (AudioUnitParameterID *)outData, nparams); + } + break; + + case kAudioUnitProperty_ParameterInfo: + result = GetParameterInfo(inScope, inElement, *(AudioUnitParameterInfo *)outData); + break; + + case kAudioUnitProperty_ParameterHistoryInfo: + { + AudioUnitParameterHistoryInfo* info = (AudioUnitParameterHistoryInfo*)outData; + result = GetParameterHistoryInfo(inScope, inElement, info->updatesPerSecond, info->historyDurationInSeconds); + } + break; + + case kAudioUnitProperty_ClassInfo: + { + *(CFPropertyListRef *)outData = NULL; + result = SaveState((CFPropertyListRef *)outData); + } + break; + + case kAudioUnitProperty_FactoryPresets: + { + *(CFArrayRef *)outData = NULL; + result = GetPresets ((CFArrayRef *)outData); + } + break; + + case kAudioUnitProperty_PresentPreset: +#if !CA_USE_AUDIO_PLUGIN_ONLY +#ifndef __LP64__ + case kAudioUnitProperty_CurrentPreset: +#endif +#endif + { + *(AUPreset *)outData = mCurrentPreset; + + // retain current string (as client owns a reference to it and will release it) + if (inID == kAudioUnitProperty_PresentPreset && mCurrentPreset.presetName) + CFRetain (mCurrentPreset.presetName); + + result = noErr; + } + break; + + case kAudioUnitProperty_ElementName: + { + AUElement * element = GetElement(inScope, inElement); + if (element->HasName()) { + *(CFStringRef *)outData = element->GetName(); + CFRetain (element->GetName()); + result = noErr; + } else + result = kAudioUnitErr_InvalidPropertyValue; + } + break; + + case kAudioUnitProperty_ElementCount: + *(UInt32 *)outData = GetScope(inScope).GetNumberOfElements(); + break; + + case kAudioUnitProperty_Latency: + *(Float64 *)outData = GetLatency(); + break; + + case kAudioUnitProperty_TailTime: + if (SupportsTail()) + *(Float64 *)outData = GetTailTime(); + else + result = kAudioUnitErr_InvalidProperty; + break; + + case kAudioUnitProperty_MaximumFramesPerSlice: + *(UInt32 *)outData = mMaxFramesPerSlice; + break; + + case kAudioUnitProperty_LastRenderError: + *(OSStatus *)outData = mLastRenderError; + mLastRenderError = 0; + break; + + case kAudioUnitProperty_SupportedNumChannels: + { + const AUChannelInfo* infoPtr = NULL; + UInt32 num = SupportedNumChannels (&infoPtr); + if(num != 0 && infoPtr != NULL) + memcpy (outData, infoPtr, num * sizeof (AUChannelInfo)); + } + break; + + case kAudioUnitProperty_SupportedChannelLayoutTags: + { + AudioChannelLayoutTag* ptr = outData ? static_cast(outData) : NULL; + UInt32 numLayouts = GetChannelLayoutTags (inScope, inElement, ptr); + if (numLayouts == 0) + result = kAudioUnitErr_InvalidProperty; + } + break; + + case kAudioUnitProperty_AudioChannelLayout: + { + AudioChannelLayout* ptr = outData ? static_cast(outData) : NULL; + Boolean writable; + UInt32 dataSize = GetAudioChannelLayout(inScope, inElement, ptr, writable); + if (!dataSize) { + result = kAudioUnitErr_InvalidProperty; + } + break; + } + +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE + case kAudioUnitProperty_ShouldAllocateBuffer: + { + AUIOElement * element = GetIOElement(inScope, inElement); + *(UInt32*)outData = element->WillAllocateBuffer(); + break; + } +#endif + + case kAudioUnitProperty_ParameterValueStrings: + result = GetParameterValueStrings(inScope, inElement, (CFArrayRef *)outData); + break; + +#if !CA_USE_AUDIO_PLUGIN_ONLY + case kAudioUnitProperty_FastDispatch: + if (!IsCMgrObject()) result = kAudioUnitErr_InvalidProperty; + else { + switch (inElement) { + case kAudioUnitGetParameterSelect: + *(AudioUnitGetParameterProc *)outData = (AudioUnitGetParameterProc)CMgr_AudioUnitBaseGetParameter; + break; + case kAudioUnitSetParameterSelect: + *(AudioUnitSetParameterProc *)outData = (AudioUnitSetParameterProc)CMgr_AudioUnitBaseSetParameter; + break; + case kAudioUnitRenderSelect: + if (AudioUnitAPIVersion() > 1) + *(AudioUnitRenderProc *)outData = (AudioUnitRenderProc)CMgr_AudioUnitBaseRender; + else result = kAudioUnitErr_InvalidElement; + break; + default: + result = GetProperty(inID, inScope, inElement, outData); + break; + } + } + break; + + case kAudioUnitProperty_GetUIComponentList: + GetUIComponentDescs ((ComponentDescription*)outData); + break; +#endif + +#if !CA_NO_AU_HOST_CALLBACKS + case kAudioUnitProperty_HostCallbacks: + memcpy(outData, &mHostCallbackInfo, sizeof(mHostCallbackInfo)); + break; +#endif +#if !CA_NO_AU_UI_FEATURES + case kAudioUnitProperty_IconLocation: + { + CFURLRef iconLocation = CopyIconLocation(); + if (iconLocation) { + *(CFURLRef*)outData = iconLocation; + } else + result = kAudioUnitErr_InvalidProperty; + } + break; + + case kAudioUnitProperty_ContextName: + *(CFStringRef *)outData = mContextName; + if (mContextName) { + CFRetain(mContextName); + // retain CFString (if exists) since client will be responsible for its release + result = noErr; + } else { + result = kAudioUnitErr_InvalidPropertyValue; + } + break; + + case kAudioUnitProperty_ParameterClumpName: + { + AudioUnitParameterNameInfo * ioClumpInfo = (AudioUnitParameterNameInfo*) outData; + if (ioClumpInfo->inID == kAudioUnitClumpID_System) // this ID value is reserved + result = kAudioUnitErr_InvalidPropertyValue; + else + { + result = CopyClumpName(inScope, ioClumpInfo->inID, ioClumpInfo->inDesiredLength, &ioClumpInfo->outName); + + // this is provided for compatbility with existing implementations that don't know + // about this new mechanism + if (result == kAudioUnitErr_InvalidProperty) + result = GetProperty (inID, inScope, inElement, outData); + } + } + break; + +#endif // !CA_NO_AU_UI_FEATURES + + case 'lrst' : // kAudioUnitProperty_LastRenderedSampleTime + *(Float64*)outData = mCurrentRenderTime.mSampleTime; + break; + + case kAudioUnitProperty_NickName: + // Ownership follows Core Foundation's 'Copy Rule' + if (mNickName) CFRetain(mNickName); + *(CFStringRef*)outData = mNickName; + break; + + default: + result = GetProperty(inID, inScope, inElement, outData); + break; + } + return result; +} + + +//_____________________________________________________________________________ +// +OSStatus AUBase::DispatchSetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize) +{ + OSStatus result = noErr; + + switch (inID) { + case kAudioUnitProperty_MakeConnection: + ca_require(inDataSize >= sizeof(AudioUnitConnection), InvalidPropertyValue); + { + AudioUnitConnection &connection = *(AudioUnitConnection *)inData; + result = SetConnection(connection); + } + break; + + + case kAudioUnitProperty_SetRenderCallback: + { + ca_require(inDataSize >= sizeof(AURenderCallbackStruct), InvalidPropertyValue); + ca_require(AudioUnitAPIVersion() > 1, InvalidProperty); + AURenderCallbackStruct &callback = *(AURenderCallbackStruct*)inData; + result = SetInputCallback(kAudioUnitProperty_SetRenderCallback, inElement, callback.inputProc, callback.inputProcRefCon); + } + break; + + case kAudioUnitProperty_ElementCount: + ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue); + ca_require(BusCountWritable(inScope), NotWritable); + result = SetBusCount(inScope, *(UInt32*)inData); + if (result == noErr) { + PropertyChanged(inID, inScope, inElement); + } + break; + + case kAudioUnitProperty_MaximumFramesPerSlice: + ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue); + result = CanSetMaxFrames(); + if (result) return result; + SetMaxFramesPerSlice(*(UInt32 *)inData); + break; + + case kAudioUnitProperty_StreamFormat: + { + if (inDataSize < 36) goto InvalidPropertyValue; + ca_require(GetElement(inScope, inElement) != NULL, InvalidElement); + + CAStreamBasicDescription newDesc; + // now we're going to be ultra conservative! because of discrepancies between + // sizes of this struct based on aligment padding inconsistencies + memset (&newDesc, 0, sizeof(newDesc)); + memcpy (&newDesc, inData, 36); + + ca_require(ValidFormat(inScope, inElement, newDesc), InvalidFormat); + + const CAStreamBasicDescription curDesc = GetStreamFormat(inScope, inElement); + + if ( !curDesc.IsEqual(newDesc, false) ) { + ca_require(IsStreamFormatWritable(inScope, inElement), NotWritable); + result = ChangeStreamFormat(inScope, inElement, curDesc, newDesc); + } + } + break; + + case kAudioUnitProperty_SampleRate: + { + ca_require(inDataSize == sizeof(Float64), InvalidPropertyValue); + ca_require(GetElement(inScope, inElement) != NULL, InvalidElement); + + const CAStreamBasicDescription curDesc = GetStreamFormat(inScope, inElement); + CAStreamBasicDescription newDesc = curDesc; + newDesc.mSampleRate = *(Float64 *)inData; + + ca_require(ValidFormat(inScope, inElement, newDesc), InvalidFormat); + + if ( !curDesc.IsEqual(newDesc, false) ) { + ca_require(IsStreamFormatWritable(inScope, inElement), NotWritable); + result = ChangeStreamFormat(inScope, inElement, curDesc, newDesc); + } + } + break; + + case kAudioUnitProperty_AudioChannelLayout: + { + const AudioChannelLayout *layout = static_cast(inData); + size_t headerSize = sizeof(AudioChannelLayout) - sizeof(AudioChannelDescription); + + ca_require(inDataSize >= headerSize + layout->mNumberChannelDescriptions * sizeof(AudioChannelDescription), InvalidPropertyValue); + result = SetAudioChannelLayout(inScope, inElement, layout); + if (result == noErr) + PropertyChanged(inID, inScope, inElement); + break; + } + + case kAudioUnitProperty_ClassInfo: + ca_require(inDataSize == sizeof(CFPropertyListRef *), InvalidPropertyValue); + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + result = RestoreState(*(CFPropertyListRef *)inData); + break; + + case kAudioUnitProperty_PresentPreset: +#if !CA_USE_AUDIO_PLUGIN_ONLY +#ifndef __LP64__ + case kAudioUnitProperty_CurrentPreset: +#endif +#endif + { + ca_require(inDataSize == sizeof(AUPreset), InvalidPropertyValue); + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + AUPreset & newPreset = *(AUPreset *)inData; + + if (newPreset.presetNumber >= 0) + { + result = NewFactoryPresetSet(newPreset); + // NewFactoryPresetSet SHOULD call SetAFactoryPreset if the preset is valid + // from its own list of preset number->name + if (!result) + PropertyChanged(inID, inScope, inElement); + } + else if (newPreset.presetName) + { + result = NewCustomPresetSet(newPreset); + if (!result) + PropertyChanged(inID, inScope, inElement); + } + else + result = kAudioUnitErr_InvalidPropertyValue; + } + break; + + case kAudioUnitProperty_ElementName: + { + ca_require(GetElement(inScope, inElement) != NULL, InvalidElement); + ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue); + AUElement * element = GetScope(inScope).GetElement (inElement); + element->SetName (*(CFStringRef *)inData); + PropertyChanged(inID, inScope, inElement); + } + break; + +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE + case kAudioUnitProperty_ShouldAllocateBuffer: + { + ca_require((inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output), InvalidScope); + ca_require(GetElement(inScope, inElement) != NULL, InvalidElement); + ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue); + ca_require(!IsInitialized(), Initialized); + + AUIOElement * element = GetIOElement(inScope, inElement); + element->SetWillAllocateBuffer(*(UInt32 *)inData != 0); + } + break; +#endif + +#if !CA_NO_AU_HOST_CALLBACKS + case kAudioUnitProperty_HostCallbacks: + { + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + UInt32 availSize = std::min(inDataSize, (UInt32)sizeof(HostCallbackInfo)); + bool hasChanged = !memcmp (&mHostCallbackInfo, inData, availSize); + memset (&mHostCallbackInfo, 0, sizeof (mHostCallbackInfo)); + memcpy (&mHostCallbackInfo, inData, availSize); + if (hasChanged) + PropertyChanged(inID, inScope, inElement); + break; + } +#endif +#if !CA_NO_AU_UI_FEATURES + case kAudioUnitProperty_SetExternalBuffer: + ca_require(inDataSize >= sizeof(AudioUnitExternalBuffer), InvalidPropertyValue); + ca_require(IsInitialized(), Uninitialized); + { + AudioUnitExternalBuffer &buf = *(AudioUnitExternalBuffer*)inData; + if (intptr_t(buf.buffer) & 0x0F) result = kAudio_ParamError; + else if (inScope == kAudioUnitScope_Input) { + AUInputElement *input = GetInput(inElement); + input->UseExternalBuffer(buf); + } else { + AUOutputElement *output = GetOutput(inElement); + output->UseExternalBuffer(buf); + } + } + break; + + case kAudioUnitProperty_ContextName: + { + ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue); + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + CFStringRef inStr = *(CFStringRef *)inData; + if (mContextName) CFRelease(mContextName); + if (inStr) CFRetain(inStr); + mContextName = inStr; + PropertyChanged(inID, inScope, inElement); + } + break; + +#endif // !CA_NO_AU_UI_FEATURES + + case kAudioUnitProperty_NickName: + { + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inDataSize == sizeof(CFStringRef), InvalidPropertyValue); + CFStringRef inStr = *(CFStringRef *)inData; + if (mNickName) CFRelease(mNickName); + if (inStr) CFRetain(inStr); + mNickName = inStr; + PropertyChanged(inID, inScope, inElement); + break; + } + + default: + result = SetProperty(inID, inScope, inElement, inData, inDataSize); + if (result == noErr) + PropertyChanged(inID, inScope, inElement); + + break; + } + return result; +NotWritable: + return kAudioUnitErr_PropertyNotWritable; +InvalidFormat: + return kAudioUnitErr_FormatNotSupported; +#if !CA_NO_AU_UI_FEATURES +Uninitialized: + return kAudioUnitErr_Uninitialized; +#endif +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || CA_USE_AUDIO_PLUGIN_ONLY +Initialized: + return kAudioUnitErr_Initialized; +#endif +InvalidScope: + return kAudioUnitErr_InvalidScope; +InvalidProperty: + return kAudioUnitErr_InvalidProperty; +InvalidPropertyValue: + return kAudioUnitErr_InvalidPropertyValue; +InvalidElement: + return kAudioUnitErr_InvalidElement; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::DispatchRemovePropertyValue (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement) +{ + OSStatus result = noErr; + switch (inID) + { + case kAudioUnitProperty_AudioChannelLayout: + { + result = RemoveAudioChannelLayout(inScope, inElement); + if (result == noErr) + PropertyChanged(inID, inScope, inElement); + break; + } + +#if !CA_NO_AU_HOST_CALLBACKS + case kAudioUnitProperty_HostCallbacks: + { + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + bool hasValue = false; + void* ptr = &mHostCallbackInfo; + for (unsigned int i = 0; i < sizeof (HostCallbackInfo); ++i) { + if (static_cast(ptr)[i]) { + hasValue = true; + break; + } + } + if (hasValue) { + memset (&mHostCallbackInfo, 0, sizeof (HostCallbackInfo)); + PropertyChanged(inID, inScope, inElement); + } + break; + } +#endif +#if !CA_NO_AU_UI_FEATURES + case kAudioUnitProperty_ContextName: + if (mContextName) CFRelease(mContextName); + mContextName = NULL; + result = noErr; + break; + +#endif // !CA_NO_AU_UI_FEATURES + + case kAudioUnitProperty_NickName: + { + if(inScope == kAudioUnitScope_Global) { + if (mNickName) CFRelease(mNickName); + mNickName = NULL; + PropertyChanged(inID, inScope, inElement); + } else { + result = kAudioUnitErr_InvalidScope; + } + break; + } + + default: + result = RemovePropertyValue (inID, inScope, inElement); + break; + } + + return result; +#if !CA_NO_AU_UI_FEATURES || !CA_NO_AU_HOST_CALLBACKS +InvalidScope: + return kAudioUnitErr_InvalidScope; +#endif +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::GetPropertyInfo( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable) +{ + return kAudioUnitErr_InvalidProperty; +} + + +//_____________________________________________________________________________ +// +OSStatus AUBase::GetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData) +{ + return kAudioUnitErr_InvalidProperty; +} + + +//_____________________________________________________________________________ +// +OSStatus AUBase::SetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize) +{ + return kAudioUnitErr_InvalidProperty; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::RemovePropertyValue ( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement) +{ + return kAudioUnitErr_InvalidPropertyValue; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::AddPropertyListener( AudioUnitPropertyID inID, + AudioUnitPropertyListenerProc inProc, + void * inProcRefCon) +{ + PropertyListener pl; + + pl.propertyID = inID; + pl.listenerProc = inProc; + pl.listenerRefCon = inProcRefCon; + + if (mPropertyListeners.empty()) + mPropertyListeners.reserve(32); + mPropertyListeners.push_back(pl); + + return noErr; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::RemovePropertyListener( AudioUnitPropertyID inID, + AudioUnitPropertyListenerProc inProc, + void * inProcRefCon, + bool refConSpecified) +{ + // iterate in reverse so that it's safe to erase in the middle of the vector + for (int i = (int)mPropertyListeners.size(); --i >=0; ) { + PropertyListeners::iterator it = mPropertyListeners.begin() + i; + if ((*it).propertyID == inID && (*it).listenerProc == inProc && (!refConSpecified || (*it).listenerRefCon == inProcRefCon)) + mPropertyListeners.erase(it); + } + return noErr; +} + +//_____________________________________________________________________________ +// +void AUBase::PropertyChanged( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement) +{ + for (PropertyListeners::iterator it = mPropertyListeners.begin(); it != mPropertyListeners.end(); ++it) + if ((*it).propertyID == inID) + ((*it).listenerProc)((*it).listenerRefCon, mComponentInstance, inID, inScope, inElement); +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::SetRenderNotification( AURenderCallback inProc, + void * inRefCon) +{ + if (inProc == NULL) + return kAudio_ParamError; + + mRenderCallbacksTouched = true; + mRenderCallbacks.deferred_add(RenderCallback(inProc, inRefCon)); + // this will do nothing if it's already in the list + return noErr; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::RemoveRenderNotification( AURenderCallback inProc, + void * inRefCon) +{ + mRenderCallbacks.deferred_remove(RenderCallback(inProc, inRefCon)); + return noErr; // error? +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::GetParameter( AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + AudioUnitParameterValue & outValue) +{ + AUElement *elem = SafeGetElement(inScope, inElement); + outValue = elem->GetParameter(inID); + return noErr; +} + + +//_____________________________________________________________________________ +// +OSStatus AUBase::SetParameter( AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + AudioUnitParameterValue inValue, + UInt32 inBufferOffsetInFrames) +{ + AUElement *elem = SafeGetElement(inScope, inElement); + elem->SetParameter(inID, inValue); + return noErr; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::ScheduleParameter ( const AudioUnitParameterEvent *inParameterEvent, + UInt32 inNumEvents) +{ + bool canScheduleParameters = CanScheduleParameters(); + + for (UInt32 i = 0; i < inNumEvents; ++i) + { + if (inParameterEvent[i].eventType == kParameterEvent_Immediate) + { + SetParameter (inParameterEvent[i].parameter, + inParameterEvent[i].scope, + inParameterEvent[i].element, + inParameterEvent[i].eventValues.immediate.value, + inParameterEvent[i].eventValues.immediate.bufferOffset); + } + if (canScheduleParameters) { + mParamList.push_back (inParameterEvent[i]); + } + } + + return noErr; +} + +// ____________________________________________________________________________ +// +static bool SortParameterEventList(const AudioUnitParameterEvent &ev1, const AudioUnitParameterEvent &ev2 ) +{ + int offset1 = ev1.eventType == kParameterEvent_Immediate ? ev1.eventValues.immediate.bufferOffset : ev1.eventValues.ramp.startBufferOffset; + int offset2 = ev2.eventType == kParameterEvent_Immediate ? ev2.eventValues.immediate.bufferOffset : ev2.eventValues.ramp.startBufferOffset; + + if(offset1 < offset2) return true; + return false; +} + + +// ____________________________________________________________________________ +// +OSStatus AUBase::ProcessForScheduledParams( ParameterEventList &inParamList, + UInt32 inFramesToProcess, + void *inUserData ) +{ + OSStatus result = noErr; + + int totalFramesToProcess = inFramesToProcess; + + int framesRemaining = totalFramesToProcess; + + unsigned int currentStartFrame = 0; // start of the whole buffer + + + + // sort the ParameterEventList by startBufferOffset + std::sort(inParamList.begin(), inParamList.end(), SortParameterEventList); + + ParameterEventList::iterator iter = inParamList.begin(); + + + while(framesRemaining > 0 ) + { + // first of all, go through the ramped automation events and find out where the next + // division of our whole buffer will be + + int currentEndFrame = totalFramesToProcess; // start out assuming we'll process all the way to + // the end of the buffer + + iter = inParamList.begin(); + + // find the next break point + while(iter != inParamList.end() ) + { + AudioUnitParameterEvent &event = *iter; + + int offset = event.eventType == kParameterEvent_Immediate ? event.eventValues.immediate.bufferOffset : event.eventValues.ramp.startBufferOffset; + + if(offset > (int)currentStartFrame && offset < currentEndFrame ) + { + currentEndFrame = offset; + break; + } + + // consider ramp end to be a possible choice (there may be gaps in the supplied ramp events) + if(event.eventType == kParameterEvent_Ramped ) + { + offset = event.eventValues.ramp.startBufferOffset + event.eventValues.ramp.durationInFrames; + + if(offset > (int)currentStartFrame && offset < currentEndFrame ) + { + currentEndFrame = offset; + } + } + + iter++; + } + + int framesThisTime = currentEndFrame - currentStartFrame; + + // next, setup the parameter maps to be current for the ramp parameters active during + // this time segment... + + for(ParameterEventList::iterator iter2 = inParamList.begin(); iter2 != inParamList.end(); iter2++ ) + { + AudioUnitParameterEvent &event = *iter2; + + bool eventFallsInSlice; + + + if(event.eventType == kParameterEvent_Ramped) + eventFallsInSlice = event.eventValues.ramp.startBufferOffset < currentEndFrame + && event.eventValues.ramp.startBufferOffset + event.eventValues.ramp.durationInFrames > currentStartFrame; + else /* kParameterEvent_Immediate */ + // actually, for the same parameter, there may be future immediate events which override this one, + // but it's OK since the event list is sorted in time order, we're guaranteed to end up with the current one + eventFallsInSlice = event.eventValues.immediate.bufferOffset <= currentStartFrame; + + if(eventFallsInSlice) + { + AUElement *element = GetElement(event.scope, event.element ); + + if(element) element->SetScheduledEvent( event.parameter, + event, + currentStartFrame, + currentEndFrame - currentStartFrame ); + } + } + + + + // Finally, actually do the processing for this slice..... + + result = ProcessScheduledSlice( inUserData, + currentStartFrame, + framesThisTime, + inFramesToProcess ); + + if(result != noErr) break; + + framesRemaining -= framesThisTime; + currentStartFrame = currentEndFrame; // now start from where we left off last time + } + + return result; +} + +//_____________________________________________________________________________ +// +void AUBase::SetWantsRenderThreadID (bool inFlag) +{ + if (inFlag == mWantsRenderThreadID) + return; + + mWantsRenderThreadID = inFlag; + if (!mWantsRenderThreadID) + mRenderThreadID = NULL; +} + +//_____________________________________________________________________________ +// + +//_____________________________________________________________________________ +// +OSStatus AUBase::DoRender( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inBusNumber, + UInt32 inFramesToProcess, + AudioBufferList & ioData) +{ + OSStatus theError; + RenderCallbackList::iterator rcit; + + AUTRACE(kCATrace_AUBaseRenderStart, mComponentInstance, (uintptr_t)this, inBusNumber, inFramesToProcess, (uintptr_t)ioData.mBuffers[0].mData); + DISABLE_DENORMALS + + try { + ca_require(IsInitialized(), Uninitialized); + ca_require(mAudioUnitAPIVersion >= 2, ParamErr); + if (inFramesToProcess > mMaxFramesPerSlice) { + static time_t lastTimeMessagePrinted = 0; + time_t now = time(NULL); + if (now != lastTimeMessagePrinted) { + lastTimeMessagePrinted = now; + syslog(LOG_ERR, "kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=%u, mMaxFramesPerSlice=%u", (unsigned)inFramesToProcess, (unsigned)mMaxFramesPerSlice); + DebugMessageN4("%s:%d inFramesToProcess=%u, mMaxFramesPerSlice=%u; TooManyFrames", __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)mMaxFramesPerSlice); + } + goto TooManyFrames; + } + ca_require (!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr); + + AUOutputElement *output = GetOutput(inBusNumber); // will throw if non-existant + if (output->GetStreamFormat().NumberChannelStreams() != ioData.mNumberBuffers) { + DebugMessageN4("%s:%d ioData.mNumberBuffers=%u, output->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError", + __FILE__, __LINE__, (unsigned)ioData.mNumberBuffers, (unsigned)output->GetStreamFormat().NumberChannelStreams()); + goto ParamErr; + } + + unsigned expectedBufferByteSize = inFramesToProcess * output->GetStreamFormat().mBytesPerFrame; + for (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) { + AudioBuffer &buf = ioData.mBuffers[ibuf]; + if (buf.mData != NULL) { + // only care about the size if the buffer is non-null + if (buf.mDataByteSize < expectedBufferByteSize) { + // if the buffer is too small, we cannot render safely. kAudio_ParamError. + DebugMessageN7("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError", + __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)output->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibuf, (unsigned)buf.mDataByteSize); + goto ParamErr; + } + // Some clients incorrectly pass bigger buffers than expectedBufferByteSize. + // We will generally set the buffer size at the end of rendering, before we return. + // However we should ensure that no one, DURING rendering, READS a + // potentially incorrect size. This can lead to doing too much work, or + // reading past the end of an input buffer into unmapped memory. + buf.mDataByteSize = expectedBufferByteSize; + } + } + + if (WantsRenderThreadID()) + { + #if TARGET_OS_MAC + mRenderThreadID = pthread_self(); + #elif TARGET_OS_WIN32 + mRenderThreadID = GetCurrentThreadId(); + #endif + } + + AudioUnitRenderActionFlags flags; + if (mRenderCallbacksTouched) { + mRenderCallbacks.update(); + flags = ioActionFlags | kAudioUnitRenderAction_PreRender; + for (rcit = mRenderCallbacks.begin(); rcit != mRenderCallbacks.end(); ++rcit) { + RenderCallback &rc = *rcit; + AUTRACE(kCATrace_AUBaseRenderCallbackStart, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 1, 0); + (*(AURenderCallback)rc.mRenderNotify)(rc.mRenderNotifyRefCon, + &flags, + &inTimeStamp, inBusNumber, inFramesToProcess, &ioData); + AUTRACE(kCATrace_AUBaseRenderCallbackEnd, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 1, 0); + } + } + + theError = DoRenderBus(ioActionFlags, inTimeStamp, inBusNumber, output, inFramesToProcess, ioData); + + if (mRenderCallbacksTouched) { + flags = ioActionFlags | kAudioUnitRenderAction_PostRender; + + if (SetRenderError (theError)) { + flags |= kAudioUnitRenderAction_PostRenderError; + } + + for (rcit = mRenderCallbacks.begin(); rcit != mRenderCallbacks.end(); ++rcit) { + RenderCallback &rc = *rcit; + AUTRACE(kCATrace_AUBaseRenderCallbackStart, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 2, 0); + (*(AURenderCallback)rc.mRenderNotify)(rc.mRenderNotifyRefCon, + &flags, + &inTimeStamp, inBusNumber, inFramesToProcess, &ioData); + AUTRACE(kCATrace_AUBaseRenderCallbackEnd, mComponentInstance, (intptr_t)this, (intptr_t)rc.mRenderNotify, 2, 0); + } + } + + // The vector's being emptied + // because these events should only apply to this Render cycle, so anything + // left over is from a preceding cycle and should be dumped. New scheduled + // parameters must be scheduled from the next pre-render callback. + if (!mParamList.empty()) + mParamList.clear(); + + } + catch (OSStatus err) { + theError = err; + goto errexit; + } + catch (...) { + theError = -1; + goto errexit; + } +done: + RESTORE_DENORMALS + AUTRACE(kCATrace_AUBaseRenderEnd, mComponentInstance, (intptr_t)this, theError, ioActionFlags, CATrace::ablData(ioData)); + + return theError; + +Uninitialized: theError = kAudioUnitErr_Uninitialized; goto errexit; +ParamErr: theError = kAudio_ParamError; goto errexit; +TooManyFrames: theError = kAudioUnitErr_TooManyFramesToProcess; goto errexit; +errexit: + DebugMessageN2 (" from %s, render err: %d", GetLoggingString(), (int)theError); + SetRenderError(theError); + goto done; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::DoProcess ( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inFramesToProcess, + AudioBufferList & ioData) +{ + OSStatus theError; + AUTRACE(kCATrace_AUBaseRenderStart, mComponentInstance, (intptr_t)this, -1, inFramesToProcess, 0); + DISABLE_DENORMALS + + try { + + if (!(ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)) { + ca_require(IsInitialized(), Uninitialized); + ca_require(inFramesToProcess <= mMaxFramesPerSlice, TooManyFrames); + ca_require(!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr); + + AUInputElement *input = GetInput(0); // will throw if non-existant + if (input->GetStreamFormat().NumberChannelStreams() != ioData.mNumberBuffers) { + DebugMessageN4("%s:%d ioData.mNumberBuffers=%u, input->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError", + __FILE__, __LINE__, (unsigned)ioData.mNumberBuffers, (unsigned)input->GetStreamFormat().NumberChannelStreams()); + goto ParamErr; + } + + unsigned expectedBufferByteSize = inFramesToProcess * input->GetStreamFormat().mBytesPerFrame; + for (unsigned ibuf = 0; ibuf < ioData.mNumberBuffers; ++ibuf) { + AudioBuffer &buf = ioData.mBuffers[ibuf]; + if (buf.mData != NULL) { + // only care about the size if the buffer is non-null + if (buf.mDataByteSize < expectedBufferByteSize) { + // if the buffer is too small, we cannot render safely. kAudio_ParamError. + DebugMessageN7("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioData.mBuffers[%u].mDataByteSize=%u; kAudio_ParamError", + __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)input->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibuf, (unsigned)buf.mDataByteSize); + goto ParamErr; + } + // Some clients incorrectly pass bigger buffers than expectedBufferByteSize. + // We will generally set the buffer size at the end of rendering, before we return. + // However we should ensure that no one, DURING rendering, READS a + // potentially incorrect size. This can lead to doing too much work, or + // reading past the end of an input buffer into unmapped memory. + buf.mDataByteSize = expectedBufferByteSize; + } + } + } + + if (WantsRenderThreadID()) + { + #if TARGET_OS_MAC + mRenderThreadID = pthread_self(); + #elif TARGET_OS_WIN32 + mRenderThreadID = GetCurrentThreadId(); + #endif + } + + if (NeedsToRender (inTimeStamp)) { + theError = ProcessBufferLists (ioActionFlags, ioData, ioData, inFramesToProcess); + } else + theError = noErr; + + } + catch (OSStatus err) { + theError = err; + goto errexit; + } + catch (...) { + theError = -1; + goto errexit; + } +done: + RESTORE_DENORMALS + AUTRACE(kCATrace_AUBaseRenderEnd, mComponentInstance, (intptr_t)this, theError, ioActionFlags, CATrace::ablData(ioData)); + + return theError; + +Uninitialized: theError = kAudioUnitErr_Uninitialized; goto errexit; +ParamErr: theError = kAudio_ParamError; goto errexit; +TooManyFrames: theError = kAudioUnitErr_TooManyFramesToProcess; goto errexit; +errexit: + DebugMessageN2 (" from %s, process err: %d", GetLoggingString(), (int)theError); + SetRenderError(theError); + goto done; +} + +OSStatus AUBase::DoProcessMultiple ( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inFramesToProcess, + UInt32 inNumberInputBufferLists, + const AudioBufferList ** inInputBufferLists, + UInt32 inNumberOutputBufferLists, + AudioBufferList ** ioOutputBufferLists) +{ + OSStatus theError; + DISABLE_DENORMALS + + try { + + if (!(ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/)) { + ca_require(IsInitialized(), Uninitialized); + ca_require(inFramesToProcess <= mMaxFramesPerSlice, TooManyFrames); + ca_require (!UsesFixedBlockSize() || inFramesToProcess == GetMaxFramesPerSlice(), ParamErr); + + for (unsigned ibl = 0; ibl < inNumberInputBufferLists; ++ibl) { + if (inInputBufferLists[ibl] != NULL) { + AUInputElement *input = GetInput(ibl); // will throw if non-existant + unsigned expectedBufferByteSize = inFramesToProcess * input->GetStreamFormat().mBytesPerFrame; + + if (input->GetStreamFormat().NumberChannelStreams() != inInputBufferLists[ibl]->mNumberBuffers) { + DebugMessageN5("%s:%d inInputBufferLists[%u]->mNumberBuffers=%u, input->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError", + __FILE__, __LINE__, ibl, (unsigned)inInputBufferLists[ibl]->mNumberBuffers, (unsigned)input->GetStreamFormat().NumberChannelStreams()); + goto ParamErr; + } + + for (unsigned ibuf = 0; ibuf < inInputBufferLists[ibl]->mNumberBuffers; ++ibuf) { + const AudioBuffer &buf = inInputBufferLists[ibl]->mBuffers[ibuf]; + if (buf.mData != NULL) { + if (buf.mDataByteSize < expectedBufferByteSize) { + // the buffer is too small + DebugMessageN8("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; inInputBufferLists[%u].mBuffers[%u].mDataByteSize=%u; kAudio_ParamError", + __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)input->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, ibl, ibuf, (unsigned)buf.mDataByteSize); + goto ParamErr; + } + } else { + // the buffer must exist + goto ParamErr; + } + } + } else { + // skip NULL input audio buffer list + } + } + + for (unsigned obl = 0; obl < inNumberOutputBufferLists; ++obl) { + if (ioOutputBufferLists[obl] != NULL) { + AUOutputElement *output = GetOutput(obl); // will throw if non-existant + unsigned expectedBufferByteSize = inFramesToProcess * output->GetStreamFormat().mBytesPerFrame; + + if (output->GetStreamFormat().NumberChannelStreams() != ioOutputBufferLists[obl]->mNumberBuffers) { + DebugMessageN5("%s:%d ioOutputBufferLists[%u]->mNumberBuffers=%u, output->GetStreamFormat().NumberChannelStreams()=%u; kAudio_ParamError", + __FILE__, __LINE__, obl, (unsigned)ioOutputBufferLists[obl]->mNumberBuffers, (unsigned)output->GetStreamFormat().NumberChannelStreams()); + goto ParamErr; + } + + for (unsigned obuf = 0; obuf < ioOutputBufferLists[obl]->mNumberBuffers; ++obuf) { + AudioBuffer &buf = ioOutputBufferLists[obl]->mBuffers[obuf]; + if (buf.mData != NULL) { + // only care about the size if the buffer is non-null + if (buf.mDataByteSize < expectedBufferByteSize) { + // if the buffer is too small, we cannot render safely. kAudio_ParamError. + DebugMessageN8("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioOutputBufferLists[%u]->mBuffers[%u].mDataByteSize=%u; kAudio_ParamError", + __FILE__, __LINE__, (unsigned)inFramesToProcess, (unsigned)output->GetStreamFormat().mBytesPerFrame, expectedBufferByteSize, obl, obuf, (unsigned)buf.mDataByteSize); + goto ParamErr; + } + // Some clients incorrectly pass bigger buffers than expectedBufferByteSize. + // We will generally set the buffer size at the end of rendering, before we return. + // However we should ensure that no one, DURING rendering, READS a + // potentially incorrect size. This can lead to doing too much work, or + // reading past the end of an input buffer into unmapped memory. + buf.mDataByteSize = expectedBufferByteSize; + } + } + } else { + // skip NULL output audio buffer list + } + } + } + + if (WantsRenderThreadID()) + { +#if TARGET_OS_MAC + mRenderThreadID = pthread_self(); +#elif TARGET_OS_WIN32 + mRenderThreadID = GetCurrentThreadId(); +#endif + } + + if (NeedsToRender (inTimeStamp)) { + theError = ProcessMultipleBufferLists (ioActionFlags, inFramesToProcess, inNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists, ioOutputBufferLists); + } else + theError = noErr; + } + catch (OSStatus err) { + theError = err; + goto errexit; + } + catch (...) { + theError = -1; + goto errexit; + } +done: + RESTORE_DENORMALS + + return theError; + +Uninitialized: theError = kAudioUnitErr_Uninitialized; goto errexit; +ParamErr: theError = kAudio_ParamError; goto errexit; +TooManyFrames: theError = kAudioUnitErr_TooManyFramesToProcess; goto errexit; +errexit: + DebugMessageN2 (" from %s, processmultiple err: %d", GetLoggingString(), (int)theError); + SetRenderError(theError); + goto done; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::SetInputCallback( UInt32 inPropertyID, + AudioUnitElement inElement, + AURenderCallback inProc, + void * inRefCon) +{ + AUInputElement *input = GetInput(inElement); // may throw + + input->SetInputCallback(inProc, inRefCon); + PropertyChanged(inPropertyID, kAudioUnitScope_Input, inElement); + + return noErr; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::SetConnection( const AudioUnitConnection & inConnection) +{ + + OSStatus err; + AUInputElement *input = GetInput(inConnection.destInputNumber); // may throw + + if (inConnection.sourceAudioUnit) { + // connecting, not disconnecting + CAStreamBasicDescription sourceDesc; + UInt32 size = sizeof(CAStreamBasicDescription); + ca_require_noerr(err = AudioUnitGetProperty( + inConnection.sourceAudioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + inConnection.sourceOutputNumber, + &sourceDesc, + &size), errexit); + ca_require_noerr(err = DispatchSetProperty (kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, inConnection.destInputNumber, + &sourceDesc, sizeof(CAStreamBasicDescription)), errexit); + } + input->SetConnection(inConnection); + + PropertyChanged(kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, inConnection.destInputNumber); + return noErr; + +errexit: + return err; +} + +//_____________________________________________________________________________ +// +UInt32 AUBase::SupportedNumChannels ( const AUChannelInfo** outInfo) +{ + return 0; +} + +//_____________________________________________________________________________ +// +bool AUBase::ValidFormat( AudioUnitScope inScope, + AudioUnitElement inElement, + const CAStreamBasicDescription & inNewFormat) +{ + return FormatIsCanonical(inNewFormat); +} + +//_____________________________________________________________________________ +// +bool AUBase::IsStreamFormatWritable( AudioUnitScope scope, + AudioUnitElement element) +{ + switch (scope) { + case kAudioUnitScope_Input: + { + AUInputElement *input = GetInput(element); + if (input->HasConnection()) return false; // can't write format when input comes from connection + } + // ... fall ... + case kAudioUnitScope_Output: + return StreamFormatWritable(scope, element); + +//#warning "aliasing of global scope format should be pushed to subclasses" + case kAudioUnitScope_Global: + return StreamFormatWritable(kAudioUnitScope_Output, 0); + } + return false; +} + +//_____________________________________________________________________________ +// +const CAStreamBasicDescription & + AUBase::GetStreamFormat( AudioUnitScope inScope, + AudioUnitElement inElement) +{ +//#warning "aliasing of global scope format should be pushed to subclasses" + AUIOElement *element; + + switch (inScope) { + case kAudioUnitScope_Input: + element = Inputs().GetIOElement(inElement); + break; + case kAudioUnitScope_Output: + element = Outputs().GetIOElement(inElement); + break; + case kAudioUnitScope_Global: // global stream description is an alias for that of output 0 + element = Outputs().GetIOElement(0); + break; + default: + COMPONENT_THROW(kAudioUnitErr_InvalidScope); + } + return element->GetStreamFormat(); +} + +OSStatus AUBase::SetBusCount( AudioUnitScope inScope, + UInt32 inCount) +{ + if (IsInitialized()) + return kAudioUnitErr_Initialized; + + GetScope(inScope).SetNumberOfElements(inCount); + return noErr; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::ChangeStreamFormat( AudioUnitScope inScope, + AudioUnitElement inElement, + const CAStreamBasicDescription & inPrevFormat, + const CAStreamBasicDescription & inNewFormat) +{ +//#warning "aliasing of global scope format should be pushed to subclasses" + AUIOElement *element; + + switch (inScope) { + case kAudioUnitScope_Input: + element = Inputs().GetIOElement(inElement); + break; + case kAudioUnitScope_Output: + element = Outputs().GetIOElement(inElement); + break; + case kAudioUnitScope_Global: + element = Outputs().GetIOElement(0); + break; + default: + COMPONENT_THROW(kAudioUnitErr_InvalidScope); + } + element->SetStreamFormat(inNewFormat); + PropertyChanged(kAudioUnitProperty_StreamFormat, inScope, inElement); + return noErr; +} + +UInt32 AUBase::GetChannelLayoutTags( AudioUnitScope inScope, + AudioUnitElement inElement, + AudioChannelLayoutTag * outLayoutTags) +{ + return GetIOElement(inScope, inElement)->GetChannelLayoutTags(outLayoutTags); +} + +UInt32 AUBase::GetAudioChannelLayout( AudioUnitScope scope, + AudioUnitElement element, + AudioChannelLayout * outLayoutPtr, + Boolean & outWritable) +{ + AUIOElement * el = GetIOElement(scope, element); + return el->GetAudioChannelLayout(outLayoutPtr, outWritable); +} + +OSStatus AUBase::RemoveAudioChannelLayout( AudioUnitScope inScope, + AudioUnitElement inElement) +{ + OSStatus result = noErr; + AUIOElement * el = GetIOElement(inScope, inElement); + Boolean writable; + if (el->GetAudioChannelLayout(NULL, writable)) { + result = el->RemoveAudioChannelLayout(); + } + return result; +} + +OSStatus AUBase::SetAudioChannelLayout( AudioUnitScope inScope, + AudioUnitElement inElement, + const AudioChannelLayout * inLayout) +{ + AUIOElement* ioEl = GetIOElement (inScope, inElement); + + // the num channels of the layout HAS TO MATCH the current channels of the Element's stream format + UInt32 currentChannels = ioEl->GetStreamFormat().NumberChannels(); + UInt32 numChannelsInLayout = CAAudioChannelLayout::NumberChannels(*inLayout); + if (currentChannels != numChannelsInLayout) + return kAudioUnitErr_InvalidPropertyValue; + + UInt32 numLayouts = GetChannelLayoutTags (inScope, inElement, NULL); + if (numLayouts == 0) + return kAudioUnitErr_InvalidProperty; + AudioChannelLayoutTag *tags = (AudioChannelLayoutTag *)CA_malloc (numLayouts * sizeof (AudioChannelLayoutTag)); + GetChannelLayoutTags (inScope, inElement, tags); + bool foundTag = false; + for (unsigned int i = 0; i < numLayouts; ++i) { + if (tags[i] == inLayout->mChannelLayoutTag || tags[i] == kAudioChannelLayoutTag_UseChannelDescriptions) { + foundTag = true; + break; + } + } + free(tags); + + if (foundTag == false) + return kAudioUnitErr_InvalidPropertyValue; + + return ioEl->SetAudioChannelLayout(*inLayout); +} + +static void AddNumToDictionary (CFMutableDictionaryRef dict, CFStringRef key, SInt32 value) +{ + CFNumberRef num = CFNumberCreate (NULL, kCFNumberSInt32Type, &value); + CFDictionarySetValue (dict, key, num); + CFRelease (num); +} + +#define kCurrentSavedStateVersion 0 + +OSStatus AUBase::SaveState( CFPropertyListRef * outData) +{ + AudioComponentDescription desc = GetComponentDescription(); + + CFMutableDictionaryRef dict = CFDictionaryCreateMutable (NULL, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + +// first step -> save the version to the data ref + SInt32 value = kCurrentSavedStateVersion; + AddNumToDictionary (dict, kVersionString, value); + +// second step -> save the component type, subtype, manu to the data ref + value = desc.componentType; + AddNumToDictionary (dict, kTypeString, value); + + value = desc.componentSubType; + AddNumToDictionary (dict, kSubtypeString, value); + + value = desc.componentManufacturer; + AddNumToDictionary (dict, kManufacturerString, value); + +// fourth step -> save the state of all parameters on all scopes and elements + CFMutableDataRef data = CFDataCreateMutable(NULL, 0); + for (AudioUnitScope iscope = 0; iscope < 3; ++iscope) { + AUScope &scope = GetScope(iscope); + scope.SaveState (data); + } + + SaveExtendedScopes(data); + +// save all this in the data section of the dictionary + CFDictionarySetValue(dict, kDataString, data); + CFRelease (data); + +//OK - now we're going to do some properties +//save the preset name... + CFDictionarySetValue (dict, kNameString, mCurrentPreset.presetName); + +// Does the unit support the RenderQuality property - if so, save it... + value = 0; + OSStatus result = DispatchGetProperty (kAudioUnitProperty_RenderQuality, + kAudioUnitScope_Global, + 0, + &value); + + if (result == noErr) { + AddNumToDictionary (dict, kRenderQualityString, value); + } + +// Does the unit support the CPULoad Quality property - if so, save it... + Float32 cpuLoad; + result = DispatchGetProperty (6/*kAudioUnitProperty_CPULoad*/, + kAudioUnitScope_Global, + 0, + &cpuLoad); + + if (result == noErr) { + CFNumberRef num = CFNumberCreate (NULL, kCFNumberFloatType, &cpuLoad); + CFDictionarySetValue (dict, kCPULoadString, num); + CFRelease (num); + } + +// Do we have any element names for any of our scopes? + // first check to see if we have any names... + bool foundName = false; + for (AudioUnitScope i = 0; i < kNumScopes; ++i) { + foundName = GetScope (i).HasElementWithName(); + if (foundName) + break; + } + // OK - we found a name away we go... + if (foundName) { + CFMutableDictionaryRef nameDict = CFDictionaryCreateMutable (NULL, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + for (AudioUnitScope i = 0; i < kNumScopes; ++i) { + GetScope (i).AddElementNamesToDict (nameDict); + } + + CFDictionarySetValue (dict, kElementNameString, nameDict); + CFRelease (nameDict); + } + +// we're done!!! + *outData = dict; + + return noErr; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::RestoreState( CFPropertyListRef plist) +{ + if (CFGetTypeID(plist) != CFDictionaryGetTypeID()) return kAudioUnitErr_InvalidPropertyValue; + + AudioComponentDescription desc = GetComponentDescription(); + + CFDictionaryRef dict = static_cast(plist); + +// zeroeth step - make sure the Part key is NOT present, as this method is used +// to restore the GLOBAL state of the dictionary + if (CFDictionaryContainsKey (dict, kPartString)) + return kAudioUnitErr_InvalidPropertyValue; + +// first step -> check the saved version in the data ref +// at this point we're only dealing with version==0 + CFNumberRef cfnum = reinterpret_cast(CFDictionaryGetValue (dict, kVersionString)); + if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue; + SInt32 value; + CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value); + if (value != kCurrentSavedStateVersion) return kAudioUnitErr_InvalidPropertyValue; + +// second step -> check that this data belongs to this kind of audio unit +// by checking the component subtype and manuID +// We're not checking the type, since there may be different versions (effect, format-converter, offline) +// of essentially the same AU + cfnum = reinterpret_cast(CFDictionaryGetValue (dict, kSubtypeString)); + if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue; + CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value); + if (UInt32(value) != desc.componentSubType) return kAudioUnitErr_InvalidPropertyValue; + + cfnum = reinterpret_cast(CFDictionaryGetValue (dict, kManufacturerString)); + if (cfnum == NULL) return kAudioUnitErr_InvalidPropertyValue; + CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value); + if (UInt32(value) != desc.componentManufacturer) return kAudioUnitErr_InvalidPropertyValue; + +// fourth step -> restore the state of all of the parameters for each scope and element + CFDataRef data = reinterpret_cast(CFDictionaryGetValue (dict, kDataString)); + if (data != NULL) + { + const UInt8 *p, *pend; + + p = CFDataGetBytePtr(data); + pend = p + CFDataGetLength(data); + + // we have a zero length data, which may just mean there were no parameters to save! + // if (p >= pend) return noErr; + + while (p < pend) { + UInt32 scopeIdx = CFSwapInt32BigToHost(*(UInt32 *)p); + p += sizeof(UInt32); + + AUScope &scope = GetScope(scopeIdx); + p = scope.RestoreState(p); + } + } + +//OK - now we're going to do some properties +//restore the preset name... + CFStringRef name = reinterpret_cast(CFDictionaryGetValue (dict, kNameString)); + if (mCurrentPreset.presetName) CFRelease (mCurrentPreset.presetName); + if (name) + { + mCurrentPreset.presetName = name; + mCurrentPreset.presetNumber = -1; + } + else { // no name entry make the default one + mCurrentPreset.presetName = kUntitledString; + mCurrentPreset.presetNumber = -1; + } + + CFRetain (mCurrentPreset.presetName); +#if !CA_USE_AUDIO_PLUGIN_ONLY +#ifndef __LP64__ + PropertyChanged(kAudioUnitProperty_CurrentPreset, kAudioUnitScope_Global, 0); +#endif +#endif + PropertyChanged(kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0); + +// Does the dict contain render quality information? + if (CFDictionaryGetValueIfPresent (dict, kRenderQualityString, reinterpret_cast(&cfnum))) + { + CFNumberGetValue (cfnum, kCFNumberSInt32Type, &value); + DispatchSetProperty (kAudioUnitProperty_RenderQuality, + kAudioUnitScope_Global, + 0, + &value, + sizeof(value)); + } + +// Does the unit support the CPULoad Quality property - if so, save it... + if (CFDictionaryGetValueIfPresent (dict, kCPULoadString, reinterpret_cast(&cfnum))) + { + Float32 floatValue; + CFNumberGetValue (cfnum, kCFNumberFloatType, &floatValue); + DispatchSetProperty (6/*kAudioUnitProperty_CPULoad*/, + kAudioUnitScope_Global, + 0, + &floatValue, + sizeof(floatValue)); + } + +// Do we have any element names for any of our scopes? + CFDictionaryRef nameDict; + if (CFDictionaryGetValueIfPresent (dict, kElementNameString, reinterpret_cast(&nameDict))) + { + char string[64]; + for (int i = 0; i < kNumScopes; ++i) + { + snprintf (string, sizeof(string), "%d", i); + CFStringRef key = CFStringCreateWithCString (NULL, string, kCFStringEncodingASCII); + CFDictionaryRef elementDict; + if (CFDictionaryGetValueIfPresent (nameDict, key, reinterpret_cast(&elementDict))) + { + bool didAddElements = GetScope (i).RestoreElementNames (elementDict); + if (didAddElements) + PropertyChanged (kAudioUnitProperty_ElementCount, i, 0); + } + CFRelease (key); + } + } + + return noErr; +} + +OSStatus AUBase::GetPresets ( CFArrayRef * outData) const +{ + return kAudioUnitErr_InvalidProperty; +} + +OSStatus AUBase::NewFactoryPresetSet (const AUPreset & inNewFactoryPreset) +{ + return kAudioUnitErr_InvalidProperty; +} + +OSStatus AUBase::NewCustomPresetSet (const AUPreset & inNewCustomPreset) +{ + CFRelease (mCurrentPreset.presetName); + mCurrentPreset = inNewCustomPreset; + CFRetain (mCurrentPreset.presetName); + return noErr; +} + + // set the default preset for the unit -> the number of the preset MUST be >= 0 + // and the name should be valid, or the preset WON'T take +bool AUBase::SetAFactoryPresetAsCurrent (const AUPreset & inPreset) +{ + if (inPreset.presetNumber < 0 || inPreset.presetName == NULL) return false; + CFRelease (mCurrentPreset.presetName); + mCurrentPreset = inPreset; + CFRetain (mCurrentPreset.presetName); + return true; +} + +#if !CA_USE_AUDIO_PLUGIN_ONLY +int AUBase::GetNumCustomUIComponents () +{ + return 0; +} + +void AUBase::GetUIComponentDescs (ComponentDescription* inDescArray) {} +#endif + +bool AUBase::HasIcon () +{ +#if !CA_NO_AU_UI_FEATURES + CFURLRef url = CopyIconLocation(); + if (url) { + CFRelease (url); + return true; + } +#endif + return false; +} + +CFURLRef AUBase::CopyIconLocation () +{ + return NULL; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::GetParameterList( AudioUnitScope inScope, + AudioUnitParameterID * outParameterList, + UInt32 & outNumParameters) +{ + AUScope &scope = GetScope(inScope); + AUElement *elementWithMostParameters = NULL; + UInt32 maxNumParams = 0; + + int nElems = scope.GetNumberOfElements(); + for (int ielem = 0; ielem < nElems; ++ielem) { + AUElement *element = scope.GetElement(ielem); + UInt32 nParams = element->GetNumberOfParameters(); + if (nParams > maxNumParams) { + maxNumParams = nParams; + elementWithMostParameters = element; + } + } + + if (outParameterList != NULL && elementWithMostParameters != NULL) + elementWithMostParameters->GetParameterList(outParameterList); + + outNumParameters = maxNumParams; + return noErr; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::GetParameterInfo( AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + AudioUnitParameterInfo &outParameterInfo ) +{ + return kAudioUnitErr_InvalidParameter; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::GetParameterValueStrings(AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + CFArrayRef * outStrings) +{ + return kAudioUnitErr_InvalidProperty; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::GetParameterHistoryInfo( AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + Float32 & outUpdatesPerSecond, + Float32 & outHistoryDurationInSeconds) +{ + return kAudioUnitErr_InvalidProperty; +} + + +//_____________________________________________________________________________ +// +OSStatus AUBase::CopyClumpName( AudioUnitScope inScope, + UInt32 inClumpID, + UInt32 inDesiredNameLength, + CFStringRef * outClumpName) +{ + return kAudioUnitErr_InvalidProperty; +} + +//_____________________________________________________________________________ +// +void AUBase::SetNumberOfElements( AudioUnitScope inScope, + UInt32 numElements) +{ + if (inScope == kAudioUnitScope_Global && numElements != 1) + COMPONENT_THROW(kAudioUnitErr_InvalidScope); + + GetScope(inScope).SetNumberOfElements(numElements); +} + +//_____________________________________________________________________________ +// +AUElement * AUBase::CreateElement( AudioUnitScope scope, + AudioUnitElement element) +{ + switch (scope) { + case kAudioUnitScope_Global: + return new AUElement(this); + case kAudioUnitScope_Input: + return new AUInputElement(this); + case kAudioUnitScope_Output: + return new AUOutputElement(this); +#if !CA_BASIC_AU_FEATURES + case kAudioUnitScope_Group: + return new AUElement(this); + case kAudioUnitScope_Part: + return new AUElement(this); +#endif + } + COMPONENT_THROW(kAudioUnitErr_InvalidScope); + + return NULL; // get rid of compiler warning +} + +//_____________________________________________________________________________ +// +bool AUBase::FormatIsCanonical( const CAStreamBasicDescription &f) +{ + return (f.mFormatID == kAudioFormatLinearPCM + && f.mFramesPerPacket == 1 + && f.mBytesPerPacket == f.mBytesPerFrame +// && f.mChannelsPerFrame >= 0 -- this is always true since it's unsigned + // so far, it's a valid PCM format +#if CA_PREFER_FIXED_POINT + && (f.mFormatFlags & kLinearPCMFormatFlagIsFloat) == 0 + && (((f.mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift) == kAudioUnitSampleFractionBits) +#else + && (f.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0 +#endif + && ((f.mChannelsPerFrame == 1) || ((f.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0) == (mAudioUnitAPIVersion == 1)) +#if TARGET_RT_BIG_ENDIAN + && (f.mFormatFlags & kLinearPCMFormatFlagIsBigEndian) != 0 +#else + && (f.mFormatFlags & kLinearPCMFormatFlagIsBigEndian) == 0 +#endif + && f.mBitsPerChannel == 8 * sizeof(AudioUnitSampleType) + && f.mBytesPerFrame == f.NumberInterleavedChannels() * sizeof(AudioUnitSampleType) + ); +} + +//_____________________________________________________________________________ +// +void AUBase::MakeCanonicalFormat( CAStreamBasicDescription & f, + int nChannels) +{ + f.SetAUCanonical(nChannels, mAudioUnitAPIVersion < 2); // interleaved for v1, non for v2 + f.mSampleRate = 0.0; +} + +const Float64 AUBase::kNoLastRenderedSampleTime = -1.; + +#include "AUBaseHelper.h" + +char* AUBase::GetLoggingString () const +{ + if (mLogString) return mLogString; + + AudioComponentDescription desc = GetComponentDescription(); + + const size_t logStringSize = 256; + const_cast(this)->mLogString = new char[logStringSize]; + char str[24]; + char str1[24]; + char str2[24]; + snprintf (const_cast(this)->mLogString, logStringSize, "AU (%p): %s %s %s", + GetComponentInstance(), + CAStringForOSType(desc.componentType, str, sizeof(str)), + CAStringForOSType(desc.componentSubType, str1, sizeof(str1)), + CAStringForOSType(desc.componentManufacturer, str2, sizeof(str2))); + + return mLogString; +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.h new file mode 100644 index 0000000000..bc19c1b1d4 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.h @@ -0,0 +1,1048 @@ +/* + File: AUBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUBase_h__ +#define __AUBase_h__ + +#include + +#if TARGET_OS_MAC + #include +#elif TARGET_OS_WIN32 + #include +#else + #error Unsupported Operating System +#endif + +#include + +#include "AUScopeElement.h" +#include "AUInputElement.h" +#include "AUOutputElement.h" +#include "AUBuffer.h" +#include "CAMath.h" +#include "CAThreadSafeList.h" +#include "CAVectorUnit.h" +#include "CAMutex.h" +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #if !CA_BASIC_AU_FEATURES + #include + #endif +#else + #include "AudioUnit.h" + #if !CA_BASIC_AU_FEATURES + #include "MusicDevice.h" + #endif +#endif + +#ifndef AUTRACE + #define AUTRACE(code, obj, a, b, c, d) +#endif + +#include "AUPlugInDispatch.h" + + + +// ________________________________________________________________________ +// These are to be moved to the public AudioUnit headers + +#define kAUDefaultSampleRate 44100.0 +#if !TARGET_OS_WIN32 +#define kAUDefaultMaxFramesPerSlice 1156 +//this allows enough default frames for a 512 dest 44K and SRC from 96K +// add a padding of 4 frames for any altivec rounding +#else +#define kAUDefaultMaxFramesPerSlice 2048 +#endif + +// ________________________________________________________________________ + +/*! @class AUBase */ +class AUBase : public ComponentBase { +public: + + /*! @ctor AUBase */ + AUBase( AudioComponentInstance inInstance, + UInt32 numInputElements, + UInt32 numOutputElements, + UInt32 numGroupElements = 0); + /*! @dtor AUBase */ + virtual ~AUBase(); + + /*! @method PostConstructor */ + virtual void PostConstructor() { CreateElements(); } + + /*! @method PreDestructor */ + virtual void PreDestructor(); + + /*! @method CreateElements */ + void CreateElements(); + // Called immediately after construction, when virtual methods work. + // Or, a subclass may call this in order to have access to elements + // in its constructor. + + /*! @method CreateExtendedElements */ + virtual void CreateExtendedElements() {} + +#pragma mark - +#pragma mark AU dispatch + // ________________________________________________________________________ + // Virtual methods (mostly) directly corresponding to the entry points. Many of these + // have useful implementations here and will not need overriding. + + /*! @method DoInitialize */ + OSStatus DoInitialize(); + // this implements the entry point and makes sure that initialization + // is only attempted exactly once... + + /*! @method Initialize */ + virtual OSStatus Initialize(); + // ... so that overrides to this method can assume that they will only + // be called exactly once. + + /*! @method IsInitialized */ + bool IsInitialized() const { return mInitialized; } + /*! @method HasBegunInitializing */ + bool HasBegunInitializing() const { return mHasBegunInitializing; } + + /*! @method DoCleanup */ + void DoCleanup(); + // same pattern as with Initialize + + /*! @method Cleanup */ + virtual void Cleanup(); + + /*! @method Reset */ + virtual OSStatus Reset( AudioUnitScope inScope, + AudioUnitElement inElement); + + // Note about GetPropertyInfo, GetProperty, SetProperty: + // Certain properties are trapped out in these dispatch functions and handled with different virtual + // methods. (To discourage hacks and keep vtable size down, these are non-virtual) + + /*! @method DispatchGetPropertyInfo */ + OSStatus DispatchGetPropertyInfo(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable); + + /*! @method DispatchGetProperty */ + OSStatus DispatchGetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData); + + /*! @method DispatchSetProperty */ + OSStatus DispatchSetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize); + + OSStatus DispatchRemovePropertyValue( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement); + + /*! @method GetPropertyInfo */ + virtual OSStatus GetPropertyInfo( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable); + + /*! @method GetProperty */ + virtual OSStatus GetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData); + + /*! @method SetProperty */ + virtual OSStatus SetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize); + + /*! @method ClearPropertyUsage */ + virtual OSStatus RemovePropertyValue ( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement); + + /*! @method AddPropertyListener */ + virtual OSStatus AddPropertyListener( AudioUnitPropertyID inID, + AudioUnitPropertyListenerProc inProc, + void * inProcRefCon); + + /*! @method RemovePropertyListener */ + virtual OSStatus RemovePropertyListener( AudioUnitPropertyID inID, + AudioUnitPropertyListenerProc inProc, + void * inProcRefCon, + bool refConSpecified); + + /*! @method SetRenderNotification */ + virtual OSStatus SetRenderNotification( AURenderCallback inProc, + void * inRefCon); + + /*! @method RemoveRenderNotification */ + virtual OSStatus RemoveRenderNotification( + AURenderCallback inProc, + void * inRefCon); + + /*! @method GetParameter */ + virtual OSStatus GetParameter( AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + AudioUnitParameterValue & outValue); + + /*! @method SetParameter */ + virtual OSStatus SetParameter( AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + AudioUnitParameterValue inValue, + UInt32 inBufferOffsetInFrames); + + /*! @method CanScheduleParams */ + virtual bool CanScheduleParameters() const = 0; + + /*! @method ScheduleParameter */ + virtual OSStatus ScheduleParameter ( const AudioUnitParameterEvent *inParameterEvent, + UInt32 inNumEvents); + + + /*! @method DoRender */ + OSStatus DoRender( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList & ioData); + + + /*! @method Process */ + OSStatus DoProcess ( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inFramesToProcess, + AudioBufferList & ioData); + + /*! @method ProcessMultiple */ + OSStatus DoProcessMultiple ( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inFramesToProcess, + UInt32 inNumberInputBufferLists, + const AudioBufferList ** inInputBufferLists, + UInt32 inNumberOutputBufferLists, + AudioBufferList ** ioOutputBufferLists); + + /*! @method ProcessBufferLists */ + virtual OSStatus ProcessBufferLists( AudioUnitRenderActionFlags & ioActionFlags, + const AudioBufferList & inBuffer, + AudioBufferList & outBuffer, + UInt32 inFramesToProcess ) + { + return kAudio_UnimplementedError; + } + + /*! @method ProcessMultipleBufferLists */ + virtual OSStatus ProcessMultipleBufferLists( AudioUnitRenderActionFlags & ioActionFlags, + UInt32 inFramesToProcess, + UInt32 inNumberInputBufferLists, + const AudioBufferList ** inInputBufferLists, + UInt32 inNumberOutputBufferLists, + AudioBufferList ** ioOutputBufferLists) + { + return kAudio_UnimplementedError; + } + + /*! @method ComplexRender */ + virtual OSStatus ComplexRender( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumberOfPackets, + UInt32 * outNumberOfPackets, + AudioStreamPacketDescription * outPacketDescriptions, + AudioBufferList & ioData, + void * outMetadata, + UInt32 * outMetadataByteSize) + { + return kAudio_UnimplementedError; + } + + // Override this method if your AU processes multiple output busses completely independently -- + // you'll want to just call Render without the NeedsToRender check. + // Otherwise, override Render(). + // + // N.B. Implementations of this method can assume that the output's buffer list has already been + // prepared and access it with GetOutput(inBusNumber)->GetBufferList() instead of + // GetOutput(inBusNumber)->PrepareBuffer(nFrames) -- if PrepareBuffer is called, a + // copy may occur after rendering. + /*! @method RenderBus */ + virtual OSStatus RenderBus( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames) + { + if (NeedsToRender(inTimeStamp)) + return Render(ioActionFlags, inTimeStamp, inNumberFrames); + return noErr; // was presumably already rendered via another bus + } + + // N.B. For a unit with only one output bus, it can assume in its implementation of this + // method that the output's buffer list has already been prepared and access it with + // GetOutput(0)->GetBufferList() instead of GetOutput(0)->PrepareBuffer(nFrames) + // -- if PrepareBuffer is called, a copy may occur after rendering. + /*! @method Render */ + virtual OSStatus Render( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inNumberFrames) + { + return noErr; + } + + +#pragma mark - +#pragma mark Property Dispatch + + static const Float64 kNoLastRenderedSampleTime; + + // ________________________________________________________________________ + // These are generated from DispatchGetProperty/DispatchGetPropertyInfo/DispatchSetProperty + + /*! @method BusCountWritable */ + virtual bool BusCountWritable( AudioUnitScope inScope) + { + return false; + } + virtual OSStatus SetBusCount( AudioUnitScope inScope, + UInt32 inCount); + + /*! @method SetConnection */ + virtual OSStatus SetConnection( const AudioUnitConnection & inConnection); + + /*! @method SetInputCallback */ + virtual OSStatus SetInputCallback( UInt32 inPropertyID, + AudioUnitElement inElement, + AURenderCallback inProc, + void * inRefCon); + + /*! @method GetParameterList */ + virtual OSStatus GetParameterList( AudioUnitScope inScope, + AudioUnitParameterID * outParameterList, + UInt32 & outNumParameters); + // outParameterList may be a null pointer + + /*! @method GetParameterInfo */ + virtual OSStatus GetParameterInfo( AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + AudioUnitParameterInfo & outParameterInfo); + + virtual OSStatus GetParameterHistoryInfo(AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + Float32 & outUpdatesPerSecond, + Float32 & outHistoryDurationInSeconds); + + /*! @method SaveState */ + virtual OSStatus SaveState( CFPropertyListRef * outData); + + /*! @method SaveExtendedScopes */ + virtual void SaveExtendedScopes( CFMutableDataRef outData) {}; + + /*! @method RestoreState */ + virtual OSStatus RestoreState( CFPropertyListRef inData); + + /*! @method GetParameterValueStrings */ + virtual OSStatus GetParameterValueStrings(AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + CFArrayRef * outStrings); + + /*! @method CopyClumpName */ + virtual OSStatus CopyClumpName( AudioUnitScope inScope, + UInt32 inClumpID, + UInt32 inDesiredNameLength, + CFStringRef * outClumpName); + + /*! @method GetPresets */ + virtual OSStatus GetPresets ( CFArrayRef * outData) const; + + // set the default preset for the unit -> the number of the preset MUST be >= 0 + // and the name should be valid, or the preset WON'T take + /*! @method SetAFactoryPresetAsCurrent */ + bool SetAFactoryPresetAsCurrent (const AUPreset & inPreset); + + // Called when someone sets a new, valid preset + // If this is a valid preset, then the subclass sets its state to that preset + // and returns noErr. + // If not a valid preset, return an error, and the pre-existing preset is restored + /*! @method NewFactoryPresetSet */ + virtual OSStatus NewFactoryPresetSet (const AUPreset & inNewFactoryPreset); + + /*! @method NewCustomPresetSet */ + virtual OSStatus NewCustomPresetSet (const AUPreset & inNewCustomPreset); + +#if !CA_USE_AUDIO_PLUGIN_ONLY + /*! @method GetNumCustomUIComponents */ + virtual int GetNumCustomUIComponents (); + + /*! @method GetUIComponentDescs */ + virtual void GetUIComponentDescs (ComponentDescription* inDescArray); +#endif + + /*! @method CopyIconLocation */ + virtual CFURLRef CopyIconLocation (); + + // default is no latency, and unimplemented tail time + /*! @method GetLatency */ + virtual Float64 GetLatency() {return 0.0;} + /*! @method GetTailTime */ + virtual Float64 GetTailTime() {return 0;} + /*! @method SupportsRampAndTail */ + virtual bool SupportsTail () { return false; } + + /*! @method IsStreamFormatWritable */ + bool IsStreamFormatWritable( AudioUnitScope scope, + AudioUnitElement element); + + /*! @method StreamFormatWritable */ + virtual bool StreamFormatWritable( AudioUnitScope scope, + AudioUnitElement element) = 0; + // scope will always be input or output + + // pass in a pointer to get the struct, and num channel infos + // you can pass in NULL to just get the number + // a return value of 0 (the default in AUBase) means the property is not supported... + /*! @method SupportedNumChannels */ + virtual UInt32 SupportedNumChannels ( const AUChannelInfo** outInfo); + + /*! @method ValidFormat */ + virtual bool ValidFormat( AudioUnitScope inScope, + AudioUnitElement inElement, + const CAStreamBasicDescription & inNewFormat); + // Will only be called after StreamFormatWritable + // has succeeded. + // Default implementation requires canonical format: + // native-endian 32-bit float, any sample rate, + // any number of channels; override when other + // formats are supported. A subclass's override can + // choose to always return true and trap invalid + // formats in ChangeStreamFormat. + + + /*! @method FormatIsCanonical */ + bool FormatIsCanonical( const CAStreamBasicDescription &format); + + /*! @method MakeCanonicalFormat */ + void MakeCanonicalFormat( CAStreamBasicDescription & outDesc, + int numChannels = 2); + + /*! @method GetStreamFormat */ + virtual const CAStreamBasicDescription & + GetStreamFormat( AudioUnitScope inScope, + AudioUnitElement inElement); + + /*! @method ChangeStreamFormat */ + virtual OSStatus ChangeStreamFormat( AudioUnitScope inScope, + AudioUnitElement inElement, + const CAStreamBasicDescription & inPrevFormat, + const CAStreamBasicDescription & inNewFormat); + // Will only be called after StreamFormatWritable + // and ValidFormat have succeeded. + + // ________________________________________________________________________ + +#if !CA_USE_AUDIO_PLUGIN_ONLY + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch( ComponentParameters * params, + AUBase * This); +#endif + + // ________________________________________________________________________ + // Methods useful for subclasses + + /*! @method GetScope */ + AUScope & GetScope( AudioUnitScope inScope) + { + if (inScope >= kNumScopes) { + AUScope * scope = GetScopeExtended(inScope); + if (!scope) COMPONENT_THROW(kAudioUnitErr_InvalidScope); + return *scope; + } + return mScopes[inScope]; + } + + /*! @method GetScopeExtended */ + virtual AUScope * GetScopeExtended (AudioUnitScope inScope) { return NULL; } + + /*! @method GlobalScope */ + AUScope & GlobalScope() { return mScopes[kAudioUnitScope_Global]; } + /*! @method Inputs */ + AUScope & Inputs() { return mScopes[kAudioUnitScope_Input]; } + /*! @method Outputs */ + AUScope & Outputs() { return mScopes[kAudioUnitScope_Output]; } +#if !CA_BASIC_AU_FEATURES + /*! @method Groups */ + AUScope & Groups() { return mScopes[kAudioUnitScope_Group]; } +#endif + /*! @method Globals */ + AUElement * Globals() { return mScopes[kAudioUnitScope_Global].GetElement(0); } + + /*! @method SetNumberOfElements */ + void SetNumberOfElements( AudioUnitScope inScope, + UInt32 numElements); + + /*! @method GetElement */ + AUElement * GetElement( AudioUnitScope inScope, + AudioUnitElement inElement) + { + return GetScope(inScope).GetElement(inElement); + } + + /*! @method GetIOElement */ + AUIOElement * GetIOElement( AudioUnitScope inScope, + AudioUnitElement inElement) + { + return GetScope(inScope).GetIOElement(inElement); + } + + /*! @method SafeGetElement */ + AUElement * SafeGetElement( AudioUnitScope inScope, + AudioUnitElement inElement) + { + return GetScope(inScope).SafeGetElement(inElement); + } + + /*! @method GetInput */ + AUInputElement * GetInput( AudioUnitElement inElement) + { + return static_cast(Inputs().SafeGetElement(inElement)); + } + + /*! @method GetOutput */ + AUOutputElement * GetOutput( AudioUnitElement inElement) + { + return static_cast(Outputs().SafeGetElement(inElement)); + } + +#if !CA_BASIC_AU_FEATURES + /*! @method GetGroup */ + AUElement * GetGroup( AudioUnitElement inElement) + { + return Groups().SafeGetElement(inElement); + } +#endif + + /*! @method PullInput */ + OSStatus PullInput( UInt32 inBusNumber, + AudioUnitRenderActionFlags &ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inNumberFrames) + { + AUInputElement *input = GetInput(inBusNumber); // throws if error + return input->PullInput(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames); + } + + /*! @method GetMaxFramesPerSlice */ + UInt32 GetMaxFramesPerSlice() const { return mMaxFramesPerSlice; } + /*! @method UsesFixedBlockSize */ + bool UsesFixedBlockSize() const { return mUsesFixedBlockSize; } + /*! @method SetUsesFixedBlockSize */ + void SetUsesFixedBlockSize(bool inUsesFixedBlockSize) { mUsesFixedBlockSize = inUsesFixedBlockSize; } + + /*! @method GetVectorUnitType */ + static SInt32 GetVectorUnitType() { return sVectorUnitType; } + /*! @method HasVectorUnit */ + static bool HasVectorUnit() { return sVectorUnitType > 0; } + /*! @method HasAltivec */ + static bool HasAltivec() { return sVectorUnitType == kVecAltivec; } + /*! @method HasSSE2 */ + static bool HasSSE2() { return sVectorUnitType >= kVecSSE2; } + /*! @method HasSSE3 */ + static bool HasSSE3() { return sVectorUnitType >= kVecSSE3; } + + /*! @method AudioUnitAPIVersion */ + UInt8 AudioUnitAPIVersion() const { return mAudioUnitAPIVersion; } + + /*! @method IsRenderThread */ + bool InRenderThread () const + { +#if TARGET_OS_MAC + return (mRenderThreadID ? pthread_equal (mRenderThreadID, pthread_self()) : false); +#elif TARGET_OS_WIN32 + return (mRenderThreadID ? mRenderThreadID == GetCurrentThreadId() : false); +#endif + } + + /*! @method HasInput */ + bool HasInput( AudioUnitElement inElement) { + AUInputElement *in = static_cast(Inputs().GetElement(inElement)); + return in != NULL && in->IsActive(); + } + // says whether an input is connected or has a callback + + /*! @method PropertyChanged */ + virtual void PropertyChanged( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement); + +#if !CA_NO_AU_UI_FEATURES + // These calls can be used to call a Host's Callbacks. The method returns -1 if the host + // hasn't supplied the callback. Any other result is returned by the host. + // As in the API contract, for a parameter's value, you specify a pointer + // to that data type. Specify NULL for a parameter that you are not interested + // as this can save work in the host. + + /*! @method CallHostBeatAndTempo */ + OSStatus CallHostBeatAndTempo (Float64 *outCurrentBeat, + Float64 *outCurrentTempo) + { + return (mHostCallbackInfo.beatAndTempoProc + ? (*mHostCallbackInfo.beatAndTempoProc) (mHostCallbackInfo.hostUserData, + outCurrentBeat, + outCurrentTempo) + : -1); + } + + /*! @method CallHostMusicalTimeLocation */ + OSStatus CallHostMusicalTimeLocation (UInt32 *outDeltaSampleOffsetToNextBeat, + Float32 *outTimeSig_Numerator, + UInt32 *outTimeSig_Denominator, + Float64 *outCurrentMeasureDownBeat) + { + return (mHostCallbackInfo.musicalTimeLocationProc + ? (*mHostCallbackInfo.musicalTimeLocationProc) (mHostCallbackInfo.hostUserData, + outDeltaSampleOffsetToNextBeat, + outTimeSig_Numerator, + outTimeSig_Denominator, + outCurrentMeasureDownBeat) + : -1); + } + + /*! @method CallHostTransportState */ + OSStatus CallHostTransportState (Boolean *outIsPlaying, + Boolean *outTransportStateChanged, + Float64 *outCurrentSampleInTimeLine, + Boolean *outIsCycling, + Float64 *outCycleStartBeat, + Float64 *outCycleEndBeat) + { + return (mHostCallbackInfo.transportStateProc + ? (*mHostCallbackInfo.transportStateProc) (mHostCallbackInfo.hostUserData, + outIsPlaying, + outTransportStateChanged, + outCurrentSampleInTimeLine, + outIsCycling, + outCycleStartBeat, + outCycleEndBeat) + : -1); + } +#endif + + char* GetLoggingString () const; + + CAMutex* GetMutex() { return mAUMutex; } + + // ________________________________________________________________________ + /*! @method CreateElement */ + virtual AUElement * CreateElement( AudioUnitScope scope, + AudioUnitElement element); + +#pragma mark - +#pragma mark AU Output Base Dispatch + // ________________________________________________________________________ + // ________________________________________________________________________ + // ________________________________________________________________________ + // output unit methods + /*! @method Start */ + virtual OSStatus Start() { return kAudio_UnimplementedError; } + /*! @method Stop */ + virtual OSStatus Stop() { return kAudio_UnimplementedError; } + +#if !CA_BASIC_AU_FEATURES +#pragma mark - +#pragma mark AU Music Base Dispatch + +#if !TARGET_OS_IPHONE +// these methods are deprecated, so we don't include them except for compatability + /*! @method PrepareInstrument */ + virtual OSStatus PrepareInstrument(MusicDeviceInstrumentID inInstrument) { return kAudio_UnimplementedError; } + + /*! @method PrepareInstrument */ + virtual OSStatus ReleaseInstrument(MusicDeviceInstrumentID inInstrument) { return kAudio_UnimplementedError; } +#endif + + // ________________________________________________________________________ + // ________________________________________________________________________ + // ________________________________________________________________________ + // music device/music effect methods -- incomplete + /*! @method MIDIEvent */ + virtual OSStatus MIDIEvent( UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) { return kAudio_UnimplementedError; } + + /*! @method SysEx */ + virtual OSStatus SysEx( const UInt8 * inData, + UInt32 inLength) { return kAudio_UnimplementedError;} + + /*! @method StartNote */ + virtual OSStatus StartNote( MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams &inParams) { return kAudio_UnimplementedError; } + + /*! @method StopNote */ + virtual OSStatus StopNote( MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) { return kAudio_UnimplementedError; } +#endif + + // ________________________________________________________________________ + // ________________________________________________________________________ + // ________________________________________________________________________ + +protected: +#pragma mark - +#pragma mark Implementation methods + + /*! @method ReallocateBuffers */ + virtual void ReallocateBuffers(); + // needs to be called when mMaxFramesPerSlice changes + virtual void DeallocateIOBuffers(); + + /*! @method FillInParameterName */ + static void FillInParameterName (AudioUnitParameterInfo& ioInfo, CFStringRef inName, bool inShouldRelease) + { + ioInfo.cfNameString = inName; + ioInfo.flags |= kAudioUnitParameterFlag_HasCFNameString; + if (inShouldRelease) + ioInfo.flags |= kAudioUnitParameterFlag_CFNameRelease; + CFStringGetCString (inName, ioInfo.name, offsetof (AudioUnitParameterInfo, clumpID), kCFStringEncodingUTF8); + } + + static void HasClump (AudioUnitParameterInfo& ioInfo, UInt32 inClumpID) + { + ioInfo.clumpID = inClumpID; + ioInfo.flags |= kAudioUnitParameterFlag_HasClump; + } + + /*! @method SetMaxFramesPerSlice */ + virtual void SetMaxFramesPerSlice(UInt32 nFrames); + + /*! @method CanSetMaxFrames */ + virtual OSStatus CanSetMaxFrames() const; + + /*! @method WantsRenderThreadID */ + bool WantsRenderThreadID () const { return mWantsRenderThreadID; } + + /*! @method SetWantsRenderThreadID */ + void SetWantsRenderThreadID (bool inFlag); + + /*! @method SetRenderError */ + OSStatus SetRenderError (OSStatus inErr) + { + if (inErr && mLastRenderError == 0) { + mLastRenderError = inErr; + PropertyChanged(kAudioUnitProperty_LastRenderError, kAudioUnitScope_Global, 0); + } + return inErr; + } + +private: + /*! @method DoRenderBus */ + // shared between Render and RenderSlice, inlined to minimize function call overhead + OSStatus DoRenderBus( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inBusNumber, + AUOutputElement * theOutput, + UInt32 inNumberFrames, + AudioBufferList & ioData) + { + if (ioData.mBuffers[0].mData == NULL || (theOutput->WillAllocateBuffer() && Outputs().GetNumberOfElements() > 1)) + // will render into cache buffer + theOutput->PrepareBuffer(inNumberFrames); + else + // will render into caller's buffer + theOutput->SetBufferList(ioData); + OSStatus result = RenderBus(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames); + if (result == noErr) { + if (ioData.mBuffers[0].mData == NULL) { + theOutput->CopyBufferListTo(ioData); + AUTRACE(kCATrace_AUBaseDoRenderBus, mComponentInstance, inNumberFrames, (intptr_t)theOutput->GetBufferList().mBuffers[0].mData, 0, *(UInt32 *)ioData.mBuffers[0].mData); + } else { + theOutput->CopyBufferContentsTo(ioData); + AUTRACE(kCATrace_AUBaseDoRenderBus, mComponentInstance, inNumberFrames, (intptr_t)theOutput->GetBufferList().mBuffers[0].mData, (intptr_t)ioData.mBuffers[0].mData, *(UInt32 *)ioData.mBuffers[0].mData); + theOutput->InvalidateBufferList(); + } + } + return result; + } + + /*! @method HasIcon */ + bool HasIcon (); + + /*! @method ResetRenderTime */ + void ResetRenderTime () + { + memset (&mCurrentRenderTime, 0, sizeof(mCurrentRenderTime)); + mCurrentRenderTime.mSampleTime = kNoLastRenderedSampleTime; + } + +protected: + /*! @method GetAudioChannelLayout */ + virtual UInt32 GetChannelLayoutTags( AudioUnitScope scope, + AudioUnitElement element, + AudioChannelLayoutTag * outLayoutTags); + + /*! @method GetAudioChannelLayout */ + virtual UInt32 GetAudioChannelLayout( AudioUnitScope scope, + AudioUnitElement element, + AudioChannelLayout * outLayoutPtr, + Boolean & outWritable); + + /*! @method SetAudioChannelLayout */ + virtual OSStatus SetAudioChannelLayout( AudioUnitScope scope, + AudioUnitElement element, + const AudioChannelLayout * inLayout); + + /*! @method RemoveAudioChannelLayout */ + virtual OSStatus RemoveAudioChannelLayout(AudioUnitScope scope, AudioUnitElement element); + + /*! @method NeedsToRender */ + bool NeedsToRender( const AudioTimeStamp & inTimeStamp) + { + bool needsToRender = fnotequal(inTimeStamp.mSampleTime, mCurrentRenderTime.mSampleTime); + if (needsToRender) // only copy this if we need to render + mCurrentRenderTime = inTimeStamp; + return needsToRender; + } + + // Scheduled parameter implementation: + + typedef std::vector ParameterEventList; + + // Usually, you won't override this method. You only need to call this if your DSP code + // is prepared to handle scheduled immediate and ramped parameter changes. + // Before calling this method, it is assumed you have already called PullInput() on the input busses + // for which the DSP code depends. ProcessForScheduledParams() will call (potentially repeatedly) + // virtual method ProcessScheduledSlice() to perform the actual DSP for a given sub-division of + // the buffer. The job of ProcessForScheduledParams() is to sub-divide the buffer into smaller + // pieces according to the scheduled times found in the ParameterEventList (usually coming + // directly from a previous call to ScheduleParameter() ), setting the appropriate immediate or + // ramped parameter values for the corresponding scopes and elements, then calling ProcessScheduledSlice() + // to do the actual DSP for each of these divisions. + virtual OSStatus ProcessForScheduledParams( ParameterEventList &inParamList, + UInt32 inFramesToProcess, + void *inUserData ); + + // This method is called (potentially repeatedly) by ProcessForScheduledParams() + // in order to perform the actual DSP required for this portion of the entire buffer + // being processed. The entire buffer can be divided up into smaller "slices" + // according to the timestamps on the scheduled parameters... + // + // sub-classes wishing to handle scheduled parameter changes should override this method + // in order to do the appropriate DSP. AUEffectBase already overrides this for standard + // effect AudioUnits. + virtual OSStatus ProcessScheduledSlice( void *inUserData, + UInt32 inStartFrameInBuffer, + UInt32 inSliceFramesToProcess, + UInt32 inTotalBufferFrames ) {return noErr;}; // default impl does nothing... + + + /*! @method CurrentRenderTime */ + const AudioTimeStamp & CurrentRenderTime () const { return mCurrentRenderTime; } + + // ________________________________________________________________________ + // Private data members to discourage hacking in subclasses +private: + struct RenderCallback { + RenderCallback(AURenderCallback proc, void *ref) : + mRenderNotify(proc), + mRenderNotifyRefCon(ref) + { } + + AURenderCallback mRenderNotify; + void * mRenderNotifyRefCon; + + bool operator == (const RenderCallback &other) { + return this->mRenderNotify == other.mRenderNotify && + this->mRenderNotifyRefCon == other.mRenderNotifyRefCon; + } + }; + typedef TThreadSafeList RenderCallbackList; + +#if !CA_BASIC_AU_FEATURES + enum { kNumScopes = 4 }; +#else + enum { kNumScopes = 3 }; +#endif + + /*! @var mElementsCreated */ + bool mElementsCreated; +protected: + /*! @var mInitialized */ + bool mInitialized; + /*! @var mHasBegunInitializing */ + bool mHasBegunInitializing; +private: + /*! @var mAudioUnitAPIVersion */ + UInt8 mAudioUnitAPIVersion; + + /*! @var mInitNumInputEls */ + const UInt32 mInitNumInputEls; + /*! @var mInitNumOutputEls */ + const UInt32 mInitNumOutputEls; +#if !CA_BASIC_AU_FEATURES + /*! @var mInitNumGroupEls */ + const UInt32 mInitNumGroupEls; +#endif + /*! @var mScopes */ + AUScope mScopes[kNumScopes]; + + /*! @var mRenderCallbacks */ + RenderCallbackList mRenderCallbacks; + bool mRenderCallbacksTouched; + + /*! @var mRenderThreadID */ +#if TARGET_OS_MAC + pthread_t mRenderThreadID; +#elif TARGET_OS_WIN32 + UInt32 mRenderThreadID; +#endif + + /*! @var mWantsRenderThreadID */ + bool mWantsRenderThreadID; + + /*! @var mCurrentRenderTime */ + AudioTimeStamp mCurrentRenderTime; + + /*! @var mMaxFramesPerSlice */ + UInt32 mMaxFramesPerSlice; + + /*! @var mLastRenderError */ + OSStatus mLastRenderError; + /*! @var mCurrentPreset */ + AUPreset mCurrentPreset; + +protected: + /*! @var mUsesFixedBlockSize */ + bool mUsesFixedBlockSize; + + struct PropertyListener { + AudioUnitPropertyID propertyID; + AudioUnitPropertyListenerProc listenerProc; + void * listenerRefCon; + }; + typedef std::vector PropertyListeners; + + /*! @var mParamList */ + ParameterEventList mParamList; + /*! @var mPropertyListeners */ + PropertyListeners mPropertyListeners; + + /*! @var mBuffersAllocated */ + bool mBuffersAllocated; + + /*! @var mLogString */ + // if this is NOT null, it will contain identifying info about this AU. + char* mLogString; + + /*! @var mNickName */ + CFStringRef mNickName; + + /*! @var mAUMutex */ + CAMutex * mAUMutex; + +private: + /*! @var sVectorUnitType */ + static SInt32 sVectorUnitType; + +#if !CA_NO_AU_HOST_CALLBACKS +protected: + /*! @var mHostCallbackInfo */ + HostCallbackInfo mHostCallbackInfo; + +#endif +#if !CA_NO_AU_UI_FEATURES +protected: + /*! @var mContextInfo */ + CFStringRef mContextName; +#endif +}; + +inline OSStatus AUInputElement::PullInputWithBufferList( + AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + AudioUnitElement inElement, + UInt32 nFrames, + AudioBufferList * inBufferList) +{ + OSStatus theResult; + + if (HasConnection()) { + // only support connections for V2 audio units +#if !CA_USE_AUDIO_PLUGIN_ONLY + if (mConnRenderProc != NULL) + theResult = reinterpret_cast(mConnRenderProc)( + mConnInstanceStorage, &ioActionFlags, &inTimeStamp, mConnection.sourceOutputNumber, nFrames, inBufferList); + else +#endif + theResult = AudioUnitRender( + mConnection.sourceAudioUnit, &ioActionFlags, &inTimeStamp, mConnection.sourceOutputNumber, nFrames, inBufferList); + } else { + // kFromCallback: + theResult = (mInputProc)( + mInputProcRefCon, &ioActionFlags, &inTimeStamp, inElement, nFrames, inBufferList); + } + + if (mInputType == kNoInput) // defense: the guy upstream could have disconnected + // it's a horrible thing to do, but may happen! + return kAudioUnitErr_NoConnection; + + + return theResult; +} + +#endif // __AUBase_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBaseHelper.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBaseHelper.h new file mode 100644 index 0000000000..03f750faa2 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBaseHelper.h @@ -0,0 +1,75 @@ +/* + File: AUBaseHelper.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUBaseHelper_h__ +#define __AUBaseHelper_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +#include "AUBase.h" + +// helpers for dealing with the file-references dictionary in an AUPreset +OSStatus GetFileRefPath (CFDictionaryRef parent, CFStringRef frKey, CFStringRef * fPath); + +// if fileRefDict is NULL, this call creates one +// if not NULL, then the key value is added to it +CFMutableDictionaryRef CreateFileRefDict (CFStringRef fKey, CFStringRef fPath, CFMutableDictionaryRef fileRefDict); + +int AccessURLAsset(const CFURLRef inURL, int mode); + +#if DEBUG + void PrintAUParamEvent (AudioUnitParameterEvent& event, FILE* f); +#endif + + + +#endif // __AUBaseHelper_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBuffer.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBuffer.cpp new file mode 100644 index 0000000000..2221bcab64 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBuffer.cpp @@ -0,0 +1,219 @@ +/* + File: AUBuffer.cpp + Abstract: AUBuffer.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUBuffer.h" +#include + +AUBufferList::~AUBufferList() +{ + Deallocate(); + if (mPtrs) + free(mPtrs); +} + +// a * b + c +static UInt32 SafeMultiplyAddUInt32(UInt32 a, UInt32 b, UInt32 c) +{ + if (a == 0 || b == 0) return c; // prevent zero divide + + if (a > (0xFFFFFFFF - c) / b) + throw std::bad_alloc(); + + return a * b + c; +} + +void AUBufferList::Allocate(const CAStreamBasicDescription &format, UInt32 nFrames) +{ + UInt32 nStreams; + if (format.IsInterleaved()) { + nStreams = 1; + } else { + nStreams = format.mChannelsPerFrame; + } + + // careful -- the I/O thread could be running! + if (nStreams > mAllocatedStreams) { + size_t theHeaderSize = sizeof(AudioBufferList) - sizeof(AudioBuffer); + mPtrs = (AudioBufferList *)CA_realloc(mPtrs, + SafeMultiplyAddUInt32(nStreams, sizeof(AudioBuffer), theHeaderSize)); + mAllocatedStreams = nStreams; + } + UInt32 bytesPerStream = SafeMultiplyAddUInt32(nFrames, format.mBytesPerFrame, 0xF) & ~0xF; + UInt32 nBytes = SafeMultiplyAddUInt32(nStreams, bytesPerStream, 0); + if (nBytes > mAllocatedBytes) { + if (mExternalMemory) { + mExternalMemory = false; + mMemory = NULL; + } + mMemory = (Byte *)CA_realloc(mMemory, nBytes); + mAllocatedBytes = nBytes; + } + mAllocatedFrames = nFrames; + mPtrState = kPtrsInvalid; +} + +void AUBufferList::Deallocate() +{ + mAllocatedStreams = 0; + mAllocatedFrames = 0; + mAllocatedBytes = 0; +// this causes a world of hurt if someone upstream disconnects during I/O (SysSoundGraph) +/* if (mPtrs) { + printf("deallocating bufferlist %08X\n", int(mPtrs)); + free(mPtrs); + mPtrs = NULL; + } */ + if (mMemory) { + if (mExternalMemory) + mExternalMemory = false; + else + free(mMemory); + mMemory = NULL; + } + mPtrState = kPtrsInvalid; +} + +AudioBufferList & AUBufferList::PrepareBuffer(const CAStreamBasicDescription &format, UInt32 nFrames) +{ + if (nFrames > mAllocatedFrames) + COMPONENT_THROW(kAudioUnitErr_TooManyFramesToProcess); + + UInt32 nStreams; + UInt32 channelsPerStream; + if (format.IsInterleaved()) { + nStreams = 1; + channelsPerStream = format.mChannelsPerFrame; + } else { + nStreams = format.mChannelsPerFrame; + channelsPerStream = 1; + if (nStreams > mAllocatedStreams) + COMPONENT_THROW(kAudioUnitErr_FormatNotSupported); + } + + AudioBufferList *abl = mPtrs; + abl->mNumberBuffers = nStreams; + AudioBuffer *buf = abl->mBuffers; + Byte *mem = mMemory; + UInt32 streamInterval = (mAllocatedFrames * format.mBytesPerFrame + 0xF) & ~0xF; + UInt32 bytesPerBuffer = nFrames * format.mBytesPerFrame; + for ( ; nStreams--; ++buf) { + buf->mNumberChannels = channelsPerStream; + buf->mData = mem; + buf->mDataByteSize = bytesPerBuffer; + mem += streamInterval; + } + if (UInt32(mem - mMemory) > mAllocatedBytes) + COMPONENT_THROW(kAudioUnitErr_TooManyFramesToProcess); + mPtrState = kPtrsToMyMemory; + return *mPtrs; +} + +AudioBufferList & AUBufferList::PrepareNullBuffer(const CAStreamBasicDescription &format, UInt32 nFrames) +{ + UInt32 nStreams; + UInt32 channelsPerStream; + if (format.IsInterleaved()) { + nStreams = 1; + channelsPerStream = format.mChannelsPerFrame; + } else { + nStreams = format.mChannelsPerFrame; + channelsPerStream = 1; + if (nStreams > mAllocatedStreams) + COMPONENT_THROW(kAudioUnitErr_FormatNotSupported); + } + AudioBufferList *abl = mPtrs; + abl->mNumberBuffers = nStreams; + AudioBuffer *buf = abl->mBuffers; + UInt32 bytesPerBuffer = nFrames * format.mBytesPerFrame; + for ( ; nStreams--; ++buf) { + buf->mNumberChannels = channelsPerStream; + buf->mData = NULL; + buf->mDataByteSize = bytesPerBuffer; + } + mPtrState = kPtrsToExternalMemory; + return *mPtrs; +} + +// this should NOT be called while I/O is in process +void AUBufferList::UseExternalBuffer(const CAStreamBasicDescription &format, const AudioUnitExternalBuffer &buf) +{ + UInt32 alignedSize = buf.size & ~0xF; + if (mMemory != NULL && alignedSize >= mAllocatedBytes) { + // don't accept the buffer if we already have one and it's big enough + // if we don't already have one, we don't need one + Byte *oldMemory = mMemory; + mMemory = buf.buffer; + mAllocatedBytes = alignedSize; + // from Allocate(): nBytes = nStreams * nFrames * format.mBytesPerFrame; + // thus: nFrames = nBytes / (nStreams * format.mBytesPerFrame) + mAllocatedFrames = mAllocatedBytes / (format.NumberChannelStreams() * format.mBytesPerFrame); + mExternalMemory = true; + free(oldMemory); + } +} + +#if DEBUG +void AUBufferList::PrintBuffer(const char *label, int subscript, const AudioBufferList &abl, UInt32 nFrames, bool asFloats) +{ + printf(" %s [%d] 0x%08lX:\n", label, subscript, long(&abl)); + const AudioBuffer *buf = abl.mBuffers; + for (UInt32 i = 0; i < abl.mNumberBuffers; ++buf, ++i) { + printf(" [%2d] %5dbytes %dch @ %p: ", (int)i, (int)buf->mDataByteSize, (int)buf->mNumberChannels, buf->mData); + if (buf->mData != NULL) { + UInt32 nSamples = nFrames * buf->mNumberChannels; + for (UInt32 j = 0; j < nSamples; ++j) { + if (nSamples > 16 && (j % 16) == 0) + printf("\n\t"); + if (asFloats) + printf(" %6.3f", ((float *)buf->mData)[j]); + else + printf(" %08X", (unsigned)((UInt32 *)buf->mData)[j]); + } + } + printf("\n"); + } +} +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBuffer.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBuffer.h new file mode 100644 index 0000000000..875ab611fb --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBuffer.h @@ -0,0 +1,267 @@ +/* + File: AUBuffer.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUBuffer_h__ +#define __AUBuffer_h__ + +#include +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#include +#include "CAStreamBasicDescription.h" +#include "CAAutoDisposer.h" +#include "CADebugMacros.h" + +// make this usable outside the stricter context of AudiUnits +#ifndef COMPONENT_THROW + #define COMPONENT_THROW(err) \ + do { DebugMessage(#err); throw static_cast(err); } while (0) +#endif + + + /*! @class AUBufferList */ +class AUBufferList { + enum EPtrState { + kPtrsInvalid, + kPtrsToMyMemory, + kPtrsToExternalMemory + }; +public: + /*! @ctor AUBufferList */ + AUBufferList() : mPtrState(kPtrsInvalid), mExternalMemory(false), mPtrs(NULL), mMemory(NULL), + mAllocatedStreams(0), mAllocatedFrames(0), mAllocatedBytes(0) { } + /*! @dtor ~AUBufferList */ + ~AUBufferList(); + + /*! @method PrepareBuffer */ + AudioBufferList & PrepareBuffer(const CAStreamBasicDescription &format, UInt32 nFrames); + /*! @method PrepareNullBuffer */ + AudioBufferList & PrepareNullBuffer(const CAStreamBasicDescription &format, UInt32 nFrames); + + /*! @method SetBufferList */ + AudioBufferList & SetBufferList(const AudioBufferList &abl) { + if (mAllocatedStreams < abl.mNumberBuffers) + COMPONENT_THROW(-1); + mPtrState = kPtrsToExternalMemory; + memcpy(mPtrs, &abl, (char *)&abl.mBuffers[abl.mNumberBuffers] - (char *)&abl); + return *mPtrs; + } + + /*! @method SetBuffer */ + void SetBuffer(UInt32 index, const AudioBuffer &ab) { + if (mPtrState == kPtrsInvalid || index >= mPtrs->mNumberBuffers) + COMPONENT_THROW(-1); + mPtrState = kPtrsToExternalMemory; + mPtrs->mBuffers[index] = ab; + } + + /*! @method InvalidateBufferList */ + void InvalidateBufferList() { mPtrState = kPtrsInvalid; } + + /*! @method GetBufferList */ + AudioBufferList & GetBufferList() const { + if (mPtrState == kPtrsInvalid) + COMPONENT_THROW(-1); + return *mPtrs; + } + + /*! @method CopyBufferListTo */ + void CopyBufferListTo(AudioBufferList &abl) const { + if (mPtrState == kPtrsInvalid) + COMPONENT_THROW(-1); + memcpy(&abl, mPtrs, (char *)&abl.mBuffers[abl.mNumberBuffers] - (char *)&abl); + } + + /*! @method CopyBufferContentsTo */ + void CopyBufferContentsTo(AudioBufferList &abl) const { + if (mPtrState == kPtrsInvalid) + COMPONENT_THROW(-1); + const AudioBuffer *srcbuf = mPtrs->mBuffers; + AudioBuffer *destbuf = abl.mBuffers; + + for (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++srcbuf, ++destbuf) { + if (i >= mPtrs->mNumberBuffers) // duplicate last source to additional outputs [4341137] + --srcbuf; + if (destbuf->mData != srcbuf->mData) + memmove(destbuf->mData, srcbuf->mData, srcbuf->mDataByteSize); + destbuf->mDataByteSize = srcbuf->mDataByteSize; + } + } + + /*! @method Allocate */ + void Allocate(const CAStreamBasicDescription &format, UInt32 nFrames); + /*! @method Deallocate */ + void Deallocate(); + + /*! @method UseExternalBuffer */ + void UseExternalBuffer(const CAStreamBasicDescription &format, const AudioUnitExternalBuffer &buf); + + // AudioBufferList utilities + /*! @method ZeroBuffer */ + static void ZeroBuffer(AudioBufferList &abl) { + AudioBuffer *buf = abl.mBuffers; + for (UInt32 i = abl.mNumberBuffers ; i--; ++buf) + memset(buf->mData, 0, buf->mDataByteSize); + } +#if DEBUG + /*! @method PrintBuffer */ + static void PrintBuffer(const char *label, int subscript, const AudioBufferList &abl, UInt32 nFrames = 8, bool asFloats = true); +#endif + + /*! @method GetAllocatedFrames */ + UInt32 GetAllocatedFrames() const { return mAllocatedFrames; } + +private: + /*! @ctor AUBufferList */ + AUBufferList(AUBufferList &) { } // prohibit copy constructor + + /*! @var mPtrState */ + EPtrState mPtrState; + /*! @var mExternalMemory */ + bool mExternalMemory; + /*! @var mPtrs */ + AudioBufferList * mPtrs; + /*! @var mMemory */ + Byte * mMemory; + /*! @var mAllocatedStreams */ + UInt32 mAllocatedStreams; + /*! @var mAllocatedFrames */ + UInt32 mAllocatedFrames; + /*! @var mAllocatedBytes */ + UInt32 mAllocatedBytes; +}; + + +// Allocates an array of samples (type T), to be optimally aligned for the processor + /*! @class TAUBuffer */ +template +class TAUBuffer { +public: + enum { + kAlignInterval = 0x10, + kAlignMask = kAlignInterval - 1 + }; + + /*! @ctor TAUBuffer.0 */ + TAUBuffer() : mMemObject(NULL), mAlignedBuffer(NULL), mBufferSizeBytes(0) + { + } + + /*! @ctor TAUBuffer.1 */ + TAUBuffer(UInt32 numElems, UInt32 numChannels) : mMemObject(NULL), mAlignedBuffer(NULL), + mBufferSizeBytes(0) + { + Allocate(numElems, numChannels); + } + + /*! @dtor ~TAUBuffer */ + ~TAUBuffer() + { + Deallocate(); + } + + /*! @method Allocate */ + void Allocate(UInt32 numElems) // can also re-allocate + { + UInt32 reqSize = numElems * sizeof(T); + + if (mMemObject != NULL && reqSize == mBufferSizeBytes) + return; // already allocated + + mBufferSizeBytes = reqSize; + mMemObject = CA_realloc(mMemObject, reqSize); + UInt32 misalign = (uintptr_t)mMemObject & kAlignMask; + if (misalign) { + mMemObject = CA_realloc(mMemObject, reqSize + kAlignMask); + mAlignedBuffer = (T *)((char *)mMemObject + kAlignInterval - misalign); + } else + mAlignedBuffer = (T *)mMemObject; + } + + /*! @method Deallocate */ + void Deallocate() + { + if (mMemObject == NULL) return; // so this method has no effect if we're using + // an external buffer + + free(mMemObject); + mMemObject = NULL; + mAlignedBuffer = NULL; + mBufferSizeBytes = 0; + } + + /*! @method AllocateClear */ + void AllocateClear(UInt32 numElems) // can also re-allocate + { + Allocate(numElems); + Clear(); + } + + /*! @method Clear */ + void Clear() + { + memset(mAlignedBuffer, 0, mBufferSizeBytes); + } + + // accessors + + /*! @method operator T *()@ */ + operator T *() { return mAlignedBuffer; } + +private: + /*! @var mMemObject */ + void * mMemObject; // null when using an external buffer + /*! @var mAlignedBuffer */ + T * mAlignedBuffer; // always valid once allocated + /*! @var mBufferSizeBytes */ + UInt32 mBufferSizeBytes; +}; + +#endif // __AUBuffer_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewBase.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewBase.cpp new file mode 100644 index 0000000000..4b9525b1bf --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewBase.cpp @@ -0,0 +1,403 @@ +/* + File: AUCarbonViewBase.cpp + Abstract: AUCarbonViewBase.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUCarbonViewBase.h" +#include "AUCarbonViewControl.h" +#include + +AUCarbonViewBase::AUCarbonViewBase(AudioUnitCarbonView inInstance, Float32 inNotificationInterval /* in seconds */) : + ComponentBase(inInstance), + mEditAudioUnit(0), + mParameterListener(NULL), +#if !__LP64__ + mEventListener(NULL), +#endif + mTimerRef (NULL), + mTimerUPP (NULL), + mCarbonWindow(NULL), + mCarbonPane(NULL), + mXOffset(0), + mYOffset(0) +{ + AUEventListenerCreate (ParameterListener, this, + CFRunLoopGetCurrent(), kCFRunLoopCommonModes, + inNotificationInterval, inNotificationInterval, + &mParameterListener); +} + +AUCarbonViewBase::~AUCarbonViewBase() +{ +#if !__LP64__ + if (mCarbonPane) + DisposeControl(mCarbonPane); + + for (ControlList::iterator it = mControlList.begin(); it != mControlList.end(); ++it) { + AUCarbonViewControl *ctl = *it; + delete ctl; + } + AUListenerDispose(mParameterListener); + + if (mTimerRef) + ::RemoveEventLoopTimer (mTimerRef); + + if (mTimerUPP) + DisposeEventLoopTimerUPP (mTimerUPP); +#endif +} + +void AUCarbonViewBase::AddControl(AUCarbonViewControl *control) +{ + ControlList::iterator it = find(mControlList.begin(), mControlList.end(), control); + if (it == mControlList.end()) + mControlList.push_back(control); +} + +void AUCarbonViewBase::RemoveControl(AUCarbonViewControl *control) +{ + ControlList::iterator it = find(mControlList.begin(), mControlList.end(), control); + if (it != mControlList.end()) { + AUCarbonViewControl *ctl = *it; + mControlList.erase(it); + delete ctl; + } +} + +void AUCarbonViewBase::ClearControls () +{ + for (ControlList::iterator it = mControlList.begin(); it != mControlList.end(); ++it) { + AUCarbonViewControl *ctl = *it; + delete ctl; + } + mControlList.clear(); +} + +void AUCarbonViewBase::ParameterListener(void * inCallbackRefCon, + void * inObject, + const AudioUnitEvent * inEvent, + UInt64 inEventHostTime, + Float32 inParameterValue) +{ + if (inEvent->mEventType == kAudioUnitEvent_ParameterValueChange) { + AUCarbonViewControl *ctl = (AUCarbonViewControl *)inObject; + ctl->ParameterToControl(inParameterValue); + } +} + + +OSStatus AUCarbonViewBase::CreateCarbonView(AudioUnit inAudioUnit, WindowRef inWindow, ControlRef inParentControl, const Float32Point &inLocation, const Float32Point &inSize, ControlRef &outParentControl) +{ +#if !__LP64__ + mEditAudioUnit = inAudioUnit; + mCarbonWindow = inWindow; + + WindowAttributes attributes; + verify_noerr(GetWindowAttributes(mCarbonWindow, &attributes)); + mCompositWindow = (attributes & kWindowCompositingAttribute) != 0; + + Rect area; + area.left = short(inLocation.x); area.top = short(inLocation.y); + area.right = short(area.left + inSize.x); area.bottom = short(area.top + inSize.y); + OSStatus err = ::CreateUserPaneControl(inWindow, &area, + kControlSupportsEmbedding, + &mCarbonPane); // subclass can resize mCarbonPane to taste + verify_noerr(err); + if (err) return err; + outParentControl = mCarbonPane; + + // register for mouse-down in our pane -- we want to clear focus + EventTypeSpec paneEvents[] = { + { kEventClassControl, kEventControlClick } + }; + WantEventTypes(GetControlEventTarget(mCarbonPane), GetEventTypeCount(paneEvents), paneEvents); + + if (IsCompositWindow()) { + verify_noerr(::HIViewAddSubview(inParentControl, mCarbonPane)); + mXOffset = 0; + mYOffset = 0; + } + else { + verify_noerr(::EmbedControl(mCarbonPane, inParentControl)); + mXOffset = inLocation.x; + mYOffset = inLocation.y; + } + mBottomRight.h = mBottomRight.v = 0; + + SizeControl(mCarbonPane, 0, 0); + if (err = CreateUI(mXOffset, mYOffset)) + return err; + + // we should only resize the control if a subclass has embedded + // controls in this AND this is done with the EmbedControl call below + // if mBottomRight is STILL equal to zero, then that wasn't done + // so don't size the control + Rect paneBounds; + GetControlBounds(mCarbonPane, &paneBounds); + // only resize mCarbonPane if it has not already been resized during CreateUI + if ((paneBounds.top == paneBounds.bottom) && (paneBounds.left == paneBounds.right)) { + if (mBottomRight.h != 0 && mBottomRight.v != 0) + SizeControl(mCarbonPane, (short) (mBottomRight.h - mXOffset), (short) (mBottomRight.v - mYOffset)); + } + + if (IsCompositWindow()) { + // prepare for handling scroll-events + EventTypeSpec scrollEvents[] = { + { kEventClassScrollable, kEventScrollableGetInfo }, + { kEventClassScrollable, kEventScrollableScrollTo } + }; + + WantEventTypes(GetControlEventTarget(mCarbonPane), GetEventTypeCount(scrollEvents), scrollEvents); + + mCurrentScrollPoint.x = mCurrentScrollPoint.y = 0.0f; + } + + return err; +#else + return noErr; +#endif +} + +OSStatus AUCarbonViewBase::CreateUI(Float32 inXOffset, Float32 inYOffset) +{ + return noErr; +} + +OSStatus AUCarbonViewBase::EmbedControl(ControlRef ctl) +{ +#if !__LP64__ + Rect r; + ::GetControlBounds(ctl, &r); + if (r.right > mBottomRight.h) mBottomRight.h = r.right; + if (r.bottom > mBottomRight.v) mBottomRight.v = r.bottom; + + if (IsCompositWindow()) + return ::HIViewAddSubview(mCarbonPane, ctl); + else + return ::EmbedControl(ctl, mCarbonPane); +#else + return noErr; +#endif +} + +void AUCarbonViewBase::AddCarbonControl(AUCarbonViewControl::ControlType type, const CAAUParameter ¶m, ControlRef control) +{ + verify_noerr(EmbedControl(control)); + + AUCarbonViewControl *auvc = new AUCarbonViewControl(this, mParameterListener, type, param, control); + auvc->Bind(); + AddControl(auvc); +} + +bool AUCarbonViewBase::HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event) +{ +#if !__LP64__ + UInt32 eclass = GetEventClass(event); + UInt32 ekind = GetEventKind(event); + ControlRef control; + + switch (eclass) { + case kEventClassControl: + { + switch (ekind) { + case kEventControlClick: + GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control); + if (control == mCarbonPane) { + ClearKeyboardFocus(mCarbonWindow); + return true; + } + } + } + break; + + case kEventClassScrollable: + { + switch (ekind) { + case kEventScrollableGetInfo: + { + // [1/4] + /* <-- kEventParamImageSize (out, typeHISize) + * On exit, contains the size of the entire scrollable view. + */ + HISize originalSize = { static_cast(mBottomRight.h), static_cast(mBottomRight.v) }; + verify_noerr(SetEventParameter(event, kEventParamImageSize, typeHISize, sizeof(HISize), &originalSize)); + + // [2/4] + /* <-- kEventParamViewSize (out, typeHISize) + * On exit, contains the amount of the scrollable view that is + * visible. + */ + HIViewRef parentView = HIViewGetSuperview(mCarbonPane); + HIRect parentBounds; + verify_noerr(HIViewGetBounds(parentView, &parentBounds)); + //HISize windowSize = { float(windowBounds.right - windowBounds.left), + // float(windowBounds.bottom - windowBounds.top) }; + verify_noerr(SetEventParameter(event, kEventParamViewSize, typeHISize, sizeof(HISize), &(parentBounds.size))); + + // [3/4] + /* <-- kEventParamLineSize (out, typeHISize) + * On exit, contains the amount that should be scrolled in + * response to a single click on a scrollbar arrow. + */ + HISize scrollIncrementSize = { 16.0f, float(20) }; + verify_noerr(SetEventParameter(event, kEventParamLineSize, typeHISize, sizeof(HISize), &scrollIncrementSize)); + + // [4/4] + /* <-- kEventParamOrigin (out, typeHIPoint) + * On exit, contains the scrollable viewÕs current origin (the + * view-relative coordinate that is drawn at the top left + * corner of its frame). These coordinates should always be + * greater than or equal to zero. They should be less than or + * equal to the viewÕs image size minus its view size. + */ + verify_noerr(SetEventParameter(event, kEventParamOrigin, typeHIPoint, sizeof(HIPoint), &mCurrentScrollPoint)); + } + return true; + + case kEventScrollableScrollTo: + { + /* + * kEventClassScrollable / kEventScrollableScrollTo + * + * Summary: + * Requests that an HIScrollViewÕs scrollable view should scroll to + * a particular origin. + */ + + /* --> kEventParamOrigin (in, typeHIPoint) + * The new origin for the scrollable view. The origin + * coordinates will vary from (0,0) to scrollable viewÕs image + * size minus its view size. + */ + HIPoint pointToScrollTo; + verify_noerr(GetEventParameter(event, kEventParamOrigin, typeHIPoint, NULL, sizeof(HIPoint), NULL, &pointToScrollTo)); + + float xDelta = mCurrentScrollPoint.x - pointToScrollTo.x; + float yDelta = mCurrentScrollPoint.y - pointToScrollTo.y; + // move visible portion the appropriate amount + verify_noerr(HIViewScrollRect(mCarbonPane, NULL, xDelta, yDelta)); + // set new content to be drawn + verify_noerr(HIViewSetBoundsOrigin(mCarbonPane, pointToScrollTo.x, pointToScrollTo.y)); + + mCurrentScrollPoint = pointToScrollTo; + } + return true; + + default: + break; + } + } + break; + + default: + break; + } +#endif + return false; +} + +/*! @method TellListener */ +void AUCarbonViewBase::TellListener (const CAAUParameter &auvp, AudioUnitCarbonViewEventID event, void *evpar) +{ +#if !__LP64__ + if (mEventListener) + (*mEventListener)(mEventListenerUserData, mComponentInstance, &auvp, event, evpar); +#endif + + AudioUnitEvent auEvent; + auEvent.mArgument.mParameter = auvp; + if (event == kAudioUnitCarbonViewEvent_MouseDownInControl) { + auEvent.mEventType = kAudioUnitEvent_BeginParameterChangeGesture; + } else { + auEvent.mEventType = kAudioUnitEvent_EndParameterChangeGesture; + } + AUEventListenerNotify(mParameterListener, this, &auEvent); +} + + +void AUCarbonViewBase::Update (bool inUIThread) +{ + for (ControlList::iterator iter = mControlList.begin(); iter != mControlList.end(); ++iter) + { + (*iter)->Update(inUIThread); + } +} + +pascal void AUCarbonViewBase::TheTimerProc (EventLoopTimerRef inTimer, void *inUserData) +{ + AUCarbonViewBase* This = reinterpret_cast(inUserData); + This->RespondToEventTimer (inTimer); +} + +void AUCarbonViewBase::RespondToEventTimer (EventLoopTimerRef inTimer) +{} + +/* + THESE are reasonable values for these two times + 0.005 // delay + 0.050 // interval +*/ + +OSStatus AUCarbonViewBase::CreateEventLoopTimer (Float32 inDelay, Float32 inInterval) +{ + if (mTimerUPP) + return noErr; + + mTimerUPP = NewEventLoopTimerUPP(TheTimerProc); + + EventLoopRef mainEventLoop = GetMainEventLoop(); + + //doesn't seem to like too small a value + if (inDelay < 0.005) + inDelay = 0.005; + + OSStatus timerResult = ::InstallEventLoopTimer( + mainEventLoop, + inDelay, + inInterval, + mTimerUPP, + this, + &mTimerRef); + return timerResult; +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewBase.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewBase.h new file mode 100644 index 0000000000..eb206ef8a7 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewBase.h @@ -0,0 +1,188 @@ +/* + File: AUCarbonViewBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUCarbonViewBase_h__ +#define __AUCarbonViewBase_h__ + +#include +#include "AUCarbonViewControl.h" +#include "ComponentBase.h" + +static const Float32 kDefaultNotificationInterval = 0.100; + + /*! @class AUCarbonViewBase */ +class AUCarbonViewBase : public ComponentBase, public CarbonEventHandler +{ +public: + /*! @ctor AUCarbonViewBase */ + AUCarbonViewBase ( AudioUnitCarbonView inInstance, + Float32 inNotificationInterval = kDefaultNotificationInterval /* in seconds */); + /*! @dtor ~AUCarbonViewBase */ + virtual ~AUCarbonViewBase(); + + // AUViewBase overrides + /*! @method CreateCarbonView */ + virtual OSStatus CreateCarbonView (AudioUnit inAudioUnit, WindowRef inWindow, ControlRef inParentControl, const Float32Point &inLocation, const Float32Point &inSize, ControlRef &outParentControl); + + // our own virtual methods + /*! @method CreateUI */ + virtual OSStatus CreateUI (Float32 inXOffset, Float32 inYOffset); + + /*! @method HandleEvent */ + virtual bool HandleEvent (EventHandlerCallRef inHandlerRef, EventRef event); + + /*! @method GetEditAudioUnit */ + const AudioUnit GetEditAudioUnit () const { return mEditAudioUnit; } + // + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch ( + ComponentParameters * params, + AUCarbonViewBase * This); + + /*! @method AddCarbonControl */ + void AddCarbonControl ( + AUCarbonViewControl::ControlType type, + const CAAUParameter & param, + ControlRef control); + + /*! @method GetCarbonWindow */ + WindowRef GetCarbonWindow () { return mCarbonWindow; } + /*! @method GetCarbonPane */ + ControlRef GetCarbonPane () { return mCarbonPane; } + /*! @method EmbedControl */ + OSStatus EmbedControl (ControlRef ctl); + + /*! @method TellListener */ + void TellListener (const CAAUParameter &auvp, AudioUnitCarbonViewEventID event, void *evpar); + + // pass in true if wanting an update to the view and you're calling this from a thread + // that is safe to do UI in. + // If you don't know, pass in false! + /*! @method Update */ + void Update (bool inUIThread); + + /*! @method GetXOffset */ + Float32 GetXOffset () { return mXOffset; } + /*! @method GetYOffset */ + Float32 GetYOffset () { return mYOffset; } + + /*! @method ClearControls */ + void ClearControls (); + + /*! @method IsCompositWindow */ + bool IsCompositWindow () const { return mCompositWindow; } + +protected: +#if !__LP64__ + /*! @method SetEventListener */ + void SetEventListener (AudioUnitCarbonViewEventListener listener, void *userData) + { + mEventListener = listener; + mEventListenerUserData = userData; + } +#endif + + /*! @method AddControl */ + void AddControl (AUCarbonViewControl *control); + /*! @method RemoveControl */ + void RemoveControl (AUCarbonViewControl *control); + + OSStatus CreateEventLoopTimer (Float32 inDelay, Float32 inInterval); + + /*! @method ParameterListener */ + static void ParameterListener (void * inCallbackRefCon, + void * inObject, + const AudioUnitEvent * inEvent, + UInt64 inEventHostTime, + Float32 inParameterValue); + + static pascal void TheTimerProc ( EventLoopTimerRef inTimer, + void * inUserData); + + virtual void RespondToEventTimer (EventLoopTimerRef inTimer); + + /*! @var mEditAudioUnit */ + AudioUnit mEditAudioUnit; // the AU we're controlling + /*! @var mParameterListener */ + AUEventListenerRef mParameterListener; + +#if !__LP64__ + /*! @var mEventListener */ + AudioUnitCarbonViewEventListener + mEventListener; +#endif + + /*! @var mEventListenerUserData */ + void * mEventListenerUserData; + +private: + typedef std::vector ControlList; + /*! @var mControlList */ + ControlList mControlList; + + EventLoopTimerRef mTimerRef; + + EventLoopTimerUPP mTimerUPP; + +protected: + /*! @var mCarbonWindow */ + WindowRef mCarbonWindow; + /*! @var mCarbonPane */ + ControlRef mCarbonPane; // user pane, contains all other controls + /*! @var mBottomRight */ + Point mBottomRight; // largest width and height of child controls + /*! @var mXOffset */ + Float32 mXOffset; + /*! @var mYOffset */ + Float32 mYOffset; + /*! @var mCompositWindow */ + bool mCompositWindow; + /*! @var mCurrentScrollPoint */ + HIPoint mCurrentScrollPoint; // needed for scrolling +}; + + +#endif // __AUCarbonViewBase_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewControl.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewControl.cpp new file mode 100644 index 0000000000..1a28c6fe1d --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewControl.cpp @@ -0,0 +1,710 @@ +/* + File: AUCarbonViewControl.cpp + Abstract: AUCarbonViewControl.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUCarbonViewControl.h" +#include "AUCarbonViewBase.h" +#include "AUViewLocalizedStringKeys.h" + +AUCarbonViewControl::AUCarbonViewControl(AUCarbonViewBase *ownerView, AUParameterListenerRef listener, ControlType type, const CAAUParameter ¶m, ControlRef control) : + mOwnerView(ownerView), + mListener(listener), + mType(type), + mParam(param), + mControl(control), + mInControlInitialization(0) +{ +#if !__LP64__ + SetControlReference(control, SRefCon(this)); +#endif +} + +AUCarbonViewControl::~AUCarbonViewControl() +{ + AUListenerRemoveParameter(mListener, this, &mParam); +} + +AUCarbonViewControl* AUCarbonViewControl::mLastControl = NULL; + +void AUCarbonViewControl::Bind() +{ +#if !__LP64__ + mInControlInitialization = 1; // true + AUListenerAddParameter(mListener, this, &mParam); + // will cause an almost-immediate callback + + EventTypeSpec events[] = { + { kEventClassControl, kEventControlValueFieldChanged } // N.B. OS X only + }; + + WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events); + + if (mType == kTypeContinuous || mType == kTypeText || mType == kTypeDiscrete) { + EventTypeSpec events[] = { + { kEventClassControl, kEventControlHit }, + { kEventClassControl, kEventControlClick }, + { kEventClassControl, kEventControlTrack } + }; + WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events); + } + + if (mType == kTypeText) { + EventTypeSpec events[] = { + { kEventClassControl, kEventControlSetFocusPart } + }; + WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events); + ControlKeyFilterUPP proc = mParam.ValuesHaveStrings() ? StdKeyFilterCallback : NumericKeyFilterCallback; + // this will fail for a static text field + SetControlData(mControl, 0, kControlEditTextKeyFilterTag, sizeof(proc), &proc); + } + + Update(true); + mInControlInitialization = 0; // false +#endif +} + +void AUCarbonViewControl::ParameterToControl(Float32 paramValue) +{ +#if !__LP64__ + ++mInControlInitialization; + switch (mType) { + case kTypeContinuous: + SetValueFract(AUParameterValueToLinear(paramValue, &mParam)); + break; + case kTypeDiscrete: + { + long value = long(paramValue); + + // special case [1] -- menu parameters + if (mParam.HasNamedParams()) { + // if we're dealing with menus they behave differently! + // becaue setting min and max doesn't work correctly for the control value + // first menu item always reports a control value of 1 + ControlKind ctrlKind; + if (GetControlKind(mControl, &ctrlKind) == noErr) { + if ((ctrlKind.kind == kControlKindPopupArrow) + || (ctrlKind.kind == kControlKindPopupButton)) + { + value = value - long(mParam.ParamInfo().minValue) + 1; + } + } + } + + // special case [2] -- Write-only boolean parameters + AudioUnitParameterInfo AUPI = mParam.ParamInfo(); + + bool isWriteOnlyBoolParameter = ( (AUPI.unit == kAudioUnitParameterUnit_Boolean) && + (AUPI.flags & kAudioUnitParameterFlag_IsWritable) && + !(AUPI.flags & kAudioUnitParameterFlag_IsReadable) ); + if (!isWriteOnlyBoolParameter) { + SetValue (value); + } + } + break; + case kTypeText: + { + CFStringRef cfstr = mParam.GetStringFromValueCopy(¶mValue); + + if ( !(mParam.ParamInfo().flags & kAudioUnitParameterFlag_IsWritable) //READ ONLY PARAMS + && (mParam.ParamInfo().flags & kAudioUnitParameterFlag_IsReadable)) + { + if (mParam.GetParamTag()) { + CFMutableStringRef str = CFStringCreateMutableCopy(NULL, 256, cfstr); + CFRelease (cfstr); + CFStringAppend (str, CFSTR(" ")); + CFStringAppend (str, mParam.GetParamTag()); + cfstr = str; + } + } + SetTextValue(cfstr); + CFRelease (cfstr); + } + break; + } + --mInControlInitialization; +#endif +} + +void AUCarbonViewControl::ControlToParameter() +{ +#if !__LP64__ + if (mInControlInitialization) + return; + + switch (mType) { + case kTypeContinuous: + { + double controlValue = GetValueFract(); + Float32 paramValue = AUParameterValueFromLinear(controlValue, &mParam); + mParam.SetValue(mListener, this, paramValue); + } + break; + case kTypeDiscrete: + { + long value = GetValue(); + + // special case [1] -- Menus + if (mParam.HasNamedParams()) { + // if we're dealing with menus they behave differently! + // becaue setting min and max doesn't work correctly for the control value + // first menu item always reports a control value of 1 + ControlKind ctrlKind; + if (GetControlKind(mControl, &ctrlKind) == noErr) { + if ((ctrlKind.kind == kControlKindPopupArrow) + || (ctrlKind.kind == kControlKindPopupButton)) + { + value = value + long(mParam.ParamInfo().minValue) - 1; + } + } + } + + // special case [2] -- Write-only boolean parameters + AudioUnitParameterInfo AUPI = mParam.ParamInfo(); + + bool isWriteOnlyBoolParameter = ( (AUPI.unit == kAudioUnitParameterUnit_Boolean) && + (AUPI.flags & kAudioUnitParameterFlag_IsWritable) && + !(AUPI.flags & kAudioUnitParameterFlag_IsReadable) ); + if (isWriteOnlyBoolParameter) { + value = 1; + } + + mParam.SetValue (mListener, this, value); + } + break; + case kTypeText: + { + Float32 val = mParam.GetValueFromString (GetTextValue()); + mParam.SetValue(mListener, this, (mParam.IsIndexedParam() ? (int)val : val)); + if (mParam.ValuesHaveStrings()) + ParameterToControl(val); //make sure we display the correct text (from the AU) + } + break; + } +#endif +} + +void AUCarbonViewControl::SetValueFract(double value) +{ +#if !__LP64__ + SInt32 minimum = GetControl32BitMinimum(mControl); + SInt32 maximum = GetControl32BitMaximum(mControl); + SInt32 cval = SInt32(value * (maximum - minimum) + minimum + 0.5); + SetControl32BitValue(mControl, cval); +// printf("set: value=%lf, min=%ld, max=%ld, ctl value=%ld\n", value, minimum, maximum, cval); +#endif +} + +double AUCarbonViewControl::GetValueFract() +{ +#if !__LP64__ + SInt32 minimum = GetControl32BitMinimum(mControl); + SInt32 maximum = GetControl32BitMaximum(mControl); + SInt32 cval = GetControl32BitValue(mControl); + double result = double(cval - minimum) / double(maximum - minimum); +// printf("get: min=%ld, max=%ld, value=%ld, result=%f\n", minimum, maximum, cval, result); + return result; +#else + return 0; +#endif +} + +void AUCarbonViewControl::SetTextValue(CFStringRef cfstr) +{ +#if !__LP64__ + verify_noerr(SetControlData(mControl, 0, kControlEditTextCFStringTag, sizeof(CFStringRef), &cfstr)); +#endif +} + +CFStringRef AUCarbonViewControl::GetTextValue() +{ +#if !__LP64__ + CFStringRef cfstr; + verify_noerr(GetControlData(mControl, 0, kControlEditTextCFStringTag, sizeof(CFStringRef), &cfstr, NULL)); + return cfstr; +#else + return CFSTR(""); +#endif +} + +void AUCarbonViewControl::SetValue(long value) +{ +#if !__LP64__ + SetControl32BitValue(mControl, value); +#endif +} + +long AUCarbonViewControl::GetValue() +{ +#if !__LP64__ + return GetControl32BitValue(mControl); +#else + return 0; +#endif +} + +/* Notes on event handling + + Button (Click and release on button) + kEventControlClick received + kEventControlTrack received + kEventControlValueFieldChanged received + kEventControlHit received + + Button (Click and release outside of button bounds) + kEventControlClick received + kEventControlTrack received + + Slider (Click, drag, and release) + kEventControlClick received + kEventControlTrack received + kEventControlValueFieldChanged received + kEventControlValueFieldChanged received + kEventControlHit received + + Slider (Click, release without changing value) + kEventControlClick received + kEventControlTrack received +*/ +bool AUCarbonViewControl::HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event) +{ + UInt32 eclass = GetEventClass(event); + UInt32 ekind = GetEventKind(event); + ControlRef control; + bool handled = true; + + switch (eclass) { + case kEventClassControl: + { + AudioUnitParameterInfo AUPI = mParam.ParamInfo(); + + bool isWriteOnlyBoolParameter = ( (AUPI.unit == kAudioUnitParameterUnit_Boolean) && + (AUPI.flags & kAudioUnitParameterFlag_IsWritable) && + !(AUPI.flags & kAudioUnitParameterFlag_IsReadable) ); + + switch (ekind) { + case kEventControlSetFocusPart: // tab + handled = !handled; // fall through to next case + mLastControl = this; + case kEventControlValueFieldChanged: + GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control); + verify(control == mControl); + ControlToParameter(); + return handled; + case kEventControlClick: + if (isWriteOnlyBoolParameter) { + GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control); + verify(control == mControl); + ControlToParameter(); + } else if (mLastControl != this) { + if (mLastControl != NULL) { + mLastControl->Update(false); + } + mLastControl = this; + } + mOwnerView->TellListener(mParam, kAudioUnitCarbonViewEvent_MouseDownInControl, NULL); + break; // don't return true, continue normal processing + case kEventControlHit: + if (mLastControl != this) { + if (mLastControl != NULL) + mLastControl->Update(false); + mLastControl = this; + } + mOwnerView->TellListener(mParam, kAudioUnitCarbonViewEvent_MouseUpInControl, NULL); + break; // don't return true, continue normal processing + case kEventControlTrack: + if (mLastControl != this) { + if (mLastControl != NULL) + mLastControl->Update(false); + mLastControl = this; + } + + CallNextEventHandler(inHandlerRef, event); + ControlToParameter(); // new code + mOwnerView->TellListener(mParam, kAudioUnitCarbonViewEvent_MouseUpInControl, NULL); + // old code: + // break; // don't return true, continue normal processing + + return handled; // don't return true, continue normal processing + } + } + } + return !handled; +} + +pascal void AUCarbonViewControl::SliderTrackProc(ControlRef theControl, ControlPartCode partCode) +{ + // this doesn't need to actually do anything +// AUCarbonViewControl *This = (AUCarbonViewControl *)GetControlReference(theControl); +} + +pascal ControlKeyFilterResult AUCarbonViewControl::StdKeyFilterCallback(ControlRef theControl, + SInt16 *keyCode, SInt16 *charCode, + EventModifiers *modifiers) +{ +#if !__LP64__ + SInt16 c = *charCode; + if (c >= ' ' || c == '\b' || c == 0x7F || (c >= 0x1c && c <= 0x1f) || c == '\t') + return kControlKeyFilterPassKey; + if (c == '\r' || c == 3) { // return or Enter + AUCarbonViewControl *This = (AUCarbonViewControl *)GetControlReference(theControl); + ControlEditTextSelectionRec sel = { 0, 32767 }; + SetControlData(This->mControl, 0, kControlEditTextSelectionTag, sizeof(sel), &sel); + This->ControlToParameter(); + } +#endif + return kControlKeyFilterBlockKey; +} + +pascal ControlKeyFilterResult AUCarbonViewControl::NumericKeyFilterCallback(ControlRef theControl, + SInt16 *keyCode, SInt16 *charCode, + EventModifiers *modifiers) +{ +#if !__LP64__ + SInt16 c = *charCode; + if (isdigit(c) || c == '+' || c == '-' || c == '.' || c == '\b' || c == 0x7F || (c >= 0x1c && c <= 0x1f) + || c == '\t') + return kControlKeyFilterPassKey; + if (c == '\r' || c == 3) { // return or Enter + AUCarbonViewControl *This = (AUCarbonViewControl *)GetControlReference(theControl); + ControlEditTextSelectionRec sel = { 0, 32767 }; + SetControlData(This->mControl, 0, kControlEditTextSelectionTag, sizeof(sel), &sel); + This->ControlToParameter(); + } +#endif + return kControlKeyFilterBlockKey; +} + +Boolean AUCarbonViewControl::SizeControlToFit(ControlRef inControl, SInt16 *outWidth, SInt16 *outHeight) +{ +#if !__LP64__ + if (inControl == 0) return false; + + Boolean bValue = false; + // this only works on text controls -- returns an error for other controls, but doesn't do anything, + // so the error is irrelevant + SetControlData(inControl, kControlEntireControl, 'stim' /* kControlStaticTextIsMultilineTag */, sizeof(Boolean), &bValue); + + SInt16 baseLineOffset; + Rect bestRect; + OSErr err = GetBestControlRect(inControl, &bestRect, &baseLineOffset); + if (err != noErr) return false; + + int width = (bestRect.right - bestRect.left) + 1; + int height = (bestRect.bottom - bestRect.top) + 1; + + Rect boundsRect; + GetControlBounds (inControl, &boundsRect); + + Rect newRect; + newRect.top = boundsRect.top; + newRect.bottom = newRect.top + height; + newRect.left = boundsRect.left; + newRect.right = newRect.left + width; + + SetControlBounds (inControl, &newRect); + + if (outWidth) + *outWidth = width; + + if (outHeight) + *outHeight = height; +#endif + return true; +} + +#pragma mark ___AUPropertyControl +bool AUPropertyControl::HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event) +{ + UInt32 eclass = GetEventClass(event); + UInt32 ekind = GetEventKind(event); + switch (eclass) { + case kEventClassControl: + switch (ekind) { + case kEventControlValueFieldChanged: + HandleControlChange(); + return true; // handled + } + } + + return false; +} + +void AUPropertyControl::RegisterEvents () +{ +#if !__LP64__ + EventTypeSpec events[] = { + { kEventClassControl, kEventControlValueFieldChanged } // N.B. OS X only + }; + + WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events); +#endif +} + +void AUPropertyControl::EmbedControl (ControlRef theControl) +{ + mView->EmbedControl (theControl); +} + +WindowRef AUPropertyControl::GetCarbonWindow() +{ + return mView->GetCarbonWindow(); +} + +#pragma mark ___AUVPreset +#if !__LP64__ +static CFStringRef kStringFactoryPreset = kAUViewLocalizedStringKey_FactoryPreset; +static bool sAUVPresetLocalized = false; +#endif + +AUVPresets::AUVPresets (AUCarbonViewBase* inParentView, + CFArrayRef& inPresets, + Point inLocation, + int nameWidth, + int controlWidth, + ControlFontStyleRec & inFontStyle) + : AUPropertyControl (inParentView), + mPresets (inPresets), + mView (inParentView) +{ +#if !__LP64__ + Rect r; + + // ok we now have an array of factory presets + // get their strings and display them + + r.top = inLocation.v; r.bottom = r.top; + r.left = inLocation.h; r.right = r.left; + + // localize as necessary + if (!sAUVPresetLocalized) { + CFBundleRef mainBundle = CFBundleGetBundleWithIdentifier(kLocalizedStringBundle_AUView); + if (mainBundle) { + kStringFactoryPreset = CFCopyLocalizedStringFromTableInBundle( + kAUViewLocalizedStringKey_FactoryPreset, kLocalizedStringTable_AUView, + mainBundle, CFSTR("FactoryPreset title string")); + sAUVPresetLocalized = true; + } + } + + // create localized title string + CFMutableStringRef factoryPresetsTitle = CFStringCreateMutable(NULL, 0); + CFStringAppend(factoryPresetsTitle, kStringFactoryPreset); + CFStringAppend(factoryPresetsTitle, kAUViewUnlocalizedString_TitleSeparator); + + ControlRef theControl; + verify_noerr(CreateStaticTextControl(mView->GetCarbonWindow(), &r, factoryPresetsTitle, &inFontStyle, &theControl)); + SInt16 width = 0; + AUCarbonViewControl::SizeControlToFit(theControl, &width, &mHeight); + CFRelease(factoryPresetsTitle); + EmbedControl(theControl); + + r.top -= 2; + r.left += width + 10; + r.right = r.left; + r.bottom = r.top; + + verify_noerr(CreatePopupButtonControl ( mView->GetCarbonWindow(), &r, NULL, + -12345, // DON'T GET MENU FROM RESOURCE mMenuID,!!! + FALSE, // variableWidth, + 0, // titleWidth, + 0, // titleJustification, + 0, // titleStyle, + &mControl)); + + MenuRef menuRef; + verify_noerr(CreateNewMenu(1, 0, &menuRef)); + + int numPresets = CFArrayGetCount(mPresets); + + for (int i = 0; i < numPresets; ++i) + { + AUPreset* preset = (AUPreset*) CFArrayGetValueAtIndex (mPresets, i); + verify_noerr(AppendMenuItemTextWithCFString (menuRef, preset->presetName, 0, 0, 0)); + } + + verify_noerr(SetControlData(mControl, 0, kControlPopupButtonMenuRefTag, sizeof(menuRef), &menuRef)); + verify_noerr (SetControlFontStyle (mControl, &inFontStyle)); + + SetControl32BitMaximum (mControl, numPresets); + + // size popup + SInt16 height = 0; + + AUCarbonViewControl::SizeControlToFit(mControl, &width, &height); + + if (height > mHeight) mHeight = height; + if (mHeight < 0) mHeight = 0; + + // find which menu item is the Default preset + UInt32 propertySize = sizeof(AUPreset); + AUPreset defaultPreset; + OSStatus result = AudioUnitGetProperty (mView->GetEditAudioUnit(), + kAudioUnitProperty_PresentPreset, + kAudioUnitScope_Global, + 0, + &defaultPreset, + &propertySize); + + mPropertyID = kAudioUnitProperty_PresentPreset; +#endif +#ifndef __LP64__ + if (result != noErr) { // if the PresentPreset property is not implemented, fall back to the CurrentPreset property + OSStatus result = AudioUnitGetProperty (mView->GetEditAudioUnit(), + kAudioUnitProperty_CurrentPreset, + kAudioUnitScope_Global, + 0, + &defaultPreset, + &propertySize); + mPropertyID = kAudioUnitProperty_CurrentPreset; + if (result == noErr) + CFRetain (defaultPreset.presetName); + } +#endif +#if !__LP64__ + EmbedControl (mControl); + + HandlePropertyChange(defaultPreset); + + RegisterEvents(); +#endif +} + +void AUVPresets::AddInterest (AUEventListenerRef inListener, + void * inObject) +{ + AudioUnitEvent e; + e.mEventType = kAudioUnitEvent_PropertyChange; + e.mArgument.mProperty.mAudioUnit = mView->GetEditAudioUnit(); + e.mArgument.mProperty.mPropertyID = mPropertyID; + e.mArgument.mProperty.mScope = kAudioUnitScope_Global; + e.mArgument.mProperty.mElement = 0; + + AUEventListenerAddEventType(inListener, inObject, &e); +} + +void AUVPresets::RemoveInterest (AUEventListenerRef inListener, + void * inObject) +{ + AudioUnitEvent e; + e.mEventType = kAudioUnitEvent_PropertyChange; + e.mArgument.mProperty.mAudioUnit = mView->GetEditAudioUnit(); + e.mArgument.mProperty.mPropertyID = mPropertyID; + e.mArgument.mProperty.mScope = kAudioUnitScope_Global; + e.mArgument.mProperty.mElement = 0; + + AUEventListenerRemoveEventType(inListener, inObject, &e); +} + +void AUVPresets::HandleControlChange () +{ +#if !__LP64__ + SInt32 i = GetControl32BitValue(mControl); + if (i > 0) + { + AUPreset* preset = (AUPreset*) CFArrayGetValueAtIndex (mPresets, i-1); + + verify_noerr(AudioUnitSetProperty (mView->GetEditAudioUnit(), + mPropertyID, // either currentPreset or PresentPreset depending on which is supported + kAudioUnitScope_Global, + 0, + preset, + sizeof(AUPreset))); + + // when we change a preset we can't expect the AU to update its state + // as it isn't meant to know that its being viewed! + // so we broadcast a notification to all listeners that all parameters on this AU have changed + AudioUnitParameter changedUnit; + changedUnit.mAudioUnit = mView->GetEditAudioUnit(); + changedUnit.mParameterID = kAUParameterListener_AnyParameter; + verify_noerr (AUParameterListenerNotify (NULL, NULL, &changedUnit) ); + } +#endif +} + +void AUVPresets::HandlePropertyChange(AUPreset &preset) +{ +#if !__LP64__ + // check to see if the preset is in our menu + int numPresets = CFArrayGetCount(mPresets); + if (preset.presetNumber < 0) { + SetControl32BitValue (mControl, 0); //controls are one-based + } else { + for (SInt32 i = 0; i < numPresets; ++i) { + AUPreset* currPreset = (AUPreset*) CFArrayGetValueAtIndex (mPresets, i); + if (preset.presetNumber == currPreset->presetNumber) { + SetControl32BitValue (mControl, ++i); //controls are one-based + break; + } + } + } + + if (preset.presetName) + CFRelease (preset.presetName); +#endif +} + +bool AUVPresets::HandlePropertyChange (const AudioUnitProperty &inProp) +{ + if (inProp.mPropertyID == mPropertyID) + { + UInt32 theSize = sizeof(AUPreset); + AUPreset currentPreset; + + OSStatus result = AudioUnitGetProperty(inProp.mAudioUnit, + inProp.mPropertyID, + inProp.mScope, + inProp.mElement, ¤tPreset, &theSize); + + if (result == noErr) { +#ifndef __LP64__ + if (inProp.mPropertyID == kAudioUnitProperty_CurrentPreset && currentPreset.presetName) + CFRetain (currentPreset.presetName); +#endif + HandlePropertyChange(currentPreset); + return true; + } + } + return false; +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewControl.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewControl.h new file mode 100644 index 0000000000..fb5adb4b83 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewControl.h @@ -0,0 +1,230 @@ +/* + File: AUCarbonViewControl.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUCarbonViewControl_h__ +#define __AUCarbonViewControl_h__ + +#include +#include +#include +#include "CarbonEventHandler.h" +#include "CAAUParameter.h" + +class AUCarbonViewBase; + +// ____________________________________________________________________________ +// AUCarbonViewControl +// Wrapper for a control that is wired to an AudioUnit parameter. + /*! @class AUCarbonViewControl */ +class AUCarbonViewControl : public CarbonEventHandler { + // note that the controls are never disposed; that's managed by the AUCarbonViewBase's + // parent pane which contains all of them ... if we later need to be able to delete + // individual controls on the fly, extra work needed +public: + enum ControlType { + kTypeContinuous, // e.g. slider + kTypeDiscrete, // e.g. pop-up menu + kTypeText + }; + + AUCarbonViewControl(AUCarbonViewBase *ownerView, AUParameterListenerRef listener, ControlType type, const CAAUParameter ¶m, ControlRef control); + ~AUCarbonViewControl(); + + /*! @method Bind */ + virtual void Bind(); // second-stage construction + + /*! @method ControlToParameter */ + virtual void ControlToParameter(); + /*! @method ParameterToControl */ + virtual void ParameterToControl(Float32 newValue); + + /*! @method SetValueFract */ + virtual void SetValueFract(double value); + /*! @method GetValueFract */ + virtual double GetValueFract(); + /*! @method SetTextValue */ + virtual void SetTextValue(CFStringRef str); + /*! @method GetTextValue */ + virtual CFStringRef GetTextValue(); + /*! @method SetValue */ + virtual void SetValue(long value); + /*! @method GetValue */ + virtual long GetValue(); + + /*! @method GetOwnerView */ + AUCarbonViewBase * GetOwnerView() {return mOwnerView;} + + /*! @method Update */ + void Update (bool inUIThread) + { + if (inUIThread) + ParameterToControl (mParam.GetValue()); + else + AUParameterListenerNotify (mListener, this, &mParam); + } + + + // CarbonEventHandler overrides + /*! @method HandleEvent */ + virtual bool HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event); + + /*! @method ControlRef */ + operator ControlRef() { return mControl; } + + /*! @method SizeControlToFit */ + static Boolean SizeControlToFit(ControlRef inControl, SInt16 *outWidth = NULL, SInt16 *outHeight = NULL); + + /*! @method SliderTrackProc */ + static pascal void SliderTrackProc(ControlRef theControl, ControlPartCode partCode); + /*! @method NumericKeyFilterCallback */ + static pascal ControlKeyFilterResult NumericKeyFilterCallback(ControlRef theControl, SInt16 *keyCode, SInt16 *charCode, + EventModifiers *modifiers); +protected: + /*! @method ParamInfo */ + const AudioUnitParameterInfo &ParamInfo() { return mParam.ParamInfo(); } + + /*! @var mOwnerView */ + AUCarbonViewBase * mOwnerView; + /*! @var mListener */ + AUParameterListenerRef mListener; + /*! @var mType */ + ControlType mType; + /*! @var mParam */ + CAAUParameter mParam; + + /*! @var mControl */ + ControlRef mControl; + + /*! @method StdKeyFilterCallback */ + static pascal ControlKeyFilterResult StdKeyFilterCallback(ControlRef theControl, SInt16 *keyCode, SInt16 *charCode, + EventModifiers *modifiers); + SInt16 mInControlInitialization; + + static AUCarbonViewControl* mLastControl; +}; + + /*! @class AUPropertyControl */ +class AUPropertyControl : public CarbonEventHandler { +public: + /*! @ctor AUPropertyControl */ + AUPropertyControl (AUCarbonViewBase * inBase) : mControl(0), mView (inBase), mHeight(0) {} + + /*! @method HandleEvent */ + virtual bool HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event); + + /*! @method HandlePropertyChange */ + virtual bool HandlePropertyChange (const AudioUnitProperty &inProp) = 0; + + /*! @method AddInterest */ + virtual void AddInterest (AUEventListenerRef inListener, + void * inObject) = 0; + + /*! @method RemoveInterest */ + virtual void RemoveInterest (AUEventListenerRef inListener, + void * inObject) = 0; + + /*! @method GetHeight */ + int GetHeight() { return mHeight;} + +protected: + /*! @method HandleControlChange */ + virtual void HandleControlChange () = 0; + + /*! @method RegisterEvents */ + void RegisterEvents (); + + /*! @method EmbedControl */ + void EmbedControl (ControlRef theControl); + + /*! @method GetCarbonWindow */ + WindowRef GetCarbonWindow(); + + /*! @var mControl */ + ControlRef mControl; + /*! @var mView */ + AUCarbonViewBase* mView; + /*! @var mHeight */ + SInt16 mHeight; +}; + + /*! @class AUVPresets */ +class AUVPresets : public AUPropertyControl { +public: + /*! @ctor HandleControlChange */ + AUVPresets (AUCarbonViewBase * inBase, + CFArrayRef& inPresets, + Point inLocation, + int nameWidth, + int controlWidth, + ControlFontStyleRec & inFontStyle); + + virtual ~AUVPresets () { CFRelease (mPresets); } + + /*! @method HandlePropertyChange */ + virtual bool HandlePropertyChange (const AudioUnitProperty &inProp); + + /*! @method AddInterest */ + virtual void AddInterest (AUEventListenerRef inListener, + void * inObject); + + /*! @method RemoveInterest */ + virtual void RemoveInterest (AUEventListenerRef inListener, + void * inObject); + +protected: + /*! @method HandleControlChange */ + virtual void HandleControlChange (); + + /*! @var mPresets */ + CFArrayRef mPresets; + /*! @var mView */ + AUCarbonViewBase* mView; + AudioUnitPropertyID mPropertyID; + + void HandlePropertyChange(AUPreset &preset); +}; + +#endif // __AUCarbonViewControl_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewDispatch.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewDispatch.cpp new file mode 100644 index 0000000000..6b0e65a82c --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUCarbonViewDispatch.cpp @@ -0,0 +1,125 @@ +/* + File: AUCarbonViewDispatch.cpp + Abstract: AUCarbonViewDispatch.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUCarbonViewBase.h" + +// ____________________________________________________________________________ +// component dispatch + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=mac68k +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(push, 2) +#elif PRAGMA_STRUCT_PACK + #pragma pack(2) +#endif + struct AudioUnitCarbonViewCreateGluePB { + unsigned char componentFlags; + unsigned char componentParamSize; + short componentWhat; + ControlRef* outControl; + const Float32Point* inSize; + const Float32Point* inLocation; + ControlRef inParentControl; + WindowRef inWindow; + AudioUnit inAudioUnit; + AudioUnitCarbonView inView; + }; +#if !__LP64__ + struct AudioUnitCarbonViewSetEventListenerGluePB { + unsigned char componentFlags; + unsigned char componentParamSize; + short componentWhat; + void* inUserData; + AudioUnitCarbonViewEventListener inCallback; + AudioUnitCarbonView inView; + }; +#endif +#if PRAGMA_STRUCT_ALIGN + #pragma options align=reset +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(pop) +#elif PRAGMA_STRUCT_PACK + #pragma pack() +#endif + +#define CheckNull(x) if ((x) == NULL) return paramErr; + +OSStatus AUCarbonViewBase::ComponentEntryDispatch(ComponentParameters *p, AUCarbonViewBase *This) +{ + if (This == NULL) return paramErr; + + OSStatus result = noErr; + + switch (p->what) { + case kAudioUnitCarbonViewCreateSelect: + { + AudioUnitCarbonViewCreateGluePB *pb = (AudioUnitCarbonViewCreateGluePB *)p; + CheckNull(pb->inAudioUnit); + CheckNull(pb->inWindow); + CheckNull(pb->inParentControl); + CheckNull(pb->inSize); + CheckNull(pb->inLocation); + CheckNull(pb->outControl); + result = This->CreateCarbonView(pb->inAudioUnit, pb->inWindow, pb->inParentControl, + *pb->inLocation, *pb->inSize, *pb->outControl); + } + break; +#if !__LP64__ + case kAudioUnitCarbonViewSetEventListenerSelect: + { + AudioUnitCarbonViewSetEventListenerGluePB *pb = (AudioUnitCarbonViewSetEventListenerGluePB *)p; + This->SetEventListener(pb->inCallback, pb->inUserData); + } + break; +#endif + + default: + result = ComponentBase::ComponentEntryDispatch(p, This); + break; + } + return result; +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUDispatch.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUDispatch.cpp new file mode 100644 index 0000000000..5543468062 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUDispatch.cpp @@ -0,0 +1,438 @@ +/* + File: AUDispatch.cpp + Abstract: AUDispatch.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUBase.h" +#include "CAXException.h" +#include "AUDispatch.h" + + + +#if TARGET_OS_MAC + #if __LP64__ + // comp instance, parameters in forward order + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_index + 1]; + #else + // parameters in reverse order, then comp instance + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_nparams - 1 - _index]; + #endif +#elif TARGET_OS_WIN32 + // (no comp instance), parameters in forward order + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_index]; +#endif + + +OSStatus AUBase::ComponentEntryDispatch(ComponentParameters *params, AUBase *This) +{ + if (This == NULL) return kAudio_ParamError; + + OSStatus result = noErr; + + switch (params->what) { + case kComponentCanDoSelect: + switch (GetSelectorForCanDo(params)) { + // any selectors + case kAudioUnitInitializeSelect: + case kAudioUnitUninitializeSelect: + case kAudioUnitGetPropertyInfoSelect: + case kAudioUnitGetPropertySelect: + case kAudioUnitSetPropertySelect: + case kAudioUnitAddPropertyListenerSelect: +#if (!__LP64__) + case kAudioUnitRemovePropertyListenerSelect: +#endif + case kAudioUnitGetParameterSelect: + case kAudioUnitSetParameterSelect: + case kAudioUnitResetSelect: + result = 1; + break; + // v1 selectors + + // v2 selectors + case kAudioUnitRemovePropertyListenerWithUserDataSelect: + case kAudioUnitAddRenderNotifySelect: + case kAudioUnitRemoveRenderNotifySelect: + case kAudioUnitScheduleParametersSelect: + case kAudioUnitRenderSelect: + result = (This->AudioUnitAPIVersion() > 1); + break; + + default: + return ComponentBase::ComponentEntryDispatch(params, This); + } + break; + + case kAudioUnitInitializeSelect: + { + CAMutex::Locker lock2(This->GetMutex()); + result = This->DoInitialize(); + } + break; + + case kAudioUnitUninitializeSelect: + { + CAMutex::Locker lock2(This->GetMutex()); + This->DoCleanup(); + result = noErr; + } + break; + + case kAudioUnitGetPropertyInfoSelect: + { + CAMutex::Locker lock(This->GetMutex()); + PARAM(AudioUnitPropertyID, pinID, 0, 5); + PARAM(AudioUnitScope, pinScope, 1, 5); + PARAM(AudioUnitElement, pinElement, 2, 5); + PARAM(UInt32 *, poutDataSize, 3, 5); + PARAM(Boolean *, poutWritable, 4, 5); + + // pass our own copies so that we assume responsibility for testing + // the caller's pointers against null and our C++ classes can + // always assume they're non-null + UInt32 dataSize; + Boolean writable; + + result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement, dataSize, writable); + if (poutDataSize != NULL) + *poutDataSize = dataSize; + if (poutWritable != NULL) + *poutWritable = writable; + } + break; + + case kAudioUnitGetPropertySelect: + { + CAMutex::Locker lock(This->GetMutex()); + PARAM(AudioUnitPropertyID, pinID, 0, 5); + PARAM(AudioUnitScope, pinScope, 1, 5); + PARAM(AudioUnitElement, pinElement, 2, 5); + PARAM(void *, poutData, 3, 5); + PARAM(UInt32 *, pioDataSize, 4, 5); + + UInt32 actualPropertySize, clientBufferSize; + Boolean writable; + char *tempBuffer; + void *destBuffer; + + if (pioDataSize == NULL) { + ca_debug_string("AudioUnitGetProperty: null size pointer"); + result = kAudio_ParamError; + goto finishGetProperty; + } + if (poutData == NULL) { + UInt32 dataSize; + + result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement, dataSize, writable); + *pioDataSize = dataSize; + goto finishGetProperty; + } + + clientBufferSize = *pioDataSize; + if (clientBufferSize == 0) + { + ca_debug_string("AudioUnitGetProperty: *ioDataSize == 0 on entry"); + // $$$ or should we allow this as a shortcut for finding the size? + result = kAudio_ParamError; + goto finishGetProperty; + } + + result = This->DispatchGetPropertyInfo(pinID, pinScope, pinElement, + actualPropertySize, writable); + if (result) + goto finishGetProperty; + + if (clientBufferSize < actualPropertySize) + { + tempBuffer = new char[actualPropertySize]; + destBuffer = tempBuffer; + } else { + tempBuffer = NULL; + destBuffer = poutData; + } + + result = This->DispatchGetProperty(pinID, pinScope, pinElement, destBuffer); + + if (result == noErr) { + if (clientBufferSize < actualPropertySize && tempBuffer != NULL) + { + memcpy(poutData, tempBuffer, clientBufferSize); + delete[] tempBuffer; + // pioDataSize remains correct, the number of bytes we wrote + } else + *pioDataSize = actualPropertySize; + } else + *pioDataSize = 0; + + finishGetProperty: + ; + + } + break; + + case kAudioUnitSetPropertySelect: + { + CAMutex::Locker lock(This->GetMutex()); + PARAM(AudioUnitPropertyID, pinID, 0, 5); + PARAM(AudioUnitScope, pinScope, 1, 5); + PARAM(AudioUnitElement, pinElement, 2, 5); + PARAM(const void *, pinData, 3, 5); + PARAM(UInt32, pinDataSize, 4, 5); + + if (pinData && pinDataSize) + result = This->DispatchSetProperty(pinID, pinScope, pinElement, pinData, pinDataSize); + else { + if (pinData == NULL && pinDataSize == 0) { + result = This->DispatchRemovePropertyValue (pinID, pinScope, pinElement); + } else { + if (pinData == NULL) { + ca_debug_string("AudioUnitSetProperty: inData == NULL"); + result = kAudio_ParamError; + goto finishSetProperty; + } + + if (pinDataSize == 0) { + ca_debug_string("AudioUnitSetProperty: inDataSize == 0"); + result = kAudio_ParamError; + goto finishSetProperty; + } + } + } + finishSetProperty: + ; + + } + break; + + case kAudioUnitAddPropertyListenerSelect: + { + CAMutex::Locker lock(This->GetMutex()); + PARAM(AudioUnitPropertyID, pinID, 0, 3); + PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 3); + PARAM(void *, pinProcRefCon, 2, 3); + result = This->AddPropertyListener(pinID, pinProc, pinProcRefCon); + } + break; + +#if (!__LP64__) + case kAudioUnitRemovePropertyListenerSelect: + { + CAMutex::Locker lock(This->GetMutex()); + PARAM(AudioUnitPropertyID, pinID, 0, 2); + PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 2); + result = This->RemovePropertyListener(pinID, pinProc, NULL, false); + } + break; +#endif + + case kAudioUnitRemovePropertyListenerWithUserDataSelect: + { + CAMutex::Locker lock(This->GetMutex()); + PARAM(AudioUnitPropertyID, pinID, 0, 3); + PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 3); + PARAM(void *, pinProcRefCon, 2, 3); + result = This->RemovePropertyListener(pinID, pinProc, pinProcRefCon, true); + } + break; + + case kAudioUnitAddRenderNotifySelect: + { + CAMutex::Locker lock(This->GetMutex()); + PARAM(AURenderCallback, pinProc, 0, 2); + PARAM(void *, pinProcRefCon, 1, 2); + result = This->SetRenderNotification (pinProc, pinProcRefCon); + } + break; + + case kAudioUnitRemoveRenderNotifySelect: + { + CAMutex::Locker lock(This->GetMutex()); + PARAM(AURenderCallback, pinProc, 0, 2); + PARAM(void *, pinProcRefCon, 1, 2); + result = This->RemoveRenderNotification (pinProc, pinProcRefCon); + } + break; + + case kAudioUnitGetParameterSelect: + { + CAMutex::Locker lock(This->GetMutex()); + PARAM(AudioUnitParameterID, pinID, 0, 4); + PARAM(AudioUnitScope, pinScope, 1, 4); + PARAM(AudioUnitElement, pinElement, 2, 4); + PARAM(AudioUnitParameterValue *, poutValue, 3, 4); + result = (poutValue == NULL ? kAudio_ParamError : This->GetParameter(pinID, pinScope, pinElement, *poutValue)); + } + break; + + case kAudioUnitSetParameterSelect: + { + CAMutex::Locker lock(This->GetMutex()); // is this realtime or no??? + PARAM(AudioUnitParameterID, pinID, 0, 5); + PARAM(AudioUnitScope, pinScope, 1, 5); + PARAM(AudioUnitElement, pinElement, 2, 5); + PARAM(AudioUnitParameterValue, pinValue, 3, 5); + PARAM(UInt32, pinBufferOffsetInFrames, 4, 5); + result = This->SetParameter(pinID, pinScope, pinElement, pinValue, pinBufferOffsetInFrames); + } + break; + + case kAudioUnitScheduleParametersSelect: + { + CAMutex::Locker lock(This->GetMutex()); // is this realtime or no??? + if (This->AudioUnitAPIVersion() > 1) + { + PARAM(AudioUnitParameterEvent *, pinParameterEvent, 0, 2); + PARAM(UInt32, pinNumParamEvents, 1, 2); + result = This->ScheduleParameter (pinParameterEvent, pinNumParamEvents); + } else + result = badComponentSelector; + } + break; + + + case kAudioUnitRenderSelect: + { + // realtime; no lock + { + PARAM(AudioUnitRenderActionFlags *, pinActionFlags, 0, 5); + PARAM(const AudioTimeStamp *, pinTimeStamp, 1, 5); + PARAM(UInt32, pinOutputBusNumber, 2, 5); + PARAM(UInt32, pinNumberFrames, 3, 5); + PARAM(AudioBufferList *, pioData, 4, 5); + AudioUnitRenderActionFlags tempFlags; + + if (pinTimeStamp == NULL || pioData == NULL) + result = kAudio_ParamError; + else { + if (pinActionFlags == NULL) { + tempFlags = 0; + pinActionFlags = &tempFlags; + } + result = This->DoRender(*pinActionFlags, *pinTimeStamp, pinOutputBusNumber, pinNumberFrames, *pioData); + } + } + } + break; + + case kAudioUnitResetSelect: + { + CAMutex::Locker lock(This->GetMutex()); + PARAM(AudioUnitScope, pinScope, 0, 2); + PARAM(AudioUnitElement, pinElement, 1, 2); + This->ResetRenderTime(); + result = This->Reset(pinScope, pinElement); + } + break; + + default: + result = ComponentBase::ComponentEntryDispatch(params, This); + break; + } + + return result; +} + +// Fast dispatch entry points -- these need to replicate all error-checking logic from above + +OSStatus CMgr_AudioUnitBaseGetParameter( AUBase * This, + AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + float *outValue) +{ + OSStatus result = AUBase::noErr; + + try { + if (This == NULL || outValue == NULL) return kAudio_ParamError; + result = This->GetParameter(inID, inScope, inElement, *outValue); + } + COMPONENT_CATCH + + return result; +} + +OSStatus CMgr_AudioUnitBaseSetParameter( AUBase * This, + AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + float inValue, + UInt32 inBufferOffset) +{ + OSStatus result = AUBase::noErr; + + try { + if (This == NULL) return kAudio_ParamError; + result = This->SetParameter(inID, inScope, inElement, inValue, inBufferOffset); + } + COMPONENT_CATCH + + return result; +} + +OSStatus CMgr_AudioUnitBaseRender( AUBase * This, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData) +{ + if (inTimeStamp == NULL || ioData == NULL) return kAudio_ParamError; + + OSStatus result = AUBase::noErr; + AudioUnitRenderActionFlags tempFlags; + + try { + if (ioActionFlags == NULL) { + tempFlags = 0; + ioActionFlags = &tempFlags; + } + result = This->DoRender(*ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, *ioData); + } + COMPONENT_CATCH + + return result; +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUDispatch.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUDispatch.h new file mode 100644 index 0000000000..a07bd032ff --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUDispatch.h @@ -0,0 +1,82 @@ +/* + File: AUDispatch.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUDispatch_h__ +#define __AUDispatch_h__ + + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include "AudioUnit.h" +#endif + +#if !CA_USE_AUDIO_PLUGIN_ONLY +/*! @function AudioUnitBaseGetParameter */ +OSStatus CMgr_AudioUnitBaseGetParameter( AUBase * This, + AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + float * outValue); + +/*! @function AudioUnitBaseSetParameter */ +OSStatus CMgr_AudioUnitBaseSetParameter( AUBase * This, + AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + float inValue, + UInt32 inBufferOffset); + +/*! @function AudioUnitBaseRender */ +OSStatus CMgr_AudioUnitBaseRender( AUBase * This, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData); +#endif + +#endif // __AUDispatch_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUEffectBase.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUEffectBase.cpp new file mode 100644 index 0000000000..74495e10a9 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUEffectBase.cpp @@ -0,0 +1,465 @@ +/* + File: AUEffectBase.cpp + Abstract: AUEffectBase.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUEffectBase.h" + +/* + This class does not deal as well as it should with N-M effects... + + The problem areas are (if the channels don't match): + ProcessInPlace if the channels don't match - there will be problems if InputChan != OutputChan + Bypass - its just passing the buffers through when not processing them + + This will be fixed in a future update... +*/ + +//_____________________________________________________________________________ +// +AUEffectBase::AUEffectBase( AudioComponentInstance audioUnit, + bool inProcessesInPlace ) : + AUBase(audioUnit, 1, 1), // 1 in bus, 1 out bus + mBypassEffect(false), + mParamSRDep (false), + mProcessesInPlace(inProcessesInPlace), + mMainOutput(NULL), mMainInput(NULL) +#if TARGET_OS_IPHONE + , mOnlyOneKernel(false) +#endif +{ +} + +//_____________________________________________________________________________ +// +AUEffectBase::~AUEffectBase() +{ + Cleanup(); +} + +//_____________________________________________________________________________ +// +void AUEffectBase::Cleanup() +{ + for (KernelList::iterator it = mKernelList.begin(); it != mKernelList.end(); ++it) + delete *it; + + mKernelList.clear(); + mMainOutput = NULL; + mMainInput = NULL; +} + + +//_____________________________________________________________________________ +// +OSStatus AUEffectBase::Initialize() +{ + // get our current numChannels for input and output + SInt16 auNumInputs = (SInt16) GetInput(0)->GetStreamFormat().mChannelsPerFrame; + SInt16 auNumOutputs = (SInt16) GetOutput(0)->GetStreamFormat().mChannelsPerFrame; + + // does the unit publish specific information about channel configurations? + const AUChannelInfo *auChannelConfigs = NULL; + UInt32 numIOconfigs = SupportedNumChannels(&auChannelConfigs); + + if ((numIOconfigs > 0) && (auChannelConfigs != NULL)) + { + bool foundMatch = false; + for (UInt32 i = 0; (i < numIOconfigs) && !foundMatch; ++i) + { + SInt16 configNumInputs = auChannelConfigs[i].inChannels; + SInt16 configNumOutputs = auChannelConfigs[i].outChannels; + if ((configNumInputs < 0) && (configNumOutputs < 0)) + { + // unit accepts any number of channels on input and output + if (((configNumInputs == -1) && (configNumOutputs == -2)) + || ((configNumInputs == -2) && (configNumOutputs == -1))) + { + foundMatch = true; + // unit accepts any number of channels on input and output IFF they are the same number on both scopes + } + else if (((configNumInputs == -1) && (configNumOutputs == -1)) && (auNumInputs == auNumOutputs)) + { + foundMatch = true; + // unit has specified a particular number of channels on both scopes + } + else + continue; + } + else + { + // the -1 case on either scope is saying that the unit doesn't care about the + // number of channels on that scope + bool inputMatch = (auNumInputs == configNumInputs) || (configNumInputs == -1); + bool outputMatch = (auNumOutputs == configNumOutputs) || (configNumOutputs == -1); + if (inputMatch && outputMatch) + foundMatch = true; + } + } + if (!foundMatch) + return kAudioUnitErr_FormatNotSupported; + } + else + { + // there is no specifically published channel info + // so for those kinds of effects, the assumption is that the channels (whatever their number) + // should match on both scopes + if ((auNumOutputs != auNumInputs) || (auNumOutputs == 0)) + { + return kAudioUnitErr_FormatNotSupported; + } + } + + MaintainKernels(); + + mMainOutput = GetOutput(0); + mMainInput = GetInput(0); + + const CAStreamBasicDescription& format = GetStreamFormat(kAudioUnitScope_Output, 0); + format.IdentifyCommonPCMFormat(mCommonPCMFormat, NULL); + mBytesPerFrame = format.mBytesPerFrame; + + return noErr; +} + +OSStatus AUEffectBase::Reset( AudioUnitScope inScope, + AudioUnitElement inElement) +{ + for (KernelList::iterator it = mKernelList.begin(); it != mKernelList.end(); ++it) { + AUKernelBase *kernel = *it; + if (kernel != NULL) + kernel->Reset(); + } + + return AUBase::Reset(inScope, inElement); +} + +OSStatus AUEffectBase::GetPropertyInfo (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable) +{ + if (inScope == kAudioUnitScope_Global) { + switch (inID) { + case kAudioUnitProperty_BypassEffect: + outWritable = true; + outDataSize = sizeof (UInt32); + return noErr; + case kAudioUnitProperty_InPlaceProcessing: + outWritable = true; + outDataSize = sizeof (UInt32); + return noErr; + } + } + return AUBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); +} + + +OSStatus AUEffectBase::GetProperty (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData) +{ + if (inScope == kAudioUnitScope_Global) { + switch (inID) { + case kAudioUnitProperty_BypassEffect: + *((UInt32*)outData) = (IsBypassEffect() ? 1 : 0); + return noErr; + case kAudioUnitProperty_InPlaceProcessing: + *((UInt32*)outData) = (mProcessesInPlace ? 1 : 0); + return noErr; + } + } + return AUBase::GetProperty (inID, inScope, inElement, outData); +} + + +OSStatus AUEffectBase::SetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize) +{ + if (inScope == kAudioUnitScope_Global) { + switch (inID) { + case kAudioUnitProperty_BypassEffect: + { + if (inDataSize < sizeof(UInt32)) + return kAudioUnitErr_InvalidPropertyValue; + + bool tempNewSetting = *((UInt32*)inData) != 0; + // we're changing the state of bypass + if (tempNewSetting != IsBypassEffect()) + { + if (!tempNewSetting && IsBypassEffect() && IsInitialized()) // turning bypass off and we're initialized + Reset(0, 0); + SetBypassEffect (tempNewSetting); + } + return noErr; + } + case kAudioUnitProperty_InPlaceProcessing: + mProcessesInPlace = (*((UInt32*)inData) != 0); + return noErr; + } + } + return AUBase::SetProperty (inID, inScope, inElement, inData, inDataSize); +} + + +void AUEffectBase::MaintainKernels() +{ +#if TARGET_OS_IPHONE + UInt32 nKernels = mOnlyOneKernel ? 1 : GetNumberOfChannels(); +#else + UInt32 nKernels = GetNumberOfChannels(); +#endif + + if (mKernelList.size() < nKernels) { + mKernelList.reserve(nKernels); + for (UInt32 i = (UInt32)mKernelList.size(); i < nKernels; ++i) + mKernelList.push_back(NewKernel()); + } else { + while (mKernelList.size() > nKernels) { + AUKernelBase *kernel = mKernelList.back(); + delete kernel; + mKernelList.pop_back(); + } + } + + for(unsigned int i = 0; i < nKernels; i++ ) + { + if(mKernelList[i]) { + mKernelList[i]->SetChannelNum (i); + } + } +} + +bool AUEffectBase::StreamFormatWritable( AudioUnitScope scope, + AudioUnitElement element) +{ + return IsInitialized() ? false : true; +} + +OSStatus AUEffectBase::ChangeStreamFormat( AudioUnitScope inScope, + AudioUnitElement inElement, + const CAStreamBasicDescription & inPrevFormat, + const CAStreamBasicDescription & inNewFormat) +{ + OSStatus result = AUBase::ChangeStreamFormat(inScope, inElement, inPrevFormat, inNewFormat); + if (result == noErr) + { + // for the moment this only dependency we know about + // where a parameter's range may change is with the sample rate + // and effects are only publishing parameters in the global scope! + if (GetParamHasSampleRateDependency() && fnotequal(inPrevFormat.mSampleRate, inNewFormat.mSampleRate)) + PropertyChanged(kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0); + } + + return result; +} + + +// ____________________________________________________________________________ +// +// This method is called (potentially repeatedly) by ProcessForScheduledParams() +// in order to perform the actual DSP required for this portion of the entire buffer +// being processed. The entire buffer can be divided up into smaller "slices" +// according to the timestamps on the scheduled parameters... +// +OSStatus AUEffectBase::ProcessScheduledSlice( void *inUserData, + UInt32 inStartFrameInBuffer, + UInt32 inSliceFramesToProcess, + UInt32 inTotalBufferFrames ) +{ + ScheduledProcessParams &sliceParams = *((ScheduledProcessParams*)inUserData); + + AudioUnitRenderActionFlags &actionFlags = *sliceParams.actionFlags; + AudioBufferList &inputBufferList = *sliceParams.inputBufferList; + AudioBufferList &outputBufferList = *sliceParams.outputBufferList; + + UInt32 channelSize = inSliceFramesToProcess * mBytesPerFrame; + // fix the size of the buffer we're operating on before we render this slice of time + for(unsigned int i = 0; i < inputBufferList.mNumberBuffers; i++ ) { + inputBufferList.mBuffers[i].mDataByteSize = inputBufferList.mBuffers[i].mNumberChannels * channelSize; + } + + for(unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++ ) { + outputBufferList.mBuffers[i].mDataByteSize = outputBufferList.mBuffers[i].mNumberChannels * channelSize; + } + // process the buffer + OSStatus result = ProcessBufferLists(actionFlags, inputBufferList, outputBufferList, inSliceFramesToProcess ); + + // we just partially processed the buffers, so increment the data pointers to the next part of the buffer to process + for(unsigned int i = 0; i < inputBufferList.mNumberBuffers; i++ ) { + inputBufferList.mBuffers[i].mData = + (char *)inputBufferList.mBuffers[i].mData + inputBufferList.mBuffers[i].mNumberChannels * channelSize; + } + + for(unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++ ) { + outputBufferList.mBuffers[i].mData = + (char *)outputBufferList.mBuffers[i].mData + outputBufferList.mBuffers[i].mNumberChannels * channelSize; + } + + return result; +} + +// ____________________________________________________________________________ +// + +OSStatus AUEffectBase::Render( AudioUnitRenderActionFlags &ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 nFrames) +{ + if (!HasInput(0)) + return kAudioUnitErr_NoConnection; + + OSStatus result = noErr; + + result = mMainInput->PullInput(ioActionFlags, inTimeStamp, 0 /* element */, nFrames); + + if (result == noErr) + { + if(ProcessesInPlace() && mMainOutput->WillAllocateBuffer()) + { + mMainOutput->SetBufferList(mMainInput->GetBufferList() ); + } + + if (ShouldBypassEffect()) + { + // leave silence bit alone + + if(!ProcessesInPlace() ) + { + mMainInput->CopyBufferContentsTo (mMainOutput->GetBufferList()); + } + } + else + { + if(mParamList.size() == 0 ) + { + // this will read/write silence bit + result = ProcessBufferLists(ioActionFlags, mMainInput->GetBufferList(), mMainOutput->GetBufferList(), nFrames); + } + else + { + // deal with scheduled parameters... + + AudioBufferList &inputBufferList = mMainInput->GetBufferList(); + AudioBufferList &outputBufferList = mMainOutput->GetBufferList(); + + ScheduledProcessParams processParams; + processParams.actionFlags = &ioActionFlags; + processParams.inputBufferList = &inputBufferList; + processParams.outputBufferList = &outputBufferList; + + // divide up the buffer into slices according to scheduled params then + // do the DSP for each slice (ProcessScheduledSlice() called for each slice) + result = ProcessForScheduledParams( mParamList, + nFrames, + &processParams ); + + + // fixup the buffer pointers to how they were before we started + UInt32 channelSize = nFrames * mBytesPerFrame; + for(unsigned int i = 0; i < inputBufferList.mNumberBuffers; i++ ) { + UInt32 size = inputBufferList.mBuffers[i].mNumberChannels * channelSize; + inputBufferList.mBuffers[i].mData = (char *)inputBufferList.mBuffers[i].mData - size; + inputBufferList.mBuffers[i].mDataByteSize = size; + } + + for(unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++ ) { + UInt32 size = outputBufferList.mBuffers[i].mNumberChannels * channelSize; + outputBufferList.mBuffers[i].mData = (char *)outputBufferList.mBuffers[i].mData - size; + outputBufferList.mBuffers[i].mDataByteSize = size; + } + } + } + + if ( (ioActionFlags & kAudioUnitRenderAction_OutputIsSilence) && !ProcessesInPlace() ) + { + AUBufferList::ZeroBuffer(mMainOutput->GetBufferList() ); + } + } + + return result; +} + + +OSStatus AUEffectBase::ProcessBufferLists( + AudioUnitRenderActionFlags & ioActionFlags, + const AudioBufferList & inBuffer, + AudioBufferList & outBuffer, + UInt32 inFramesToProcess ) +{ + if (ShouldBypassEffect()) + return noErr; + + // interleaved (or mono) + switch (mCommonPCMFormat) { + case CAStreamBasicDescription::kPCMFormatFloat32 : + ProcessBufferListsT(ioActionFlags, inBuffer, outBuffer, inFramesToProcess); + break; + case CAStreamBasicDescription::kPCMFormatFixed824 : + ProcessBufferListsT(ioActionFlags, inBuffer, outBuffer, inFramesToProcess); + break; + case CAStreamBasicDescription::kPCMFormatInt16 : + ProcessBufferListsT(ioActionFlags, inBuffer, outBuffer, inFramesToProcess); + break; + default : + throw CAException(kAudio_UnimplementedError); + } + + return noErr; +} + +Float64 AUEffectBase::GetSampleRate() +{ + return GetOutput(0)->GetStreamFormat().mSampleRate; +} + +UInt32 AUEffectBase::GetNumberOfChannels() +{ + return GetOutput(0)->GetStreamFormat().mChannelsPerFrame; +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUEffectBase.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUEffectBase.h new file mode 100644 index 0000000000..3e74f83941 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUEffectBase.h @@ -0,0 +1,377 @@ +/* + File: AUEffectBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUEffectBase_h__ +#define __AUEffectBase_h__ + +#include "AUBase.h" +#include "AUSilentTimeout.h" +#include "CAException.h" + +class AUKernelBase; + +// Base class for an effect with one input stream, one output stream, +// any number of channels. + /*! @class AUEffectBase */ +class AUEffectBase : public AUBase { +public: + /*! @ctor AUEffectBase */ + AUEffectBase( AudioComponentInstance audioUnit, + bool inProcessesInPlace = true ); + /*! @dtor ~AUEffectBase */ + ~AUEffectBase(); + + /*! @method Initialize */ + virtual OSStatus Initialize(); + + /*! @method Cleanup */ + virtual void Cleanup(); + + + /*! @method Reset */ + virtual OSStatus Reset( AudioUnitScope inScope, + AudioUnitElement inElement); + + /*! @method GetPropertyInfo */ + virtual OSStatus GetPropertyInfo (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable); + + /*! @method GetProperty */ + virtual OSStatus GetProperty (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData); + + /*! @method SetProperty */ + virtual OSStatus SetProperty(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize); + + /*! @method StreamFormatWritable */ + virtual bool StreamFormatWritable (AudioUnitScope scope, + AudioUnitElement element); + + /*! @method ChangeStreamFormat */ + virtual OSStatus ChangeStreamFormat ( + AudioUnitScope inScope, + AudioUnitElement inElement, + const CAStreamBasicDescription & inPrevFormat, + const CAStreamBasicDescription & inNewFormat); + + /*! @method Render */ + virtual OSStatus Render(AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inNumberFrames); + + // our virtual methods + + // If your unit processes N to N channels, and there are no interactions between channels, + // it can override NewKernel to create a mono processing object per channel. Otherwise, + // don't override NewKernel, and instead, override ProcessBufferLists. + /*! @method NewKernel */ + virtual AUKernelBase * NewKernel() { return NULL; } + + /*! @method ProcessBufferLists */ + virtual OSStatus ProcessBufferLists( + AudioUnitRenderActionFlags & ioActionFlags, + const AudioBufferList & inBuffer, + AudioBufferList & outBuffer, + UInt32 inFramesToProcess ); + + // convenience format accessors (use output 0's format) + /*! @method GetSampleRate */ + Float64 GetSampleRate(); + + /*! @method GetNumberOfChannels */ + UInt32 GetNumberOfChannels(); + + // convenience wrappers for accessing parameters in the global scope + /*! @method SetParameter */ + using AUBase::SetParameter; + void SetParameter( AudioUnitParameterID paramID, + AudioUnitParameterValue value) + { + Globals()->SetParameter(paramID, value); + } + + /*! @method GetParameter */ + using AUBase::GetParameter; + AudioUnitParameterValue GetParameter( AudioUnitParameterID paramID ) + { + return Globals()->GetParameter(paramID ); + } + + /*! @method CanScheduleParameters */ + virtual bool CanScheduleParameters() const { return true; } + + /*! @method IsBypassEffect */ + // This is used for the property value - to reflect to the UI if an effect is bypassed + bool IsBypassEffect () { return mBypassEffect; } + +protected: + + /*! @method MaintainKernels */ + void MaintainKernels(); + + /*! @method ShouldBypassEffect */ + // This is used in the render call to see if an effect is bypassed + // It can return a different status than IsBypassEffect (though it MUST take that into account) + virtual bool ShouldBypassEffect () { return IsBypassEffect(); } + +public: + /*! @method SetBypassEffect */ + virtual void SetBypassEffect (bool inFlag) { mBypassEffect = inFlag; } + + /*! @method SetParamHasSampleRateDependency */ + void SetParamHasSampleRateDependency (bool inFlag) + { + mParamSRDep = inFlag; + } + + /*! @method GetParamHasSampleRateDependency */ + bool GetParamHasSampleRateDependency () const { return mParamSRDep; } + + struct ScheduledProcessParams // pointer passed in as void* userData param for ProcessScheduledSlice() + { + AudioUnitRenderActionFlags *actionFlags; + AudioBufferList *inputBufferList; + AudioBufferList *outputBufferList; + }; + + virtual OSStatus ProcessScheduledSlice( void *inUserData, + UInt32 inStartFrameInBuffer, + UInt32 inSliceFramesToProcess, + UInt32 inTotalBufferFrames ); + + + bool ProcessesInPlace() const {return mProcessesInPlace;}; + void SetProcessesInPlace(bool inProcessesInPlace) {mProcessesInPlace = inProcessesInPlace;}; + + typedef std::vector KernelList; + + + +protected: + /*! @var mKernelList */ + KernelList mKernelList; + + AUKernelBase* GetKernel(UInt32 index) { return mKernelList[index]; } + + /*! @method IsInputSilent */ + bool IsInputSilent (AudioUnitRenderActionFlags inActionFlags, UInt32 inFramesToProcess) + { + bool inputSilent = (inActionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0; + + // take latency and tail time into account when propagating the silent bit + UInt32 silentTimeoutFrames = UInt32(GetSampleRate() * (GetLatency() + GetTailTime())); + mSilentTimeout.Process (inFramesToProcess, silentTimeoutFrames, inputSilent); + return inputSilent; + } + +#if TARGET_OS_IPHONE + void SetOnlyOneKernel(bool inUseOnlyOneKernel) { mOnlyOneKernel = inUseOnlyOneKernel; } // set in ctor of subclass that wants it. +#endif + + template + void ProcessBufferListsT( + AudioUnitRenderActionFlags & ioActionFlags, + const AudioBufferList & inBuffer, + AudioBufferList & outBuffer, + UInt32 inFramesToProcess ); + + CAStreamBasicDescription::CommonPCMFormat GetCommonPCMFormat() const { return mCommonPCMFormat; } + + +private: + /*! @var mBypassEffect */ + bool mBypassEffect; + /*! @var mParamSRDep */ + bool mParamSRDep; + + /*! @var mProcessesInplace */ + bool mProcessesInPlace; + + /*! @var mSilentTimeout */ + AUSilentTimeout mSilentTimeout; + + /*! @var mMainOutput */ + AUOutputElement * mMainOutput; + + /*! @var mMainInput */ + AUInputElement * mMainInput; + +#if TARGET_OS_IPHONE + /*! @var mOnlyOneKernel */ + bool mOnlyOneKernel; +#endif + + /*! @var mCommonPCMFormat */ + CAStreamBasicDescription::CommonPCMFormat mCommonPCMFormat; + UInt32 mBytesPerFrame; +}; + + +// Base class for a "kernel", an object that performs DSP on one channel of an interleaved stream. + /*! @class AUKernelBase */ +class AUKernelBase { +public: + /*! @ctor AUKernelBase */ + AUKernelBase(AUEffectBase *inAudioUnit ) : + mAudioUnit(inAudioUnit) { } + + /*! @dtor ~AUKernelBase */ + virtual ~AUKernelBase() { } + + /*! @method Reset */ + virtual void Reset() { } + + /*! @method Process */ + virtual void Process( const Float32 * inSourceP, + Float32 * inDestP, + UInt32 inFramesToProcess, + UInt32 inNumChannels, + bool & ioSilence) { throw CAException(kAudio_UnimplementedError ); } + + /*! @method Process */ + virtual void Process( const SInt32 * inSourceP, + SInt32 * inDestP, + UInt32 inFramesToProcess, + UInt32 inNumChannels, + bool & ioSilence) { throw CAException(kAudio_UnimplementedError ); } + + /*! @method Process */ + virtual void Process( const SInt16 * inSourceP, + SInt16 * inDestP, + UInt32 inFramesToProcess, + UInt32 inNumChannels, + bool & ioSilence) { throw CAException(kAudio_UnimplementedError ); } + + /*! @method GetSampleRate */ + Float64 GetSampleRate() + { + return mAudioUnit->GetSampleRate(); + } + + /*! @method GetParameter */ + AudioUnitParameterValue GetParameter (AudioUnitParameterID paramID) + { + return mAudioUnit->GetParameter(paramID); + } + + void SetChannelNum (UInt32 inChan) { mChannelNum = inChan; } + UInt32 GetChannelNum () { return mChannelNum; } + +protected: + /*! @var mAudioUnit */ + AUEffectBase * mAudioUnit; + UInt32 mChannelNum; + +}; + +template +void AUEffectBase::ProcessBufferListsT( + AudioUnitRenderActionFlags & ioActionFlags, + const AudioBufferList & inBuffer, + AudioBufferList & outBuffer, + UInt32 inFramesToProcess ) +{ + bool ioSilence; + + bool silentInput = IsInputSilent (ioActionFlags, inFramesToProcess); + ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence; + + // call the kernels to handle either interleaved or deinterleaved + if (inBuffer.mNumberBuffers == 1) { + if (inBuffer.mBuffers[0].mNumberChannels == 0) + throw CAException(kAudio_ParamError); + + for (UInt32 channel = 0; channel < mKernelList.size(); ++channel) { + AUKernelBase *kernel = mKernelList[channel]; + + if (kernel == NULL) continue; + ioSilence = silentInput; + + // process each interleaved channel individually + kernel->Process( + (const T *)inBuffer.mBuffers[0].mData + channel, + (T *)outBuffer.mBuffers[0].mData + channel, + inFramesToProcess, + inBuffer.mBuffers[0].mNumberChannels, + ioSilence); + + if (!ioSilence) + ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence; + } + } else { + for (UInt32 channel = 0; channel < mKernelList.size(); ++channel) { + AUKernelBase *kernel = mKernelList[channel]; + + if (kernel == NULL) continue; + + ioSilence = silentInput; + const AudioBuffer *srcBuffer = &inBuffer.mBuffers[channel]; + AudioBuffer *destBuffer = &outBuffer.mBuffers[channel]; + + kernel->Process( + (const T *)srcBuffer->mData, + (T *)destBuffer->mData, + inFramesToProcess, + 1, + ioSilence); + + if (!ioSilence) + ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence; + } + } +} + + +#endif // __AUEffectBase_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputElement.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputElement.cpp new file mode 100644 index 0000000000..5e5ba792fe --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputElement.cpp @@ -0,0 +1,151 @@ +/* + File: AUInputElement.cpp + Abstract: AUInputElement.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUBase.h" + +inline bool HasGoodBufferPointers(const AudioBufferList &abl, UInt32 nBytes) +{ + const AudioBuffer *buf = abl.mBuffers; + for (UInt32 i = abl.mNumberBuffers; i--;++buf) { + if (buf->mData == NULL || buf->mDataByteSize < nBytes) + return false; + } + return true; +} + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// AUInputElement::AUInputElement +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +AUInputElement::AUInputElement(AUBase *audioUnit) : + AUIOElement(audioUnit), + mInputType(kNoInput) +{ +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// AUInputElement::SetConnection +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +void AUInputElement::SetConnection(const AudioUnitConnection &conn) +{ + if (conn.sourceAudioUnit == 0) { + Disconnect(); + return; + } + + mInputType = kFromConnection; + mConnection = conn; + AllocateBuffer(); + + mConnInstanceStorage = NULL; + +#if !CA_USE_AUDIO_PLUGIN_ONLY + mConnRenderProc = NULL; + UInt32 size = sizeof(AudioUnitRenderProc); + OSStatus result = AudioUnitGetProperty( conn.sourceAudioUnit, + kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, + kAudioUnitRenderSelect, + &mConnRenderProc, + &size); + if (result == noErr) + mConnInstanceStorage = CMgr_GetComponentInstanceStorage (conn.sourceAudioUnit); + else + mConnRenderProc = NULL; +#endif +} + +void AUInputElement::Disconnect() +{ + mInputType = kNoInput; + mIOBuffer.Deallocate(); +} + + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// AUInputElement::SetInputCallback +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +void AUInputElement::SetInputCallback(AURenderCallback proc, void *refCon) +{ + if (proc == NULL) + Disconnect(); + else { + mInputType = kFromCallback; + mInputProc = proc; + mInputProcRefCon = refCon; + AllocateBuffer(); + } +} + +OSStatus AUInputElement::SetStreamFormat(const CAStreamBasicDescription &fmt) +{ + OSStatus err = AUIOElement::SetStreamFormat(fmt); + if (err == AUBase::noErr) + AllocateBuffer(); + return err; +} + +OSStatus AUInputElement::PullInput( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + AudioUnitElement inElement, + UInt32 nFrames) +{ + if (!IsActive()) + return kAudioUnitErr_NoConnection; + + AudioBufferList *pullBuffer; + + if (HasConnection() || !WillAllocateBuffer()) + pullBuffer = &mIOBuffer.PrepareNullBuffer(mStreamFormat, nFrames); + else + pullBuffer = &mIOBuffer.PrepareBuffer(mStreamFormat, nFrames); + + return PullInputWithBufferList (ioActionFlags, inTimeStamp, inElement, nFrames, pullBuffer); +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputElement.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputElement.h new file mode 100644 index 0000000000..4a3060c9f3 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputElement.h @@ -0,0 +1,119 @@ +/* + File: AUInputElement.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUInput_h__ +#define __AUInput_h__ + +#include "AUScopeElement.h" +#include "AUBuffer.h" + +/*! @class AUInputElement */ +class AUInputElement : public AUIOElement { +public: + + /*! @ctor AUInputElement */ + AUInputElement(AUBase *audioUnit); + /*! @dtor ~AUInputElement */ + virtual ~AUInputElement() { } + + // AUElement override + /*! @method SetStreamFormat */ + virtual OSStatus SetStreamFormat(const CAStreamBasicDescription &desc); + /*! @method NeedsBufferSpace */ + virtual bool NeedsBufferSpace() const { return IsCallback(); } + + /*! @method SetConnection */ + void SetConnection(const AudioUnitConnection &conn); + /*! @method SetInputCallback */ + void SetInputCallback(AURenderCallback proc, void *refCon); + + /*! @method IsActive */ + bool IsActive() const { return mInputType != kNoInput; } + /*! @method IsCallback */ + bool IsCallback() const { return mInputType == kFromCallback; } + /*! @method HasConnection */ + bool HasConnection() const { return mInputType == kFromConnection; } + + /*! @method PullInput */ + OSStatus PullInput( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + AudioUnitElement inElement, + UInt32 inNumberFrames); + + /*! @method PullInputWithBufferList */ + OSStatus PullInputWithBufferList( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + AudioUnitElement inElement, + UInt32 nFrames, + AudioBufferList * inBufferList); +protected: + /*! @method Disconnect */ + void Disconnect(); + + enum EInputType { kNoInput, kFromConnection, kFromCallback }; + + /*! @var mInputType */ + EInputType mInputType; + + // if from callback: + /*! @var mInputProc */ + AURenderCallback mInputProc; + /*! @var mInputProcRefCon */ + void * mInputProcRefCon; + + // if from connection: + /*! @var mConnection */ + AudioUnitConnection mConnection; +#if !CA_USE_AUDIO_PLUGIN_ONLY + /*! @var mConnRenderProc */ + AudioUnitRenderProc mConnRenderProc; +#endif + /*! @var mConnInstanceStorage */ + void * mConnInstanceStorage; // for the input component +}; + + +#endif // __AUInput_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputFormatConverter.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputFormatConverter.h new file mode 100644 index 0000000000..91c1b8cc5b --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUInputFormatConverter.h @@ -0,0 +1,155 @@ +/* + File: AUInputFormatConverter.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUInputFormatConverter_h__ +#define __AUInputFormatConverter_h__ + +#include "FormatConverterClient.h" +#include "AUTimestampGenerator.h" + +// ____________________________________________________________________________ +// AUInputFormatConverter +// +// Subclass of FormatConverterClient that applies a format conversion +// to an input of an AudioUnit. + /*! @class AUInputFormatConverter */ +class AUInputFormatConverter : public FormatConverterClient { +public: + /*! @ctor AUInputFormatConverter */ + AUInputFormatConverter(AUBase *hostAU, int inputBus) : + mHost(hostAU), + mHostBus(inputBus), + mPreviousSilentFrames(0x1000) + { +#if DEBUG + mTimestampGenerator.mVerbosity = 0; + strcpy(mTimestampGenerator.mDebugName, "AUConverter"); +#endif + } + + // need to subsequently call Initialize, with the desired formats + + /*! @dtor ~AUInputFormatConverter */ + ~AUInputFormatConverter() + { + } + + virtual OSStatus Initialize(const AudioStreamBasicDescription &src, const AudioStreamBasicDescription &dest) + { + OSStatus err = FormatConverterClient::Initialize(src, dest); + if (err) return err; + mIsPCMToPCM = (src.mFormatID == kAudioFormatLinearPCM) && (dest.mFormatID == kAudioFormatLinearPCM); + mHasSRC = (fnonzero(src.mSampleRate) && fnonzero(dest.mSampleRate) && fnotequal(src.mSampleRate, dest.mSampleRate)); + return ca_noErr; + } + + virtual OSStatus Reset() + { + mPreviousSilentFrames = 0x1000; + mTimestampGenerator.Reset(); + return FormatConverterClient::Reset(); + } + + void SetStartInputTimeAtZero(bool b) + { + mTimestampGenerator.SetStartInputAtZero(b); + } + + /*! @method FillComplexBuffer */ + OSStatus AUFillComplexBuffer(const AudioTimeStamp & inTimeStamp, + UInt32 & ioOutputDataPacketSize, + AudioBufferList & outOutputData, + AudioStreamPacketDescription* outPacketDescription, + bool& outSilence) + { + mTimestampGenerator.AddOutputTime(inTimeStamp, ioOutputDataPacketSize, mOutputFormat.mSampleRate); + mSilentOutput = true; + OSStatus err = FillComplexBuffer(ioOutputDataPacketSize, outOutputData, outPacketDescription); + if (mSilentOutput) { + if (!mIsPCMToPCM || (mHasSRC && mPreviousSilentFrames < 32)) + mSilentOutput = false; + mPreviousSilentFrames += ioOutputDataPacketSize; + } else + mPreviousSilentFrames = 0; + outSilence = mSilentOutput; + return err; + } + + /*! @method FormatConverterInputProc */ + virtual OSStatus FormatConverterInputProc( + UInt32 & ioNumberDataPackets, + AudioBufferList & ioData, + AudioStreamPacketDescription** outDataPacketDescription) + { + OSStatus err = ca_noErr; + + AudioUnitRenderActionFlags actionFlags = 0; + AUInputElement *input = mHost->GetInput(mHostBus); + *ioNumberDataPackets = std::min(*ioNumberDataPackets, This->mHost->GetMaxFramesPerSlice()); + const AudioTimeStamp &inputTime = mTimestampGenerator.GenerateInputTime(ioNumberDataPackets, mInputFormat.mSampleRate); + err = input->PullInput(actionFlags, inputTime, mHostBus, ioNumberDataPackets); + if (!err) { + input->CopyBufferListTo(ioData); + if (!(actionFlags & kAudioUnitRenderAction_OutputIsSilence)) + mSilentOutput = false; + } + return err; + } + +protected: + /*! @var mHost */ + AUBase * mHost; + /*! @var mHostBus */ + int mHostBus; + + AUTimestampGenerator mTimestampGenerator; + bool mIsPCMToPCM; + bool mHasSRC; + bool mSilentOutput; + UInt32 mPreviousSilentFrames; +}; + +#endif // __AUInputFormatConverter_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIBase.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIBase.cpp new file mode 100644 index 0000000000..dab6ec5f1f --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIBase.cpp @@ -0,0 +1,495 @@ +/* + File: AUMIDIBase.cpp + Abstract: AUMIDIBase.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUMIDIBase.h" +#include +#include "CAXException.h" + +//temporaray location +enum +{ + kMidiMessage_NoteOff = 0x80, + kMidiMessage_NoteOn = 0x90, + kMidiMessage_PolyPressure = 0xA0, + kMidiMessage_ControlChange = 0xB0, + kMidiMessage_ProgramChange = 0xC0, + kMidiMessage_ChannelPressure = 0xD0, + kMidiMessage_PitchWheel = 0xE0, + + kMidiController_AllSoundOff = 120, + kMidiController_ResetAllControllers = 121, + kMidiController_AllNotesOff = 123 +}; + +AUMIDIBase::AUMIDIBase(AUBase* inBase) + : mAUBaseInstance (*inBase) +{ +#if CA_AUTO_MIDI_MAP + mMapManager = new CAAUMIDIMapManager(); +#endif +} + +AUMIDIBase::~AUMIDIBase() +{ +#if CA_AUTO_MIDI_MAP + if (mMapManager) + delete mMapManager; +#endif +} + +#if TARGET_API_MAC_OSX +OSStatus AUMIDIBase::DelegateGetPropertyInfo(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable) +{ + OSStatus result = noErr; + + switch (inID) { +#if !TARGET_OS_IPHONE + case kMusicDeviceProperty_MIDIXMLNames: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + if (GetXMLNames(NULL) == noErr) { + outDataSize = sizeof(CFURLRef); + outWritable = false; + } else + result = kAudioUnitErr_InvalidProperty; + break; +#endif +#if CA_AUTO_MIDI_MAP + case kAudioUnitProperty_AllParameterMIDIMappings: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + outWritable = true; + outDataSize = sizeof (AUParameterMIDIMapping)*mMapManager->NumMaps(); + result = noErr; + break; + + case kAudioUnitProperty_HotMapParameterMIDIMapping: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + outWritable = true; + outDataSize = sizeof (AUParameterMIDIMapping); + result = noErr; + break; + + case kAudioUnitProperty_AddParameterMIDIMapping: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + outWritable = true; + outDataSize = sizeof (AUParameterMIDIMapping); + result = noErr; + break; + + case kAudioUnitProperty_RemoveParameterMIDIMapping: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + outWritable = true; + outDataSize = sizeof (AUParameterMIDIMapping); + result = noErr; + break; +#endif + + default: + result = kAudioUnitErr_InvalidProperty; + break; + } + return result; + +#if CA_AUTO_MIDI_MAP || (!TARGET_OS_IPHONE) +InvalidScope: + return kAudioUnitErr_InvalidScope; +InvalidElement: + return kAudioUnitErr_InvalidElement; +#endif +} + +OSStatus AUMIDIBase::DelegateGetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData) +{ + OSStatus result; + + switch (inID) { +#if !TARGET_OS_IPHONE + case kMusicDeviceProperty_MIDIXMLNames: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + result = GetXMLNames((CFURLRef *)outData); + break; +#endif +#if CA_AUTO_MIDI_MAP + case kAudioUnitProperty_AllParameterMIDIMappings:{ + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + AUParameterMIDIMapping* maps = (static_cast(outData)); + mMapManager->GetMaps(maps); +// printf ("GETTING MAPS\n"); +// mMapManager->Print(); + result = noErr; + break; + } + + case kAudioUnitProperty_HotMapParameterMIDIMapping:{ + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + AUParameterMIDIMapping * map = (static_cast(outData)); + mMapManager->GetHotParameterMap (*map); + result = noErr; + break; + } +#endif + + default: + result = kAudioUnitErr_InvalidProperty; + break; + } + return result; + +#if CA_AUTO_MIDI_MAP || (!TARGET_OS_IPHONE) +InvalidScope: + return kAudioUnitErr_InvalidScope; +InvalidElement: + return kAudioUnitErr_InvalidElement; +#endif +} + +OSStatus AUMIDIBase::DelegateSetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize) +{ + OSStatus result; + + switch (inID) { +#if CA_AUTO_MIDI_MAP + case kAudioUnitProperty_AddParameterMIDIMapping:{ + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + AUParameterMIDIMapping * maps = (AUParameterMIDIMapping*)inData; + mMapManager->SortedInsertToParamaterMaps (maps, (inDataSize / sizeof(AUParameterMIDIMapping)), mAUBaseInstance); + mAUBaseInstance.PropertyChanged (kAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0); + result = noErr; + break; + } + + case kAudioUnitProperty_RemoveParameterMIDIMapping:{ + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + AUParameterMIDIMapping * maps = (AUParameterMIDIMapping*)inData; + bool didChange; + mMapManager->SortedRemoveFromParameterMaps(maps, (inDataSize / sizeof(AUParameterMIDIMapping)), didChange); + if (didChange) + mAUBaseInstance.PropertyChanged (kAudioUnitProperty_AllParameterMIDIMappings, kAudioUnitScope_Global, 0); + result = noErr; + break; + } + + case kAudioUnitProperty_HotMapParameterMIDIMapping:{ + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + AUParameterMIDIMapping & map = *((AUParameterMIDIMapping*)inData); + mMapManager->SetHotMapping (map); + result = noErr; + break; + } + case kAudioUnitProperty_AllParameterMIDIMappings:{ + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + AUParameterMIDIMapping * mappings = (AUParameterMIDIMapping*)inData; + mMapManager->ReplaceAllMaps (mappings, (inDataSize / sizeof(AUParameterMIDIMapping)), mAUBaseInstance); + result = noErr; + break; + } +#endif + + default: + result = kAudioUnitErr_InvalidProperty; + break; + } + return result; +#if CA_AUTO_MIDI_MAP + InvalidScope: + return kAudioUnitErr_InvalidScope; + InvalidElement: + return kAudioUnitErr_InvalidElement; +#endif +} + + + +#endif //TARGET_API_MAC_OSX + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#pragma mark ____MidiDispatch + + +inline const Byte * NextMIDIEvent(const Byte *event, const Byte *end) +{ + Byte c = *event; + switch (c >> 4) { + default: // data byte -- assume in sysex + while ((*++event & 0x80) == 0 && event < end) + ; + break; + case 0x8: + case 0x9: + case 0xA: + case 0xB: + case 0xE: + event += 3; + break; + case 0xC: + case 0xD: + event += 2; + break; + case 0xF: + switch (c) { + case 0xF0: + while ((*++event & 0x80) == 0 && event < end) + ; + break; + case 0xF1: + case 0xF3: + event += 2; + break; + case 0xF2: + event += 3; + break; + default: + ++event; + break; + } + } + return (event >= end) ? end : event; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// AUMIDIBase::HandleMIDIPacketList +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +OSStatus AUMIDIBase::HandleMIDIPacketList(const MIDIPacketList *pktlist) +{ + if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized; + + int nPackets = pktlist->numPackets; + const MIDIPacket *pkt = pktlist->packet; + + while (nPackets-- > 0) { + const Byte *event = pkt->data, *packetEnd = event + pkt->length; + long startFrame = (long)pkt->timeStamp; + while (event < packetEnd) { + Byte status = event[0]; + if (status & 0x80) { + // really a status byte (not sysex continuation) + HandleMidiEvent(status & 0xF0, status & 0x0F, event[1], event[2], static_cast(startFrame)); + // note that we're generating a bogus channel number for system messages (0xF0-FF) + } + event = NextMIDIEvent(event, packetEnd); + } + pkt = reinterpret_cast(packetEnd); + } + return noErr; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// AUMIDIBase::HandleMidiEvent +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +OSStatus AUMIDIBase::HandleMidiEvent(UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame) +{ + if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized; + +#if CA_AUTO_MIDI_MAP +// you potentially have a choice to make here - if a param mapping matches, do you still want to process the +// MIDI event or not. The default behaviour is to continue on with the MIDI event. + if (mMapManager->HandleHotMapping (status, channel, data1, mAUBaseInstance)) { + mAUBaseInstance.PropertyChanged (kAudioUnitProperty_HotMapParameterMIDIMapping, kAudioUnitScope_Global, 0); + } + else { + mMapManager->FindParameterMapEventMatch(status, channel, data1, data2, inStartFrame, mAUBaseInstance); + } +#endif + + OSStatus result = noErr; + + switch(status) + { + case kMidiMessage_NoteOn: + if(data2) + { + result = HandleNoteOn(channel, data1, data2, inStartFrame); + } + else + { + // zero velocity translates to note off + result = HandleNoteOff(channel, data1, data2, inStartFrame); + } + break; + + case kMidiMessage_NoteOff: + result = HandleNoteOff(channel, data1, data2, inStartFrame); + break; + + default: + result = HandleNonNoteEvent (status, channel, data1, data2, inStartFrame); + break; + } + + return result; +} + +OSStatus AUMIDIBase::HandleNonNoteEvent (UInt8 status, UInt8 channel, UInt8 data1, UInt8 data2, UInt32 inStartFrame) +{ + OSStatus result = noErr; + + switch (status) + { + case kMidiMessage_PitchWheel: + result = HandlePitchWheel(channel, data1, data2, inStartFrame); + break; + + case kMidiMessage_ProgramChange: + result = HandleProgramChange(channel, data1); + break; + + case kMidiMessage_ChannelPressure: + result = HandleChannelPressure(channel, data1, inStartFrame); + break; + + case kMidiMessage_ControlChange: + { + switch (data1) { + case kMidiController_AllNotesOff: + result = HandleAllNotesOff(channel); + break; + + case kMidiController_ResetAllControllers: + result = HandleResetAllControllers(channel); + break; + + case kMidiController_AllSoundOff: + result = HandleAllSoundOff(channel); + break; + + default: + result = HandleControlChange(channel, data1, data2, inStartFrame); + break; + } + break; + } + case kMidiMessage_PolyPressure: + result = HandlePolyPressure (channel, data1, data2, inStartFrame); + break; + } + return result; +} + +OSStatus AUMIDIBase::SysEx (const UInt8 * inData, + UInt32 inLength) +{ + if (!mAUBaseInstance.IsInitialized()) return kAudioUnitErr_Uninitialized; + + return HandleSysEx(inData, inLength ); +} + + + +#if TARGET_OS_MAC + #if __LP64__ + // comp instance, parameters in forward order + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_index + 1]; + #else + // parameters in reverse order, then comp instance + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_nparams - 1 - _index]; + #endif +#elif TARGET_OS_WIN32 + // (no comp instance), parameters in forward order + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_index]; +#endif + +#if !CA_USE_AUDIO_PLUGIN_ONLY +OSStatus AUMIDIBase::ComponentEntryDispatch( ComponentParameters * params, + AUMIDIBase * This) +{ + if (This == NULL) return kAudio_ParamError; + + OSStatus result; + + switch (params->what) { + case kMusicDeviceMIDIEventSelect: + { + PARAM(UInt32, pbinStatus, 0, 4); + PARAM(UInt32, pbinData1, 1, 4); + PARAM(UInt32, pbinData2, 2, 4); + PARAM(UInt32, pbinOffsetSampleFrame, 3, 4); + result = This->MIDIEvent(pbinStatus, pbinData1, pbinData2, pbinOffsetSampleFrame); + } + break; + case kMusicDeviceSysExSelect: + { + PARAM(const UInt8 *, pbinData, 0, 2); + PARAM(UInt32, pbinLength, 1, 2); + result = This->SysEx(pbinData, pbinLength); + } + break; + + default: + result = badComponentSelector; + break; + } + + return result; +} +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIBase.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIBase.h new file mode 100644 index 0000000000..116b18cf13 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIBase.h @@ -0,0 +1,213 @@ +/* + File: AUMIDIBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUMIDIBase_h__ +#define __AUMIDIBase_h__ + +#include "AUBase.h" + +#if CA_AUTO_MIDI_MAP + #include "CAAUMIDIMapManager.h" +#endif + +struct MIDIPacketList; + +// ________________________________________________________________________ +// MusicDeviceBase +// + /*! @class AUMIDIBase */ +class AUMIDIBase { +public: + // this is NOT a copy constructor! + /*! @ctor AUMIDIBase */ + AUMIDIBase(AUBase* inBase); + /*! @dtor ~AUMIDIBase */ + virtual ~AUMIDIBase(); + + /*! @method MIDIEvent */ + virtual OSStatus MIDIEvent( UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) + { + UInt32 strippedStatus = inStatus & 0xf0; + UInt32 channel = inStatus & 0x0f; + + return HandleMidiEvent(strippedStatus, channel, inData1, inData2, inOffsetSampleFrame); + } + + /*! @method HandleMIDIPacketList */ + OSStatus HandleMIDIPacketList(const MIDIPacketList *pktlist); + + /*! @method SysEx */ + virtual OSStatus SysEx( const UInt8 * inData, + UInt32 inLength); + +#if TARGET_API_MAC_OSX + /*! @method DelegateGetPropertyInfo */ + virtual OSStatus DelegateGetPropertyInfo(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable); + + /*! @method DelegateGetProperty */ + virtual OSStatus DelegateGetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData); + + /*! @method DelegateSetProperty */ + virtual OSStatus DelegateSetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize); +#endif + +protected: + // MIDI dispatch + /*! @method HandleMidiEvent */ + virtual OSStatus HandleMidiEvent( UInt8 inStatus, + UInt8 inChannel, + UInt8 inData1, + UInt8 inData2, + UInt32 inStartFrame); + + /*! @method HandleNonNoteEvent */ + virtual OSStatus HandleNonNoteEvent ( UInt8 status, + UInt8 channel, + UInt8 data1, + UInt8 data2, + UInt32 inStartFrame); + +#if TARGET_API_MAC_OSX + /*! @method GetXMLNames */ + virtual OSStatus GetXMLNames(CFURLRef *outNameDocument) + { return kAudioUnitErr_InvalidProperty; } // if not overridden, it's unsupported +#endif + +// channel messages + /*! @method HandleNoteOn */ + virtual OSStatus HandleNoteOn( UInt8 inChannel, + UInt8 inNoteNumber, + UInt8 inVelocity, + UInt32 inStartFrame) { return noErr; } + + /*! @method HandleNoteOff */ + virtual OSStatus HandleNoteOff( UInt8 inChannel, + UInt8 inNoteNumber, + UInt8 inVelocity, + UInt32 inStartFrame) { return noErr; } + + /*! @method HandleControlChange */ + virtual OSStatus HandleControlChange( UInt8 inChannel, + UInt8 inController, + UInt8 inValue, + UInt32 inStartFrame) { return noErr; } + + /*! @method HandlePitchWheel */ + virtual OSStatus HandlePitchWheel( UInt8 inChannel, + UInt8 inPitch1, + UInt8 inPitch2, + UInt32 inStartFrame) { return noErr; } + + /*! @method HandleChannelPressure */ + virtual OSStatus HandleChannelPressure( UInt8 inChannel, + UInt8 inValue, + UInt32 inStartFrame) { return noErr; } + + /*! @method HandleProgramChange */ + virtual OSStatus HandleProgramChange( UInt8 inChannel, + UInt8 inValue) { return noErr; } + + /*! @method HandlePolyPressure */ + virtual OSStatus HandlePolyPressure( UInt8 inChannel, + UInt8 inKey, + UInt8 inValue, + UInt32 inStartFrame) { return noErr; } + + /*! @method HandleResetAllControllers */ + virtual OSStatus HandleResetAllControllers(UInt8 inChannel) { return noErr; } + + /*! @method HandleAllNotesOff */ + virtual OSStatus HandleAllNotesOff( UInt8 inChannel) { return noErr; } + + /*! @method HandleAllSoundOff */ + virtual OSStatus HandleAllSoundOff( UInt8 inChannel) { return noErr; } + + +//System messages + /*! @method HandleSysEx */ + virtual OSStatus HandleSysEx( const UInt8 * inData, + UInt32 inLength ) { return noErr; } + +#if CA_AUTO_MIDI_MAP + /* map manager */ + CAAUMIDIMapManager *GetMIDIMapManager() {return mMapManager;}; + +#endif + + +private: + /*! @var mAUBaseInstance */ + AUBase & mAUBaseInstance; + +#if CA_AUTO_MIDI_MAP + /* map manager */ + CAAUMIDIMapManager * mMapManager; +#endif + +public: +#if !CA_USE_AUDIO_PLUGIN_ONLY + // component dispatcher + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch( ComponentParameters *params, + AUMIDIBase *This); +#endif +}; + +#endif // __AUMIDIBase_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIEffectBase.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIEffectBase.cpp new file mode 100644 index 0000000000..06e5961265 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIEffectBase.cpp @@ -0,0 +1,164 @@ +/* + File: AUMIDIEffectBase.cpp + Abstract: AUMIDIEffectBase.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUMIDIEffectBase.h" + +// compatibility with older OS SDK releases +typedef OSStatus +(*TEMP_MusicDeviceMIDIEventProc)( void * inComponentStorage, + UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame); + +static OSStatus AUMIDIEffectBaseMIDIEvent(void * inComponentStorage, + UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame); + +AUMIDIEffectBase::AUMIDIEffectBase( AudioComponentInstance inInstance, + bool inProcessesInPlace ) + : AUEffectBase(inInstance, inProcessesInPlace), + AUMIDIBase(this) +{ +} + +OSStatus AUMIDIEffectBase::GetPropertyInfo(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable) +{ + OSStatus result; + + result = AUEffectBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); + + if (result == kAudioUnitErr_InvalidProperty) + result = AUMIDIBase::DelegateGetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); + + return result; +} + +OSStatus AUMIDIEffectBase::GetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData) +{ + OSStatus result; + +#if !CA_USE_AUDIO_PLUGIN_ONLY + if (inID == kAudioUnitProperty_FastDispatch) { + if (inElement == kMusicDeviceMIDIEventSelect) { + *(TEMP_MusicDeviceMIDIEventProc *)outData = AUMIDIEffectBaseMIDIEvent; + return noErr; + } + return kAudioUnitErr_InvalidElement; + } +#endif + + result = AUEffectBase::GetProperty (inID, inScope, inElement, outData); + + if (result == kAudioUnitErr_InvalidProperty) + result = AUMIDIBase::DelegateGetProperty (inID, inScope, inElement, outData); + + return result; +} + +OSStatus AUMIDIEffectBase::SetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize) +{ + + OSStatus result = AUEffectBase::SetProperty (inID, inScope, inElement, inData, inDataSize); + + if (result == kAudioUnitErr_InvalidProperty) + result = AUMIDIBase::DelegateSetProperty (inID, inScope, inElement, inData, inDataSize); + + return result; +} + + +#if !TARGET_OS_IPHONE +OSStatus AUMIDIEffectBase::ComponentEntryDispatch(ComponentParameters * params, + AUMIDIEffectBase * This) +{ + if (This == NULL) return paramErr; + + OSStatus result; + + switch (params->what) { + case kMusicDeviceMIDIEventSelect: + case kMusicDeviceSysExSelect: + result = AUMIDIBase::ComponentEntryDispatch (params, This); + break; + default: + result = AUEffectBase::ComponentEntryDispatch(params, This); + break; + } + + return result; +} +#endif + +// fast dispatch +static OSStatus AUMIDIEffectBaseMIDIEvent(void * inComponentStorage, + UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) +{ + OSStatus result = noErr; + try { + AUMIDIEffectBase *This = static_cast(inComponentStorage); + if (This == NULL) return paramErr; + result = This->AUMIDIBase::MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame); + } + COMPONENT_CATCH + return result; +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIEffectBase.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIEffectBase.h new file mode 100644 index 0000000000..1ccd6ccc1b --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUMIDIEffectBase.h @@ -0,0 +1,104 @@ +/* + File: AUMIDIEffectBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUMIDIEffectBase_h__ +#define __AUMIDIEffectBase_h__ + +#include "AUMIDIBase.h" +#include "AUEffectBase.h" + +// ________________________________________________________________________ +// AUMIDIEffectBase +// + /*! @class AUMIDIEffectBase */ +class AUMIDIEffectBase : public AUEffectBase, public AUMIDIBase { +public: + /*! @ctor AUMIDIEffectBase */ + AUMIDIEffectBase( AudioComponentInstance inInstance, + bool inProcessesInPlace = false ); + /*! @method MIDIEvent */ + virtual OSStatus MIDIEvent(UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) + { + return AUMIDIBase::MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame); + } + + /*! @method SysEx */ + virtual OSStatus SysEx(const UInt8 * inData, + UInt32 inLength) + { + return AUMIDIBase::SysEx (inData, inLength); + } + + /*! @method GetPropertyInfo */ + virtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable); + + /*! @method GetProperty */ + virtual OSStatus GetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData); + /*! @method SetProperty */ + virtual OSStatus SetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize); +#if !TARGET_OS_IPHONE + // component dispatcher + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch( ComponentParameters * params, + AUMIDIEffectBase * This); +#endif +}; + +#endif // __AUMIDIEffectBase_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputBase.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputBase.cpp new file mode 100644 index 0000000000..4ee9bb7a7a --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputBase.cpp @@ -0,0 +1,76 @@ +/* + File: AUOutputBase.cpp + Abstract: AUOutputBase.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !CA_USE_AUDIO_PLUGIN_ONLY +#include "AUOutputBase.h" + +OSStatus AUOutputBase::ComponentEntryDispatch(ComponentParameters *params, AUOutputBase *This) +{ + if (This == NULL) return paramErr; + + OSStatus result; + + switch (params->what) { + case kAudioOutputUnitStartSelect: + { + result = This->Start(); + } + break; + + case kAudioOutputUnitStopSelect: + { + result = This->Stop(); + } + break; + + default: + result = badComponentSelector; + break; + } + + return result; +} +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputBase.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputBase.h new file mode 100644 index 0000000000..685c9bce08 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputBase.h @@ -0,0 +1,82 @@ +/* + File: AUOutputBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUOutputBase_h__ +#define __AUOutputBase_h__ + +#include "AUBase.h" + +// ________________________________________________________________________ +// AUOutputBase +// this is now a mix-in rather than an AUBase subclass + + /*! @class AUOutputBase */ +class AUOutputBase { +public: + /*! @ctor AUOutputBase */ + AUOutputBase(AUBase *inBase) : mAUBaseInstance(*inBase) { } + virtual ~AUOutputBase() { } + + // additional component entry points + /*! @method Start */ + virtual OSStatus Start() = 0; + + /*! @method Stop */ + virtual OSStatus Stop() = 0; + +#if !CA_USE_AUDIO_PLUGIN_ONLY + // component dispatcher + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch( ComponentParameters * params, + AUOutputBase * This); +#endif + +private: + /*! @var mAUBaseInstance */ + AUBase & mAUBaseInstance; +}; + +#endif // __AUOutputBase_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputElement.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputElement.cpp new file mode 100644 index 0000000000..658facb659 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputElement.cpp @@ -0,0 +1,62 @@ +/* + File: AUOutputElement.cpp + Abstract: AUOutputElement.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUOutputElement.h" +#include "AUBase.h" + +AUOutputElement::AUOutputElement(AUBase *audioUnit) : + AUIOElement(audioUnit) +{ + AllocateBuffer(); +} + +OSStatus AUOutputElement::SetStreamFormat(const CAStreamBasicDescription &desc) +{ + OSStatus result = AUIOElement::SetStreamFormat(desc); // inherited + if (result == AUBase::noErr) + AllocateBuffer(); + return result; +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputElement.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputElement.h new file mode 100644 index 0000000000..99b7a11a4f --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUOutputElement.h @@ -0,0 +1,66 @@ +/* + File: AUOutputElement.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUOutput_h__ +#define __AUOutput_h__ + +#include "AUScopeElement.h" +#include "AUBuffer.h" + + /*! @class AUOutputElement */ +class AUOutputElement : public AUIOElement { +public: + /*! @ctor AUOutputElement */ + AUOutputElement(AUBase *audioUnit); + + // AUElement override + /*! @method SetStreamFormat */ + virtual OSStatus SetStreamFormat(const CAStreamBasicDescription &desc); + /*! @method NeedsBufferSpace */ + virtual bool NeedsBufferSpace() const { return true; } +}; + +#endif // __AUOutput_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUPlugInDispatch.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUPlugInDispatch.cpp new file mode 100644 index 0000000000..3575a64593 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUPlugInDispatch.cpp @@ -0,0 +1,668 @@ +/* + File: AUPlugInDispatch.cpp + Abstract: AUPlugInDispatch.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUPlugInDispatch.h" +#include "CAXException.h" +#include "ComponentBase.h" +#include "AUBase.h" + +#define ACPI ((AudioComponentPlugInInstance *)self) +#define AUI ((AUBase *)&ACPI->mInstanceStorage) + +#define AUI_LOCK CAMutex::Locker auLock(AUI->GetMutex()); + +// ------------------------------------------------------------------------------------------------ +static OSStatus AUMethodInitialize(void *self) +{ + OSStatus result = noErr; + try { + AUI_LOCK + result = AUI->DoInitialize(); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodUninitialize(void *self) +{ + OSStatus result = noErr; + try { + AUI_LOCK + AUI->DoCleanup(); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodGetPropertyInfo(void *self, AudioUnitPropertyID prop, AudioUnitScope scope, AudioUnitElement elem, UInt32 *outDataSize, Boolean *outWritable) +{ + OSStatus result = noErr; + try { + UInt32 dataSize = 0; // 13517289 GetPropetyInfo was returning an uninitialized value when there is an error. This is a problem for auval. + Boolean writable = false; + + AUI_LOCK + result = AUI->DispatchGetPropertyInfo(prop, scope, elem, dataSize, writable); + if (outDataSize != NULL) + *outDataSize = dataSize; + if (outWritable != NULL) + *outWritable = writable; + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodGetProperty(void *self, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void *outData, UInt32 *ioDataSize) +{ + OSStatus result = noErr; + try { + UInt32 actualPropertySize, clientBufferSize; + Boolean writable; + char *tempBuffer; + void *destBuffer; + + AUI_LOCK + if (ioDataSize == NULL) { + ca_debug_string("AudioUnitGetProperty: null size pointer"); + result = kAudio_ParamError; + goto finishGetProperty; + } + if (outData == NULL) { + UInt32 dataSize; + + result = AUI->DispatchGetPropertyInfo(inID, inScope, inElement, dataSize, writable); + *ioDataSize = dataSize; + goto finishGetProperty; + } + + clientBufferSize = *ioDataSize; + if (clientBufferSize == 0) + { + ca_debug_string("AudioUnitGetProperty: *ioDataSize == 0 on entry"); + // $$$ or should we allow this as a shortcut for finding the size? + result = kAudio_ParamError; + goto finishGetProperty; + } + + result = AUI->DispatchGetPropertyInfo(inID, inScope, inElement, actualPropertySize, writable); + if (result != noErr) + goto finishGetProperty; + + if (clientBufferSize < actualPropertySize) + { + tempBuffer = new char[actualPropertySize]; + destBuffer = tempBuffer; + } else { + tempBuffer = NULL; + destBuffer = outData; + } + + result = AUI->DispatchGetProperty(inID, inScope, inElement, destBuffer); + + if (result == noErr) { + if (clientBufferSize < actualPropertySize && tempBuffer != NULL) + { + memcpy(outData, tempBuffer, clientBufferSize); + delete[] tempBuffer; + // ioDataSize remains correct, the number of bytes we wrote + } else + *ioDataSize = actualPropertySize; + } else + *ioDataSize = 0; + } + COMPONENT_CATCH +finishGetProperty: + return result; +} + +static OSStatus AUMethodSetProperty(void *self, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void *inData, UInt32 inDataSize) +{ + OSStatus result = noErr; + try { + AUI_LOCK + if (inData && inDataSize) + result = AUI->DispatchSetProperty(inID, inScope, inElement, inData, inDataSize); + else { + if (inData == NULL && inDataSize == 0) { + result = AUI->DispatchRemovePropertyValue(inID, inScope, inElement); + } else { + if (inData == NULL) { + ca_debug_string("AudioUnitSetProperty: inData == NULL"); + result = kAudio_ParamError; + goto finishSetProperty; + } + + if (inDataSize == 0) { + ca_debug_string("AudioUnitSetProperty: inDataSize == 0"); + result = kAudio_ParamError; + goto finishSetProperty; + } + } + } + } + COMPONENT_CATCH +finishSetProperty: + return result; +} + +static OSStatus AUMethodAddPropertyListener(void *self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void *userData) +{ + OSStatus result = noErr; + try { + AUI_LOCK + result = AUI->AddPropertyListener(prop, proc, userData); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodRemovePropertyListener(void *self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc) +{ + OSStatus result = noErr; + try { + AUI_LOCK + result = AUI->RemovePropertyListener(prop, proc, NULL, false); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodRemovePropertyListenerWithUserData(void *self, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void *userData) +{ + OSStatus result = noErr; + try { + AUI_LOCK + result = AUI->RemovePropertyListener(prop, proc, userData, true); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodAddRenderNotify(void *self, AURenderCallback proc, void *userData) +{ + OSStatus result = noErr; + try { + AUI_LOCK + result = AUI->SetRenderNotification(proc, userData); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodRemoveRenderNotify(void *self, AURenderCallback proc, void *userData) +{ + OSStatus result = noErr; + try { + AUI_LOCK + result = AUI->RemoveRenderNotification(proc, userData); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodGetParameter(void *self, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement elem, AudioUnitParameterValue *value) +{ + OSStatus result = noErr; + try { + AUI_LOCK + result = (value == NULL ? kAudio_ParamError : AUI->GetParameter(param, scope, elem, *value)); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodSetParameter(void *self, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement elem, AudioUnitParameterValue value, UInt32 bufferOffset) +{ + OSStatus result = noErr; + try { + // this is a (potentially) realtime method; no lock + result = AUI->SetParameter(param, scope, elem, value, bufferOffset); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodScheduleParameters(void *self, const AudioUnitParameterEvent *events, UInt32 numEvents) +{ + OSStatus result = noErr; + try { + // this is a (potentially) realtime method; no lock + result = AUI->ScheduleParameter(events, numEvents); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodRender(void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) +{ + OSStatus result = noErr; + +#if !TARGET_OS_IPHONE + try { +#endif + // this is a processing method; no lock + AudioUnitRenderActionFlags tempFlags; + + if (inTimeStamp == NULL || ioData == NULL) + result = kAudio_ParamError; + else { + if (ioActionFlags == NULL) { + tempFlags = 0; + ioActionFlags = &tempFlags; + } + result = AUI->DoRender(*ioActionFlags, *inTimeStamp, inOutputBusNumber, inNumberFrames, *ioData); + } + +#if !TARGET_OS_IPHONE + } + COMPONENT_CATCH +#endif + + return result; +} + +static OSStatus AUMethodComplexRender(void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberOfPackets, UInt32 *outNumberOfPackets, AudioStreamPacketDescription *outPacketDescriptions, AudioBufferList *ioData, void *outMetadata, UInt32 *outMetadataByteSize) +{ + OSStatus result = noErr; + +#if !TARGET_OS_IPHONE + try { +#endif + // this is a processing method; no lock + AudioUnitRenderActionFlags tempFlags; + + if (inTimeStamp == NULL || ioData == NULL) + result = kAudio_ParamError; + else { + if (ioActionFlags == NULL) { + tempFlags = 0; + ioActionFlags = &tempFlags; + } + result = AUI->ComplexRender(*ioActionFlags, *inTimeStamp, inOutputBusNumber, inNumberOfPackets, outNumberOfPackets, outPacketDescriptions, *ioData, outMetadata, outMetadataByteSize); + } + +#if !TARGET_OS_IPHONE + } + COMPONENT_CATCH +#endif + + return result; +} + +static OSStatus AUMethodReset(void *self, AudioUnitScope scope, AudioUnitElement elem) +{ + OSStatus result = noErr; + try { + AUI_LOCK + result = AUI->Reset(scope, elem); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodProcess (void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) +{ + OSStatus result = noErr; + +#if !TARGET_OS_IPHONE + try { +#endif + // this is a processing method; no lock + bool doParamCheck = true; + + AudioUnitRenderActionFlags tempFlags; + + if (ioActionFlags == NULL) { + tempFlags = 0; + ioActionFlags = &tempFlags; + } else { + if (*ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/) + doParamCheck = false; + } + + if (doParamCheck && (inTimeStamp == NULL || ioData == NULL)) + result = kAudio_ParamError; + else { + result = AUI->DoProcess(*ioActionFlags, *inTimeStamp, inNumberFrames, *ioData); + } + +#if !TARGET_OS_IPHONE + } + COMPONENT_CATCH +#endif + + return result; +} + +static OSStatus AUMethodProcessMultiple (void *self, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, UInt32 inNumberInputBufferLists, const AudioBufferList **inInputBufferLists, UInt32 inNumberOutputBufferLists, AudioBufferList **ioOutputBufferLists) +{ + OSStatus result = noErr; + +#if !TARGET_OS_IPHONE + try { +#endif + // this is a processing method; no lock + bool doParamCheck = true; + + AudioUnitRenderActionFlags tempFlags; + + if (ioActionFlags == NULL) { + tempFlags = 0; + ioActionFlags = &tempFlags; + } else { + if (*ioActionFlags & (1 << 9)/*kAudioUnitRenderAction_DoNotCheckRenderArgs*/) + doParamCheck = false; + } + + if (doParamCheck && (inTimeStamp == NULL || inInputBufferLists == NULL || ioOutputBufferLists == NULL)) + result = kAudio_ParamError; + else { + result = AUI->DoProcessMultiple(*ioActionFlags, *inTimeStamp, inNumberFrames, inNumberInputBufferLists, inInputBufferLists, inNumberOutputBufferLists, ioOutputBufferLists); + } + +#if !TARGET_OS_IPHONE + } + COMPONENT_CATCH +#endif + + return result; +} +// ------------------------------------------------------------------------------------------------ + +static OSStatus AUMethodStart(void *self) +{ + OSStatus result = noErr; + try { + AUI_LOCK + result = AUI->Start(); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodStop(void *self) +{ + OSStatus result = noErr; + try { + AUI_LOCK + result = AUI->Stop(); + } + COMPONENT_CATCH + return result; +} + +// ------------------------------------------------------------------------------------------------ + +#if !CA_BASIC_AU_FEATURES +// I don't know what I'm doing here; conflicts with the multiple inheritence in MusicDeviceBase. +static OSStatus AUMethodMIDIEvent(void *self, UInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame) +{ + OSStatus result = noErr; + try { + // this is a potential render-time method; no lock + result = AUI->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodSysEx(void *self, const UInt8 *inData, UInt32 inLength) +{ + OSStatus result = noErr; + try { + // this is a potential render-time method; no lock + result = AUI->SysEx(inData, inLength); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodStartNote(void *self, MusicDeviceInstrumentID inInstrument, MusicDeviceGroupID inGroupID, NoteInstanceID *outNoteInstanceID, UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams *inParams) +{ + OSStatus result = noErr; + try { + // this is a potential render-time method; no lock + if (inParams == NULL || outNoteInstanceID == NULL) + result = kAudio_ParamError; + else + result = AUI->StartNote(inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodStopNote(void *self, MusicDeviceGroupID inGroupID, NoteInstanceID inNoteInstanceID, UInt32 inOffsetSampleFrame) +{ + OSStatus result = noErr; + try { + // this is a potential render-time method; no lock + result = AUI->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame); + } + COMPONENT_CATCH + return result; +} + +#if !TARGET_OS_IPHONE +static OSStatus AUMethodPrepareInstrument (void *self, MusicDeviceInstrumentID inInstrument) +{ + OSStatus result = noErr; + try { + // this is a potential render-time method; no lock + result = AUI->PrepareInstrument(inInstrument); + } + COMPONENT_CATCH + return result; +} + +static OSStatus AUMethodReleaseInstrument (void *self, MusicDeviceInstrumentID inInstrument) +{ + OSStatus result = noErr; + try { + // this is a potential render-time method; no lock + result = AUI->ReleaseInstrument(inInstrument); + } + COMPONENT_CATCH + return result; +} +#endif // TARGET_OS_IPHONE +#endif // CA_BASIC_AU_FEATURES + + +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#pragma mark - +#pragma mark Lookup Methods + +AudioComponentMethod AUBaseLookup::Lookup (SInt16 selector) +{ + switch (selector) { + case kAudioUnitInitializeSelect: return (AudioComponentMethod)AUMethodInitialize; + case kAudioUnitUninitializeSelect: return (AudioComponentMethod)AUMethodUninitialize; + case kAudioUnitGetPropertyInfoSelect: return (AudioComponentMethod)AUMethodGetPropertyInfo; + case kAudioUnitGetPropertySelect: return (AudioComponentMethod)AUMethodGetProperty; + case kAudioUnitSetPropertySelect: return (AudioComponentMethod)AUMethodSetProperty; + case kAudioUnitAddPropertyListenerSelect:return (AudioComponentMethod)AUMethodAddPropertyListener; + case kAudioUnitRemovePropertyListenerSelect: + return (AudioComponentMethod)AUMethodRemovePropertyListener; + case kAudioUnitRemovePropertyListenerWithUserDataSelect: + return (AudioComponentMethod)AUMethodRemovePropertyListenerWithUserData; + case kAudioUnitAddRenderNotifySelect: return (AudioComponentMethod)AUMethodAddRenderNotify; + case kAudioUnitRemoveRenderNotifySelect:return (AudioComponentMethod)AUMethodRemoveRenderNotify; + case kAudioUnitGetParameterSelect: return (AudioComponentMethod)AUMethodGetParameter; + case kAudioUnitSetParameterSelect: return (AudioComponentMethod)AUMethodSetParameter; + case kAudioUnitScheduleParametersSelect:return (AudioComponentMethod)AUMethodScheduleParameters; + case kAudioUnitRenderSelect: return (AudioComponentMethod)AUMethodRender; + case kAudioUnitResetSelect: return (AudioComponentMethod)AUMethodReset; + default: + break; + } + return NULL; +} + +AudioComponentMethod AUOutputLookup::Lookup (SInt16 selector) +{ + AudioComponentMethod method = AUBaseLookup::Lookup(selector); + if (method) return method; + + switch (selector) { + case kAudioOutputUnitStartSelect: return (AudioComponentMethod)AUMethodStart; + case kAudioOutputUnitStopSelect: return (AudioComponentMethod)AUMethodStop; + default: + break; + } + return NULL; +} + +AudioComponentMethod AUComplexOutputLookup::Lookup (SInt16 selector) +{ + AudioComponentMethod method = AUBaseLookup::Lookup(selector); + if (method) return method; + + method = AUOutputLookup::Lookup(selector); + if (method) return method; + + if (selector == kAudioUnitComplexRenderSelect) + return (AudioComponentMethod)AUMethodComplexRender; + return NULL; +} + +AudioComponentMethod AUBaseProcessLookup::Lookup (SInt16 selector) +{ + AudioComponentMethod method = AUBaseLookup::Lookup(selector); + if (method) return method; + + if (selector == kAudioUnitProcessSelect) + return (AudioComponentMethod)AUMethodProcess; + + return NULL; +} + +AudioComponentMethod AUBaseProcessMultipleLookup::Lookup (SInt16 selector) +{ + AudioComponentMethod method = AUBaseLookup::Lookup(selector); + if (method) return method; + + if (selector == kAudioUnitProcessMultipleSelect) + return (AudioComponentMethod)AUMethodProcessMultiple; + + return NULL; +} + +AudioComponentMethod AUBaseProcessAndMultipleLookup::Lookup (SInt16 selector) +{ + AudioComponentMethod method = AUBaseLookup::Lookup(selector); + if (method) return method; + + method = AUBaseProcessMultipleLookup::Lookup(selector); + if (method) return method; + + method = AUBaseProcessLookup::Lookup(selector); + if (method) return method; + + return NULL; +} + +#if !CA_BASIC_AU_FEATURES +inline AudioComponentMethod MIDI_Lookup (SInt16 selector) +{ + switch (selector) { + case kMusicDeviceMIDIEventSelect: return (AudioComponentMethod)AUMethodMIDIEvent; + case kMusicDeviceSysExSelect: return (AudioComponentMethod)AUMethodSysEx; + default: + break; + } + return NULL; +} + +AudioComponentMethod AUMIDILookup::Lookup (SInt16 selector) +{ + AudioComponentMethod method = AUBaseLookup::Lookup(selector); + if (method) return method; + + return MIDI_Lookup(selector); +} + +AudioComponentMethod AUMIDIProcessLookup::Lookup (SInt16 selector) +{ + AudioComponentMethod method = AUBaseProcessLookup::Lookup(selector); + if (method) return method; + + return MIDI_Lookup(selector); +} + +AudioComponentMethod AUMusicLookup::Lookup (SInt16 selector) +{ + AudioComponentMethod method = AUBaseLookup::Lookup(selector); + if (method) return method; + + switch (selector) { + case kMusicDeviceStartNoteSelect: return (AudioComponentMethod)AUMethodStartNote; + case kMusicDeviceStopNoteSelect: return (AudioComponentMethod)AUMethodStopNote; +#if !TARGET_OS_IPHONE + case kMusicDevicePrepareInstrumentSelect: return (AudioComponentMethod)AUMethodPrepareInstrument; + case kMusicDeviceReleaseInstrumentSelect: return (AudioComponentMethod)AUMethodReleaseInstrument; +#endif + default: + break; + } + return MIDI_Lookup (selector); +} + +AudioComponentMethod AUAuxBaseLookup::Lookup (SInt16 selector) +{ + switch (selector) { + case kAudioUnitGetPropertyInfoSelect: return (AudioComponentMethod)AUMethodGetPropertyInfo; + case kAudioUnitGetPropertySelect: return (AudioComponentMethod)AUMethodGetProperty; + case kAudioUnitSetPropertySelect: return (AudioComponentMethod)AUMethodSetProperty; + + case kAudioUnitGetParameterSelect: return (AudioComponentMethod)AUMethodGetParameter; + case kAudioUnitSetParameterSelect: return (AudioComponentMethod)AUMethodSetParameter; + + default: + break; + } + return NULL; +} +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUPlugInDispatch.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUPlugInDispatch.h new file mode 100644 index 0000000000..54e748e3a8 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUPlugInDispatch.h @@ -0,0 +1,144 @@ +/* + File: AUPlugInDispatch.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUPlugInBase_h__ +#define __AUPlugInBase_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #if !CA_BASIC_AU_FEATURES + #include + #endif +#else + #include "AudioComponent.h" + #include "MusicDevice.h" +#endif + +#include "ComponentBase.h" + +struct AUBaseLookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template +class AUBaseFactory : public APFactory +{ +}; + +struct AUOutputLookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template +class AUOutputBaseFactory : public APFactory +{ +}; + +struct AUComplexOutputLookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template +class AUOutputComplexBaseFactory : public APFactory +{ +}; + +struct AUBaseProcessLookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template +class AUBaseProcessFactory : public APFactory +{ +}; + +struct AUBaseProcessMultipleLookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template +class AUBaseProcessMultipleFactory : public APFactory +{ +}; + +struct AUBaseProcessAndMultipleLookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template +class AUBaseProcessAndMultipleFactory : public APFactory +{ +}; + +#if !CA_BASIC_AU_FEATURES +struct AUMIDILookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template +class AUMIDIEffectFactory : public APFactory +{ +}; + +struct AUMIDIProcessLookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template +class AUMIDIProcessFactory : public APFactory +{ +}; + +struct AUMusicLookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template +class AUMusicDeviceFactory : public APFactory +{ +}; + +struct AUAuxBaseLookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template +class AUAuxBaseFactory : public APFactory +{ +}; +#endif // CA_BASIC_AU_FEATURES + +#endif // __AUPlugInBase_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUScopeElement.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUScopeElement.cpp new file mode 100644 index 0000000000..c441dfe642 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUScopeElement.cpp @@ -0,0 +1,565 @@ +/* + File: AUScopeElement.cpp + Abstract: AUScopeElement.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AUScopeElement.h" +#include "AUBase.h" + +//_____________________________________________________________________________ +// +// By default, parameterIDs may be arbitrarily spaced, and an STL map +// will be used for access. Calling UseIndexedParameters() will +// instead use an STL vector for faster indexed access. +// This assumes the paramIDs are numbered 0.....inNumberOfParameters-1 +// Call this before defining/adding any parameters with SetParameter() +// +void AUElement::UseIndexedParameters(int inNumberOfParameters) +{ + mIndexedParameters.resize (inNumberOfParameters); + mUseIndexedParameters = true; +} + +//_____________________________________________________________________________ +// +// Helper method. +// returns the ParameterMapEvent object associated with the paramID +// +inline ParameterMapEvent& AUElement::GetParamEvent(AudioUnitParameterID paramID) +{ + ParameterMapEvent *event; + + if(mUseIndexedParameters) + { + if(paramID >= mIndexedParameters.size() ) + COMPONENT_THROW(kAudioUnitErr_InvalidParameter); + + event = &mIndexedParameters[paramID]; + } + else + { + ParameterMap::iterator i = mParameters.find(paramID); + if (i == mParameters.end()) + COMPONENT_THROW(kAudioUnitErr_InvalidParameter); + + event = &(*i).second; + } + + return *event; +} + +//_____________________________________________________________________________ +// +// Helper method. +// returns whether the specified paramID is known to the element +// +bool AUElement::HasParameterID (AudioUnitParameterID paramID) const +{ + if(mUseIndexedParameters) + { + if(paramID >= mIndexedParameters.size() ) + return false; + + return true; + } + + ParameterMap::const_iterator i = mParameters.find(paramID); + if (i == mParameters.end()) + return false; + + return true; +} + +//_____________________________________________________________________________ +// +// caller assumes that this is actually an immediate parameter +// +AudioUnitParameterValue AUElement::GetParameter(AudioUnitParameterID paramID) +{ + ParameterMapEvent &event = GetParamEvent(paramID); + + return event.GetValue(); +} + + +//_____________________________________________________________________________ +// +void AUElement::GetRampSliceStartEnd( AudioUnitParameterID paramID, + AudioUnitParameterValue & outStartValue, + AudioUnitParameterValue & outEndValue, + AudioUnitParameterValue & outValuePerFrameDelta ) + +{ + ParameterMapEvent &event = GetParamEvent(paramID); + + // works even if the value is constant (immediate parameter value) + event.GetRampSliceStartEnd(outStartValue, outEndValue, outValuePerFrameDelta ); +} + +//_____________________________________________________________________________ +// +AudioUnitParameterValue AUElement::GetEndValue( AudioUnitParameterID paramID) + +{ + ParameterMapEvent &event = GetParamEvent(paramID); + + // works even if the value is constant (immediate parameter value) + return event.GetEndValue(); +} + +//_____________________________________________________________________________ +// +void AUElement::SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue inValue, bool okWhenInitialized) +{ + if(mUseIndexedParameters) + { + ParameterMapEvent &event = GetParamEvent(paramID); + event.SetValue(inValue); + } + else + { + ParameterMap::iterator i = mParameters.find(paramID); + + if (i == mParameters.end()) + { + if (mAudioUnit->IsInitialized() && !okWhenInitialized) { + // The AU should not be creating new parameters once initialized. + // If a client tries to set an undefined parameter, we could throw as follows, + // but this might cause a regression. So it is better to just fail silently. + // COMPONENT_THROW(kAudioUnitErr_InvalidParameter); +#if DEBUG + fprintf(stderr, "WARNING: %s SetParameter for undefined param ID %d while initialized. Ignoring..\n", + mAudioUnit->GetLoggingString(), (int)paramID); +#endif + } else { + // create new entry in map for the paramID (only happens first time) + ParameterMapEvent event(inValue); + mParameters[paramID] = event; + } + } + else + { + // paramID already exists in map so simply change its value + ParameterMapEvent &event = (*i).second; + event.SetValue(inValue); + } + } +} + +//_____________________________________________________________________________ +// +void AUElement::SetScheduledEvent( AudioUnitParameterID paramID, + const AudioUnitParameterEvent &inEvent, + UInt32 inSliceOffsetInBuffer, + UInt32 inSliceDurationFrames, + bool okWhenInitialized ) +{ + if(mUseIndexedParameters) + { + ParameterMapEvent &event = GetParamEvent(paramID); + event.SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames ); + } + else + { + ParameterMap::iterator i = mParameters.find(paramID); + + if (i == mParameters.end()) + { + if (mAudioUnit->IsInitialized() && !okWhenInitialized) { + // The AU should not be creating new parameters once initialized. + // If a client tries to set an undefined parameter, we could throw as follows, + // but this might cause a regression. So it is better to just fail silently. + // COMPONENT_THROW(kAudioUnitErr_InvalidParameter); +#if DEBUG + fprintf(stderr, "WARNING: %s SetScheduledEvent for undefined param ID %d while initialized. Ignoring..\n", + mAudioUnit->GetLoggingString(), (int)paramID); +#endif + } else { + // create new entry in map for the paramID (only happens first time) + ParameterMapEvent event(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames); + mParameters[paramID] = event; + } + } + else + { + // paramID already exists in map so simply change its value + ParameterMapEvent &event = (*i).second; + + event.SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames ); + } + } +} + + + +//_____________________________________________________________________________ +// +void AUElement::GetParameterList(AudioUnitParameterID *outList) +{ + if(mUseIndexedParameters) + { + UInt32 nparams = static_cast(mIndexedParameters.size()); + for (UInt32 i = 0; i < nparams; i++ ) + *outList++ = (AudioUnitParameterID)i; + } + else + { + for (ParameterMap::iterator i = mParameters.begin(); i != mParameters.end(); ++i) + *outList++ = (*i).first; + } +} + +//_____________________________________________________________________________ +// +void AUElement::SaveState(CFMutableDataRef data) +{ + if(mUseIndexedParameters) + { + UInt32 nparams = static_cast(mIndexedParameters.size()); + UInt32 theData = CFSwapInt32HostToBig(nparams); + CFDataAppendBytes(data, (UInt8 *)&theData, sizeof(nparams)); + + for (UInt32 i = 0; i < nparams; i++) + { + struct { + UInt32 paramID; + //CFSwappedFloat32 value; crashes gcc3 PFE + UInt32 value; // really a big-endian float + } entry; + + entry.paramID = CFSwapInt32HostToBig(i); + + AudioUnitParameterValue v = mIndexedParameters[i].GetValue(); + entry.value = CFSwapInt32HostToBig(*(UInt32 *)&v ); + + CFDataAppendBytes(data, (UInt8 *)&entry, sizeof(entry)); + } + } + else + { + UInt32 nparams = CFSwapInt32HostToBig(static_cast(mParameters.size())); + CFDataAppendBytes(data, (UInt8 *)&nparams, sizeof(nparams)); + + for (ParameterMap::iterator i = mParameters.begin(); i != mParameters.end(); ++i) { + struct { + UInt32 paramID; + //CFSwappedFloat32 value; crashes gcc3 PFE + UInt32 value; // really a big-endian float + } entry; + + entry.paramID = CFSwapInt32HostToBig((*i).first); + + AudioUnitParameterValue v = (*i).second.GetValue(); + entry.value = CFSwapInt32HostToBig(*(UInt32 *)&v ); + + CFDataAppendBytes(data, (UInt8 *)&entry, sizeof(entry)); + } + } +} + +//_____________________________________________________________________________ +// +const UInt8 * AUElement::RestoreState(const UInt8 *state) +{ + union FloatInt32 { UInt32 i; AudioUnitParameterValue f; }; + const UInt8 *p = state; + UInt32 nparams = CFSwapInt32BigToHost(*(UInt32 *)p); + p += sizeof(UInt32); + + for (UInt32 i = 0; i < nparams; ++i) { + struct { + AudioUnitParameterID paramID; + AudioUnitParameterValue value; + } entry; + + entry.paramID = CFSwapInt32BigToHost(*(UInt32 *)p); + p += sizeof(UInt32); + FloatInt32 temp; + temp.i = CFSwapInt32BigToHost(*(UInt32 *)p); + entry.value = temp.f; + p += sizeof(AudioUnitParameterValue); + + SetParameter(entry.paramID, entry.value); + } + return p; +} + +//_____________________________________________________________________________ +// +void AUElement::SetName (CFStringRef inName) +{ + if (mElementName) CFRelease (mElementName); + mElementName = inName; + if (mElementName) CFRetain (mElementName); +} + + +//_____________________________________________________________________________ +// +AUIOElement::AUIOElement(AUBase *audioUnit) : + AUElement(audioUnit), + mWillAllocate (true) +{ + mStreamFormat.SetAUCanonical(2, // stereo + audioUnit->AudioUnitAPIVersion() == 1); + // interleaved if API version 1, deinterleaved if version 2 + mStreamFormat.mSampleRate = kAUDefaultSampleRate; +} + +//_____________________________________________________________________________ +// +OSStatus AUIOElement::SetStreamFormat(const CAStreamBasicDescription &desc) +{ + mStreamFormat = desc; + return AUBase::noErr; +} + +//_____________________________________________________________________________ +// inFramesToAllocate == 0 implies the AudioUnit's max-frames-per-slice will be used +void AUIOElement::AllocateBuffer(UInt32 inFramesToAllocate) +{ + if (GetAudioUnit()->HasBegunInitializing()) + { + UInt32 framesToAllocate = inFramesToAllocate > 0 ? inFramesToAllocate : GetAudioUnit()->GetMaxFramesPerSlice(); + +// printf ("will allocate: %d\n", (int)((mWillAllocate && NeedsBufferSpace()) ? framesToAllocate : 0)); + + mIOBuffer.Allocate(mStreamFormat, (mWillAllocate && NeedsBufferSpace()) ? framesToAllocate : 0); + } +} + +//_____________________________________________________________________________ +// +void AUIOElement::DeallocateBuffer() +{ + mIOBuffer.Deallocate(); +} + +//_____________________________________________________________________________ +// +// AudioChannelLayout support + +// outLayoutTagsPtr WILL be NULL if called to find out how many +// layouts that Audio Unit will report +// return 0 (ie. NO channel layouts) if the AU doesn't require channel layout knowledge +UInt32 AUIOElement::GetChannelLayoutTags (AudioChannelLayoutTag *outLayoutTagsPtr) +{ + return 0; +} + +// As the AudioChannelLayout can be a variable length structure +// (though in most cases it won't be!!!) +// The size of the ACL is always returned by the method +// if outMapPtr is NOT-NULL, then AU should copy into this pointer (outMapPtr) the current ACL that it has in use. +// the AU should also return whether the property is writable (that is the client can provide any arbitrary ACL that the audio unit will then honour) +// or if the property is read only - which is the generally preferred mode. +// If the AU doesn't require an AudioChannelLayout, then just return 0. +UInt32 AUIOElement::GetAudioChannelLayout (AudioChannelLayout *outMapPtr, + Boolean &outWritable) +{ + return 0; +} + +// the incoming channel map will be at least as big as a basic AudioChannelLayout +// but its contents will determine its actual size +// Subclass should overide if channel map is writable +OSStatus AUIOElement::SetAudioChannelLayout (const AudioChannelLayout &inData) +{ + return kAudioUnitErr_InvalidProperty; +} + +// Some units support optional usage of channel maps - typically converter units +// that can do channel remapping between different maps. In that optional case +// the user should be able to remove a channel map if that is possible. +// Typically this is NOT the case (e.g., the 3DMixer even in the stereo case +// needs to know if it is rendering to speakers or headphones) +OSStatus AUIOElement::RemoveAudioChannelLayout () +{ + return kAudioUnitErr_InvalidPropertyValue; +} + + +//_____________________________________________________________________________ +// +AUScope::~AUScope() +{ + for (ElementVector::iterator it = mElements.begin(); it != mElements.end(); ++it) + delete *it; +} + +//_____________________________________________________________________________ +// +void AUScope::SetNumberOfElements(UInt32 numElements) +{ + if (mDelegate) + return mDelegate->SetNumberOfElements(numElements); + + if (numElements > mElements.size()) { + mElements.reserve(numElements); + while (numElements > mElements.size()) { + AUElement *elem = mCreator->CreateElement(GetScope(), static_cast(mElements.size())); + mElements.push_back(elem); + } + } else + while (numElements < mElements.size()) { + AUElement *elem = mElements.back(); + mElements.pop_back(); + delete elem; + } +} + +//_____________________________________________________________________________ +// +bool AUScope::HasElementWithName () const +{ + for (UInt32 i = 0; i < GetNumberOfElements(); ++i) { + AUElement * el = const_cast(this)->GetElement (i); + if (el && el->HasName()) { + return true; + } + } + return false; +} + +//_____________________________________________________________________________ +// + +void AUScope::AddElementNamesToDict (CFMutableDictionaryRef & inNameDict) +{ + if (HasElementWithName()) + { + static char string[32]; + CFMutableDictionaryRef elementDict = CFDictionaryCreateMutable (NULL, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFStringRef str; + for (UInt32 i = 0; i < GetNumberOfElements(); ++i) { + AUElement * el = GetElement (i); + if (el && el->HasName()) { + snprintf (string, sizeof(string), "%d", int(i)); + str = CFStringCreateWithCString (NULL, string, kCFStringEncodingASCII); + CFDictionarySetValue (elementDict, str, el->GetName()); + CFRelease (str); + } + } + + snprintf (string, sizeof(string), "%d", int(mScope)); + str = CFStringCreateWithCString (NULL, string, kCFStringEncodingASCII); + CFDictionarySetValue (inNameDict, str, elementDict); + CFRelease (str); + CFRelease (elementDict); + } +} + +//_____________________________________________________________________________ +// +bool AUScope::RestoreElementNames (CFDictionaryRef& inNameDict) +{ + static char string[32]; + + //first we have to see if we have enough elements + bool didAddElements = false; + unsigned int maxElNum = GetNumberOfElements(); + + int dictSize = static_cast(CFDictionaryGetCount(inNameDict)); + CFStringRef * keys = (CFStringRef*)CA_malloc (dictSize * sizeof (CFStringRef)); + CFDictionaryGetKeysAndValues (inNameDict, reinterpret_cast(keys), NULL); + for (int i = 0; i < dictSize; i++) + { + unsigned int intKey = 0; + CFStringGetCString (keys[i], string, 32, kCFStringEncodingASCII); + int result = sscanf (string, "%u", &intKey); + // check if sscanf succeeded and element index is less than max elements. + if (result && UInt32(intKey) < maxElNum) + { + CFStringRef elName = reinterpret_cast(CFDictionaryGetValue (inNameDict, keys[i])); + AUElement* element = GetElement (intKey); + if (element) + element->SetName (elName); + } + } + free (keys); + + return didAddElements; +} + +void AUScope::SaveState(CFMutableDataRef data) +{ + AudioUnitElement nElems = GetNumberOfElements(); + for (AudioUnitElement ielem = 0; ielem < nElems; ++ielem) { + AUElement *element = GetElement(ielem); + UInt32 nparams = element->GetNumberOfParameters(); + if (nparams > 0) { + struct { + UInt32 scope; + UInt32 element; + } hdr; + + hdr.scope = CFSwapInt32HostToBig(GetScope()); + hdr.element = CFSwapInt32HostToBig(ielem); + CFDataAppendBytes(data, (UInt8 *)&hdr, sizeof(hdr)); + + element->SaveState(data); + } + } +} + +const UInt8 * AUScope::RestoreState(const UInt8 *state) +{ + const UInt8 *p = state; + UInt32 elementIdx = CFSwapInt32BigToHost(*(UInt32 *)p); p += sizeof(UInt32); + AUElement *element = GetElement(elementIdx); + if (!element) { + struct { + AudioUnitParameterID paramID; + AudioUnitParameterValue value; + } entry; + UInt32 nparams = CFSwapInt32BigToHost(*(UInt32 *)p); + p += sizeof(UInt32); + + p += nparams * sizeof(entry); + } else + p = element->RestoreState(p); + + return p; +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUScopeElement.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUScopeElement.h new file mode 100644 index 0000000000..7e37bfba62 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUScopeElement.h @@ -0,0 +1,553 @@ +/* + File: AUScopeElement.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUScopeElement_h__ +#define __AUScopeElement_h__ + +#include +#include + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif +#include "ComponentBase.h" +#include "AUBuffer.h" + + +class AUBase; + +// ____________________________________________________________________________ +// +// represents a parameter's value (either constant or ramped) +/*! @class ParameterMapEvent */ +class ParameterMapEvent +{ +public: +/*! @ctor ParameterMapEvent */ + ParameterMapEvent() + : mEventType(kParameterEvent_Immediate), mBufferOffset(0), mDurationInFrames(0), mValue1(0.0f), mValue2(0.0f), mSliceDurationFrames(0) + {} + +/*! @ctor ParameterMapEvent */ + ParameterMapEvent(AudioUnitParameterValue inValue) + : mEventType(kParameterEvent_Immediate), mBufferOffset(0), mDurationInFrames(0), mValue1(inValue), mValue2(inValue), mSliceDurationFrames(0) + {} + + // constructor for scheduled event +/*! @ctor ParameterMapEvent */ + ParameterMapEvent( const AudioUnitParameterEvent &inEvent, + UInt32 inSliceOffsetInBuffer, + UInt32 inSliceDurationFrames ) + { + SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames ); + }; + +/*! @method SetScheduledEvent */ + void SetScheduledEvent( const AudioUnitParameterEvent &inEvent, + UInt32 inSliceOffsetInBuffer, + UInt32 inSliceDurationFrames ) + { + mEventType = inEvent.eventType; + mSliceDurationFrames = inSliceDurationFrames; + + if(mEventType == kParameterEvent_Immediate ) + { + // constant immediate value for the whole slice + mValue1 = inEvent.eventValues.immediate.value; + mValue2 = mValue1; + mDurationInFrames = inSliceDurationFrames; + mBufferOffset = 0; + } + else + { + mDurationInFrames = inEvent.eventValues.ramp.durationInFrames; + mBufferOffset = inEvent.eventValues.ramp.startBufferOffset - inSliceOffsetInBuffer; // shift over for this slice + mValue1 = inEvent.eventValues.ramp.startValue; + mValue2 = inEvent.eventValues.ramp.endValue; + } + }; + + + +/*! @method GetEventType */ + AUParameterEventType GetEventType() const {return mEventType;}; + +/*! @method GetValue */ + AudioUnitParameterValue GetValue() const {return mValue1;}; // only valid if immediate event type +/*! @method GetEndValue */ + AudioUnitParameterValue GetEndValue() const {return mValue2;}; // only valid if immediate event type +/*! @method SetValue */ + void SetValue(AudioUnitParameterValue inValue) + { + mEventType = kParameterEvent_Immediate; + mValue1 = inValue; + mValue2 = inValue; + } + + // interpolates the start and end values corresponding to the current processing slice + // most ramp parameter implementations will want to use this method + // the start value will correspond to the start of the slice + // the end value will correspond to the end of the slice +/*! @method GetRampSliceStartEnd */ + void GetRampSliceStartEnd( AudioUnitParameterValue & outStartValue, + AudioUnitParameterValue & outEndValue, + AudioUnitParameterValue & outValuePerFrameDelta ) + { + if (mEventType == kParameterEvent_Ramped) { + outValuePerFrameDelta = (mValue2 - mValue1) / mDurationInFrames; + + outStartValue = mValue1 + outValuePerFrameDelta * (-mBufferOffset); // corresponds to frame 0 of this slice + outEndValue = outStartValue + outValuePerFrameDelta * mSliceDurationFrames; + } else { + outValuePerFrameDelta = 0; + outStartValue = outEndValue = mValue1; + } + }; + + // Some ramp parameter implementations will want to interpret the ramp using their + // own interpolation method (perhaps non-linear) + // This method gives the raw ramp information, relative to this processing slice + // for the client to interpret as desired +/*! @method GetRampInfo */ + void GetRampInfo( SInt32 & outBufferOffset, + UInt32 & outDurationInFrames, + AudioUnitParameterValue & outStartValue, + AudioUnitParameterValue & outEndValue ) + { + outBufferOffset = mBufferOffset; + outDurationInFrames = mDurationInFrames; + outStartValue = mValue1; + outEndValue = mValue2; + }; + +#if DEBUG + void Print() + { + printf("ParameterEvent @ %p\n", this); + printf(" mEventType = %d\n", (int)mEventType); + printf(" mBufferOffset = %d\n", (int)mBufferOffset); + printf(" mDurationInFrames = %d\n", (int)mDurationInFrames); + printf(" mSliceDurationFrames = %d\n", (int)mSliceDurationFrames); + printf(" mValue1 = %.5f\n", mValue1); + printf(" mValue2 = %.5f\n", mValue2); + } +#endif + +private: + AUParameterEventType mEventType; + + SInt32 mBufferOffset; // ramp start offset relative to start of this slice (may be negative) + UInt32 mDurationInFrames; // total duration of ramp parameter + AudioUnitParameterValue mValue1; // value if immediate : startValue if ramp + AudioUnitParameterValue mValue2; // endValue (only used for ramp) + + UInt32 mSliceDurationFrames; // duration of this processing slice +}; + + + +// ____________________________________________________________________________ +// +class AUIOElement; + +/*! @class AUElement */ +class AUElement { +public: +/*! @ctor AUElement */ + AUElement(AUBase *audioUnit) : mAudioUnit(audioUnit), + mUseIndexedParameters(false), mElementName(0) { } + +/*! @dtor ~AUElement */ + virtual ~AUElement() { if (mElementName) CFRelease (mElementName); } + +/*! @method GetNumberOfParameters */ + virtual UInt32 GetNumberOfParameters() + { + if(mUseIndexedParameters) return static_cast(mIndexedParameters.size()); else return static_cast(mParameters.size()); + } +/*! @method GetParameterList */ + virtual void GetParameterList(AudioUnitParameterID *outList); +/*! @method HasParameterID */ + bool HasParameterID (AudioUnitParameterID paramID) const; + +/*! @method GetParameter */ + AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID); +/*! @method SetParameter */ + void SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue value, bool okWhenInitialized = false); + // Only set okWhenInitialized to true when you know the outside world cannot access this element. Otherwise the parameter map could get corrupted. + + // interpolates the start and end values corresponding to the current processing slice + // most ramp parameter implementations will want to use this method +/*! @method GetRampSliceStartEnd */ + void GetRampSliceStartEnd( AudioUnitParameterID paramID, + AudioUnitParameterValue & outStartValue, + AudioUnitParameterValue & outEndValue, + AudioUnitParameterValue & outValuePerFrameDelta ); + +/*! @method GetEndValue */ + AudioUnitParameterValue GetEndValue( AudioUnitParameterID paramID); + +/*! @method SetRampParameter */ + void SetScheduledEvent( AudioUnitParameterID paramID, + const AudioUnitParameterEvent &inEvent, + UInt32 inSliceOffsetInBuffer, + UInt32 inSliceDurationFrames, + bool okWhenInitialized = false ); + // Only set okWhenInitialized to true when you know the outside world cannot access this element. Otherwise the parameter map could get corrupted. + + +/*! @method GetAudioUnit */ + AUBase * GetAudioUnit() const { return mAudioUnit; }; + +/*! @method SaveState */ + void SaveState(CFMutableDataRef data); +/*! @method RestoreState */ + const UInt8 * RestoreState(const UInt8 *state); +/*! @method GetName */ + CFStringRef GetName () const { return mElementName; } +/*! @method SetName */ + void SetName (CFStringRef inName); +/*! @method HasName */ + bool HasName () const { return mElementName != 0; } +/*! @method UseIndexedParameters */ + virtual void UseIndexedParameters(int inNumberOfParameters); + +/*! @method AsIOElement*/ + virtual AUIOElement* AsIOElement () { return NULL; } + +protected: + inline ParameterMapEvent& GetParamEvent(AudioUnitParameterID paramID); + +private: + typedef std::map > ParameterMap; + +/*! @var mAudioUnit */ + AUBase * mAudioUnit; +/*! @var mParameters */ + ParameterMap mParameters; + +/*! @var mUseIndexedParameters */ + bool mUseIndexedParameters; +/*! @var mIndexedParameters */ + std::vector mIndexedParameters; + +/*! @var mElementName */ + CFStringRef mElementName; +}; + + + +// ____________________________________________________________________________ +// +/*! @class AUIOElement */ +class AUIOElement : public AUElement { +public: +/*! @ctor AUIOElement */ + AUIOElement(AUBase *audioUnit); + +/*! @method GetStreamFormat */ + const CAStreamBasicDescription &GetStreamFormat() const { return mStreamFormat; } + +/*! @method SetStreamFormat */ + virtual OSStatus SetStreamFormat(const CAStreamBasicDescription &desc); + +/*! @method AllocateBuffer */ + virtual void AllocateBuffer(UInt32 inFramesToAllocate = 0); +/*! @method DeallocateBuffer */ + void DeallocateBuffer(); +/*! @method NeedsBufferSpace */ + virtual bool NeedsBufferSpace() const = 0; + +/*! @method SetWillAllocateBuffer */ + void SetWillAllocateBuffer(bool inFlag) { + mWillAllocate = inFlag; + } +/*! @method WillAllocateBuffer */ + bool WillAllocateBuffer() const { + return mWillAllocate; + } + +/*! @method UseExternalBuffer */ + void UseExternalBuffer(const AudioUnitExternalBuffer &buf) { + mIOBuffer.UseExternalBuffer(mStreamFormat, buf); + } +/*! @method PrepareBuffer */ + AudioBufferList & PrepareBuffer(UInt32 nFrames) { + if (mWillAllocate) + return mIOBuffer.PrepareBuffer(mStreamFormat, nFrames); + throw OSStatus(kAudioUnitErr_InvalidPropertyValue); + } +/*! @method PrepareNullBuffer */ + AudioBufferList & PrepareNullBuffer(UInt32 nFrames) { + return mIOBuffer.PrepareNullBuffer(mStreamFormat, nFrames); + } +/*! @method SetBufferList */ + AudioBufferList & SetBufferList(AudioBufferList &abl) { return mIOBuffer.SetBufferList(abl); } +/*! @method SetBuffer */ + void SetBuffer(UInt32 index, AudioBuffer &ab) { mIOBuffer.SetBuffer(index, ab); } +/*! @method InvalidateBufferList */ + void InvalidateBufferList() { mIOBuffer.InvalidateBufferList(); } + +/*! @method GetBufferList */ + AudioBufferList & GetBufferList() const { return mIOBuffer.GetBufferList(); } + +/*! @method GetChannelData */ + AudioUnitSampleType * GetChannelData(int ch) const { + if (mStreamFormat.IsInterleaved()) + return static_cast(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch; + else + return static_cast(mIOBuffer.GetBufferList().mBuffers[ch].mData); + } + Float32 * GetFloat32ChannelData(int ch) const { + if (mStreamFormat.IsInterleaved()) + return static_cast(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch; + else + return static_cast(mIOBuffer.GetBufferList().mBuffers[ch].mData); + } + SInt32 * GetSInt32ChannelData(int ch) const { + if (mStreamFormat.IsInterleaved()) + return static_cast(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch; + else + return static_cast(mIOBuffer.GetBufferList().mBuffers[ch].mData); + } + SInt16 * GetInt16ChannelData(int ch) const { + if (mStreamFormat.IsInterleaved()) + return static_cast(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch; + else + return static_cast(mIOBuffer.GetBufferList().mBuffers[ch].mData); + } + +/*! @method CopyBufferListTo */ + void CopyBufferListTo(AudioBufferList &abl) const { + mIOBuffer.CopyBufferListTo(abl); + } +/*! @method CopyBufferContentsTo */ + void CopyBufferContentsTo(AudioBufferList &abl) const { + mIOBuffer.CopyBufferContentsTo(abl); + } + +/* UInt32 BytesToFrames(UInt32 nBytes) { return nBytes / mStreamFormat.mBytesPerFrame; } + UInt32 BytesToFrames(AudioBufferList &abl) { + return BytesToFrames(abl.mBuffers[0].mDataByteSize); + } + UInt32 FramesToBytes(UInt32 nFrames) { return nFrames * mStreamFormat.mBytesPerFrame; }*/ + +/*! @method IsInterleaved */ + bool IsInterleaved() const { return mStreamFormat.IsInterleaved(); } +/*! @method NumberChannels */ + UInt32 NumberChannels() const { return mStreamFormat.NumberChannels(); } +/*! @method NumberInterleavedChannels */ + UInt32 NumberInterleavedChannels() const { return mStreamFormat.NumberInterleavedChannels(); } + +/*! @method GetChannelMapTags */ + virtual UInt32 GetChannelLayoutTags (AudioChannelLayoutTag *outLayoutTagsPtr); + +/*! @method GetAudioChannelLayout */ + virtual UInt32 GetAudioChannelLayout (AudioChannelLayout *outMapPtr, Boolean &outWritable); + +/*! @method SetAudioChannelLayout */ + virtual OSStatus SetAudioChannelLayout (const AudioChannelLayout &inData); + +/*! @method RemoveAudioChannelLayout */ + virtual OSStatus RemoveAudioChannelLayout (); + +/*! @method AsIOElement*/ + virtual AUIOElement* AsIOElement () { return this; } + +protected: +/*! @var mStreamFormat */ + CAStreamBasicDescription mStreamFormat; +/*! @var mIOBuffer */ + AUBufferList mIOBuffer; // for input: input proc buffer, only allocated when needed + // for output: output cache, usually allocated early on +/*! @var mWillAllocate */ + bool mWillAllocate; +}; + +// ____________________________________________________________________________ +// +// AUScopeDelegates are a way to get virtual scopes. +/*! @class AUScopeDelegate */ +class AUScopeDelegate { +public: +/*! @ctor AUScopeDelegate */ + AUScopeDelegate() : mCreator(NULL), mScope(0) { } +/*! @dtor ~AUScopeDelegate */ + virtual ~AUScopeDelegate() {} + +/*! @method Initialize */ + void Initialize( AUBase *creator, + AudioUnitScope scope, + UInt32 numElements) + { + mCreator = creator; + mScope = scope; + SetNumberOfElements(numElements); + } + +/*! @method SetNumberOfElements */ + virtual void SetNumberOfElements(UInt32 numElements) = 0; + +/*! @method GetNumberOfElements */ + virtual UInt32 GetNumberOfElements() = 0; + +/*! @method GetElement */ + virtual AUElement * GetElement(UInt32 elementIndex) = 0; + + AUBase * GetCreator() const { return mCreator; } + AudioUnitScope GetScope() const { return mScope; } + + +private: +/*! @var mCreator */ + AUBase * mCreator; +/*! @var mScope */ + AudioUnitScope mScope; +}; + + + +// ____________________________________________________________________________ +// +/*! @class AUScope */ +class AUScope { +public: +/*! @ctor AUScope */ + AUScope() : mCreator(NULL), mScope(0), mDelegate(0) { } +/*! @dtor ~AUScope */ + ~AUScope(); + +/*! @method Initialize */ + void Initialize(AUBase *creator, + AudioUnitScope scope, + UInt32 numElements) + { + mCreator = creator; + mScope = scope; + + if (mDelegate) + return mDelegate->Initialize(creator, scope, numElements); + + SetNumberOfElements(numElements); + } + +/*! @method SetNumberOfElements */ + void SetNumberOfElements(UInt32 numElements); + +/*! @method GetNumberOfElements */ + UInt32 GetNumberOfElements() const + { + if (mDelegate) + return mDelegate->GetNumberOfElements(); + + return static_cast(mElements.size()); + } + +/*! @method GetElement */ + AUElement * GetElement(UInt32 elementIndex) const + { + if (mDelegate) + return mDelegate->GetElement(elementIndex); + + ElementVector::const_iterator i = mElements.begin() + elementIndex; + // catch passing -1 in as the elementIndex - causes a wrap around + return (i >= mElements.end() || i < mElements.begin()) ? NULL : *i; + } + +/*! @method SafeGetElement */ + AUElement * SafeGetElement(UInt32 elementIndex) + { + AUElement *element = GetElement(elementIndex); + if (element == NULL) + COMPONENT_THROW(kAudioUnitErr_InvalidElement); + return element; + } + +/*! @method GetIOElement */ + AUIOElement * GetIOElement(UInt32 elementIndex) const + { + AUElement *element = GetElement(elementIndex); + AUIOElement *ioel = element ? element->AsIOElement () : NULL; + if (!ioel) + COMPONENT_THROW (kAudioUnitErr_InvalidElement); + return ioel; + } + +/*! @method HasElementWithName */ + bool HasElementWithName () const; + +/*! @method AddElementNamesToDict */ + void AddElementNamesToDict (CFMutableDictionaryRef & inNameDict); + + bool RestoreElementNames (CFDictionaryRef& inNameDict); + + AudioUnitScope GetScope() const { return mScope; } + + void SetDelegate(AUScopeDelegate* inDelegate) { mDelegate = inDelegate; } + +/*! @method SaveState */ + void SaveState(CFMutableDataRef data); + +/*! @method RestoreState */ + const UInt8 * RestoreState(const UInt8 *state); + +private: + typedef std::vector ElementVector; +/*! @var mCreator */ + AUBase * mCreator; +/*! @var mScope */ + AudioUnitScope mScope; +/*! @var mElements */ + ElementVector mElements; +/*! @var mDelegate */ + AUScopeDelegate * mDelegate; +}; + + + +#endif // __AUScopeElement_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUSilentTimeout.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUSilentTimeout.h new file mode 100644 index 0000000000..7e5a65eed6 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUSilentTimeout.h @@ -0,0 +1,93 @@ +/* + File: AUSilentTimeout.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUSilentTimeout +#define __AUSilentTimeout + +class AUSilentTimeout +{ +public: + AUSilentTimeout() + : mTimeoutCounter(0), + mResetTimer(true) + {}; + + void Process(UInt32 inFramesToProcess, UInt32 inTimeoutLimit, bool &ioSilence ) + { + if(ioSilence ) + { + if(mResetTimer ) + { + mTimeoutCounter = inTimeoutLimit; + mResetTimer = false; + } + + if(mTimeoutCounter > 0 ) + { + mTimeoutCounter -= inFramesToProcess; + ioSilence = false; + } + } + else + { + // signal to reset the next time we receive silence + mResetTimer = true; + } + } + + void Reset() + { + mResetTimer = true; + }; + + + +private: + SInt32 mTimeoutCounter; + bool mResetTimer; +}; + +#endif // __AUSilentTimeout diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUTimestampGenerator.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUTimestampGenerator.h new file mode 100644 index 0000000000..6e27f74b74 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUTimestampGenerator.h @@ -0,0 +1,163 @@ +/* + File: AUTimestampGenerator.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUTimestampGenerator_h__ +#define __AUTimestampGenerator_h__ + +#include +#include "CAHostTimeBase.h" +#include + +#define TSGFMT "0x%10qx" +//#define TSGFMT "%10qd" + +// This class generates a continuously increasing series of timestamps based +// on a series of potentially discontinuous timestamps (as can be delivered from +// CoreAudio in the event of an overload or major engine change). +// N.B.: "output" = downstream (source) timestamp +// "input" = upstream (derived) timestamp +class AUTimestampGenerator { +public: + AUTimestampGenerator(bool hostTimeDiscontinuityCorrection = false) + { + mState.mStartInputAtZero = true; + mState.mBypassed = false; + mState.mHostTimeDiscontinuityCorrection = hostTimeDiscontinuityCorrection; +#if DEBUG + mVerbosity = 0; + snprintf(mDebugName, sizeof(mDebugName), "tsg @ %p", this); +#endif + // CAHostTimeBase should be used instead of the calls in + // we make this call here to ensure that this is initialized, otherwise the first time + // you do actually call CAHostTimeBase to do work, can be on the render thread, and lead to unwanted VM faults + CAHostTimeBase::GetFrequency(); + Reset(); + } + + void SetStartInputAtZero(bool b) { mState.mStartInputAtZero = b; } + bool GetStartInputAtZero() const { return mState.mStartInputAtZero; } + + // bypassing is intended for a narrow special case. the upstream sample time will always be the same as the downstream time. + void SetBypassed(bool b) { mState.mBypassed = b; } + bool GetBypassed() const { return mState.mBypassed; } + + // Call this to reset the timeline. + void Reset() + { + mState.mCurrentInputTime.mSampleTime = 0.; + mState.mNextInputSampleTime = 0.; + mState.mCurrentOutputTime.mSampleTime = 0.; + mState.mNextOutputSampleTime = 0.; + mState.mLastOutputTime.mFlags = 0; + mState.mRateScalarAdj = 1.; + + mFirstTime = true; +#if DEBUG + if (mVerbosity) + printf("%-20.20s: Reset\n", mDebugName); +#endif + } + + // Call this once per render cycle with the downstream timestamp. + // expectedDeltaFrames is the expected difference between the current and NEXT + // downstream timestamps. + // sampleRate is the OUTPUT sample rate. + void AddOutputTime(const AudioTimeStamp &inTimeStamp, Float64 expectedDeltaFrames, double outputSampleRate, double rateScalarAdj=1.0); + + // Call this once per render cycle to obtain the upstream timestamp. + // framesToAdvance is the number of frames the input timeline is to be + // advanced during this render cycle. + // sampleRate is the INPUT sample rate. + const AudioTimeStamp & GenerateInputTime(Float64 framesToAdvance, double inputSampleRate, bool advanceHostTime = false); + + // this can be called to override the setting of the next input sample time in GenerateInputTime + void Advance(Float64 framesToAdvance) + { +#if DEBUG + if (mVerbosity > 1) + printf("%-20.20s: ADVANCE in = " TSGFMT " advance = " TSGFMT "\n", mDebugName, (SInt64)mState.mCurrentInputTime.mSampleTime, (SInt64)framesToAdvance); +#endif + mState.mNextInputSampleTime = mState.mCurrentInputTime.mSampleTime + framesToAdvance; + } + + struct State { + AudioTimeStamp mCurrentInputTime; + Float64 mNextInputSampleTime; + Float64 mNextOutputSampleTime; + Float64 mInputSampleTimeForOutputPull; + + AudioTimeStamp mLastOutputTime; + AudioTimeStamp mCurrentOutputTime; + + bool mStartInputAtZero; // if true, input timeline starts at 0, else it starts + // synced with the output timeline + bool mDiscontinuous; + bool mBypassed; + Float64 mDiscontinuityDeltaSamples; + + double mRateScalarAdj; + + bool mHostTimeDiscontinuityCorrection; // If true, propagate timestamp discontinuities using host time. + }; + + void GetState(State& outState) const { outState = mState; } + void SetState(State const& inState) { mState = inState; mFirstTime = false; } + +private: + + struct State mState; + + bool mFirstTime; + +#if DEBUG +public: + int mVerbosity; + char mDebugName[64]; +#endif +}; + + +#endif // __AUTimestampGenerator_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUViewLocalizedStringKeys.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUViewLocalizedStringKeys.h new file mode 100644 index 0000000000..7f40021333 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUViewLocalizedStringKeys.h @@ -0,0 +1,88 @@ +/* + File: AUViewLocalizedStringKeys.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AUViewLocalizedStringKeys_h__ +#define __AUViewLocalizedStringKeys_h__ + +// ACCESS POINT: +#define kLocalizedStringBundle_AUView CFSTR("com.apple.audio.units.Components") +#define kLocalizedStringTable_AUView CFSTR("CustomUI") + +// UNLOCALIZED STRINGS: + #define kAUViewUnlocalizedString_TitleSeparator CFSTR(": ") + +// Generic View: + #define kAUViewLocalizedStringKey_AudioUnit CFSTR("Audio Unit") + #define kAUViewLocalizedStringKey_Manufacturer CFSTR("Manufacturer") + + #define kAUViewLocalizedStringKey_FactoryPreset CFSTR("Factory Preset") + + #define kAUViewLocalizedStringKey_Properties CFSTR("Properties") + #define kAUViewLocalizedStringKey_Parameters CFSTR("Parameters") + + #define kAUViewLocalizedStringKey_Standard CFSTR("Standard") + #define kAUViewLocalizedStringKey_Expert CFSTR("Expert") + +// AULoadCPU: + #define kAUViewLocalizedStringKey_RestrictCPULoad CFSTR("Restrict CPU Load") + #define kAUViewLocalizedStringKey_PercentSymbol CFSTR("%") + #define kAUViewLocalizedStringKey_NotApplicable CFSTR("n/a") + +// AUDiskStreamingCheckbox: + #define kAUViewLocalizedStringKey_StreamFromDisk CFSTR("Stream From Disk") + +// AURenderQualityPopup: + #define kAUViewLocalizedStringKey_RenderQuality CFSTR("Render Quality") + #define kAUViewLocalizedStringKey_Maximum CFSTR("Maximum") + #define kAUViewLocalizedStringKey_High CFSTR("High") + #define kAUViewLocalizedStringKey_Medium CFSTR("Medium") + #define kAUViewLocalizedStringKey_Low CFSTR("Low") + #define kAUViewLocalizedStringKey_Minimum CFSTR("Minimum") + +// AUChannelLayoutPopUp: + #define kAUViewLocalizedStringKey_AudioChannelLayout CFSTR("Audio Channel Layout") + +#endif //__AUViewLocalizedStringKeys_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAUParameter.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAUParameter.cpp new file mode 100644 index 0000000000..481a468ce5 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAUParameter.cpp @@ -0,0 +1,400 @@ +/* + File: CAAUParameter.cpp + Abstract: CAAUParameter.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "CAAUParameter.h" + +CAAUParameter::CAAUParameter() +{ + memset(this, 0, sizeof(CAAUParameter)); +} + +CAAUParameter::CAAUParameter(AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element) +{ + memset(this, 0, sizeof(CAAUParameter)); + Init (au, param, scope, element); +} + +CAAUParameter::CAAUParameter (AudioUnitParameter &inParam) +{ + memset(this, 0, sizeof(CAAUParameter)); + Init (inParam.mAudioUnit, inParam.mParameterID, inParam.mScope, inParam.mElement); +} + +CAAUParameter::CAAUParameter(const CAAUParameter &a) +{ + memset(this, 0, sizeof(CAAUParameter)); + *this = a; +} + +CAAUParameter & CAAUParameter::operator = (const CAAUParameter &a) +{ + if (mParamName) CFRelease(mParamName); + if (mParamTag) CFRelease(mParamTag); + if (mNamedParams) CFRelease(mNamedParams); + + memcpy(this, &a, sizeof(CAAUParameter)); + + if (mParamName) CFRetain(mParamName); + if (mParamTag) CFRetain(mParamTag); + if (mNamedParams) CFRetain(mNamedParams); + + return *this; +} + +CAAUParameter::~CAAUParameter() +{ + if (mParamName) CFRelease(mParamName); + if (mParamTag) CFRelease(mParamTag); + if (mNamedParams) CFRelease (mNamedParams); +} + +void CAAUParameter::Init (AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element) +{ + mAudioUnit = au; + mParameterID = param; + mScope = scope; + mElement = element; + + UInt32 propertySize = sizeof(mParamInfo); + OSStatus err = AudioUnitGetProperty(au, kAudioUnitProperty_ParameterInfo, + scope, param, &mParamInfo, &propertySize); + if (err) + memset(&mParamInfo, 0, sizeof(mParamInfo)); + if (mParamInfo.flags & kAudioUnitParameterFlag_HasCFNameString) { + mParamName = mParamInfo.cfNameString; + if (!(mParamInfo.flags & kAudioUnitParameterFlag_CFNameRelease)) + CFRetain (mParamName); + } else + mParamName = CFStringCreateWithCString(NULL, mParamInfo.name, kCFStringEncodingUTF8); + + const char* str = 0; + switch (mParamInfo.unit) + { + case kAudioUnitParameterUnit_Boolean: + str = "T/F"; + break; + case kAudioUnitParameterUnit_Percent: + case kAudioUnitParameterUnit_EqualPowerCrossfade: + str = "%"; + break; + case kAudioUnitParameterUnit_Seconds: + str = "Secs"; + break; + case kAudioUnitParameterUnit_SampleFrames: + str = "Samps"; + break; + case kAudioUnitParameterUnit_Phase: + case kAudioUnitParameterUnit_Degrees: + str = "Degr."; + break; + case kAudioUnitParameterUnit_Hertz: + str = "Hz"; + break; + case kAudioUnitParameterUnit_Cents: + case kAudioUnitParameterUnit_AbsoluteCents: + str = "Cents"; + break; + case kAudioUnitParameterUnit_RelativeSemiTones: + str = "S-T"; + break; + case kAudioUnitParameterUnit_MIDINoteNumber: + case kAudioUnitParameterUnit_MIDIController: + str = "MIDI"; + //these are inclusive, so add one value here + mNumIndexedParams = short(mParamInfo.maxValue+1 - mParamInfo.minValue); + break; + case kAudioUnitParameterUnit_Decibels: + str = "dB"; + break; + case kAudioUnitParameterUnit_MixerFaderCurve1: + case kAudioUnitParameterUnit_LinearGain: + str = "Gain"; + break; + case kAudioUnitParameterUnit_Pan: + str = "L/R"; + break; + case kAudioUnitParameterUnit_Meters: + str = "Mtrs"; + break; + case kAudioUnitParameterUnit_Octaves: + str = "8ve"; + break; + case kAudioUnitParameterUnit_BPM: + str = "BPM"; + break; + case kAudioUnitParameterUnit_Beats: + str = "Beats"; + break; + case kAudioUnitParameterUnit_Milliseconds: + str = "msecs"; + break; + case kAudioUnitParameterUnit_Ratio: + str = "Ratio"; + break; + case kAudioUnitParameterUnit_Indexed: + { + propertySize = sizeof(mNamedParams); + err = AudioUnitGetProperty (au, + kAudioUnitProperty_ParameterValueStrings, + scope, + param, + &mNamedParams, + &propertySize); + if (!err && mNamedParams) { + mNumIndexedParams = CFArrayGetCount(mNamedParams); + } else { + //these are inclusive, so add one value here + mNumIndexedParams = short(mParamInfo.maxValue+1 - mParamInfo.minValue); + } + str = NULL; + } + break; + case kAudioUnitParameterUnit_CustomUnit: + { + CFStringRef unitName = mParamInfo.unitName; + static char paramStr[256]; + CFStringGetCString (unitName, paramStr, 256, kCFStringEncodingUTF8); + if (mParamInfo.flags & kAudioUnitParameterFlag_CFNameRelease) + CFRelease (unitName); + str = paramStr; + break; + } + case kAudioUnitParameterUnit_Generic: + case kAudioUnitParameterUnit_Rate: + default: + str = NULL; + break; + } + + if (str) + mParamTag = CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8); + else + mParamTag = NULL; +} + + +Float32 CAAUParameter::GetValue() const +{ + Float32 value = 0.; + //OSStatus err = + AudioUnitGetParameter(mAudioUnit, mParameterID, mScope, mElement, &value); + return value; +} + +CFStringRef CreateLocalizedStringForParameterValue ( double inParameterValue, + const CAAUParameter * inParameter, + UInt32 inDigits, + UInt32 minDigits) { + if (!inParameter) return nil; + + AudioUnitParameterInfo info = inParameter->ParamInfo(); + int pow10; + + switch (info.unit) { + case kAudioUnitParameterUnit_Hertz: + // number of significant digits based on value + pow10 = int(log10(fmax(inParameterValue, .000001))); + break; + default: + // number of significant digits based on parameter range + pow10 = int(log10(fmax(double(info.maxValue - info.minValue), .000001))); + break; + } + + // pow10 range nDigitsAfterDecimal + // -2 .0100-.0999 4 + // -1 .100-.999 3 + // 0 1.00-9.99 2 + // 1 10.0-99.9 1 + // 2 100-999 0 + // 3 1000-9990 -1 + // 4 10000-99900 -2 + + int nDigitsAfterDecimal = inDigits - (pow10 + 1); + if (nDigitsAfterDecimal < 0) + nDigitsAfterDecimal = 0; // the least number of digits possible is zero + + if (info.flags & kAudioUnitParameterFlag_IsHighResolution) + nDigitsAfterDecimal = 4; + + CFLocaleRef currentLocale = CFLocaleCopyCurrent(); + CFNumberFormatterRef numberFormatter = CFNumberFormatterCreate (NULL, currentLocale, kCFNumberFormatterDecimalStyle); + + CFNumberRef maxFractionDigits = CFNumberCreate (NULL, kCFNumberIntType, &nDigitsAfterDecimal); + + if (nDigitsAfterDecimal > 0) + nDigitsAfterDecimal = minDigits; + + CFNumberRef minFractionDigits = CFNumberCreate (NULL, kCFNumberIntType, &nDigitsAfterDecimal); + + CFNumberFormatterSetProperty (numberFormatter, kCFNumberFormatterMinFractionDigits, minFractionDigits); + CFNumberFormatterSetProperty (numberFormatter, kCFNumberFormatterMaxFractionDigits, maxFractionDigits); + CFStringRef formattedNumberString = CFNumberFormatterCreateStringWithValue (NULL, numberFormatter, kCFNumberDoubleType, &inParameterValue); + + CFRelease(currentLocale); + CFRelease(numberFormatter); + CFRelease(maxFractionDigits); + CFRelease(minFractionDigits); + + return formattedNumberString; +} + +CFStringRef CreateLocalizedStringForParameterValue ( double inParameterValue, + const CAAUParameter * inParameter, + UInt32 inDigits) { + return CreateLocalizedStringForParameterValue (inParameterValue, inParameter, inDigits, 1); +} + +double ValueForLocalizedParameterString (CFStringRef string, const CAAUParameter * inParameter) { + CFLocaleRef currentLocale = CFLocaleCopyCurrent(); + CFNumberFormatterRef numberFormatter = CFNumberFormatterCreate (NULL, currentLocale, kCFNumberFormatterDecimalStyle); + + double value = 0; + Boolean worked = CFNumberFormatterGetValueFromString (numberFormatter, string, NULL, kCFNumberDoubleType, &value); + + CFRelease(currentLocale); + CFRelease(numberFormatter); + + if (worked) + return value; + else { + AudioUnitParameterInfo info = inParameter->ParamInfo(); + return info.defaultValue; + } +} + +CFStringRef CAAUParameter::GetStringFromValueCopy(const Float32 *value) const +{ + if (HasNamedParams()) + { + Float32 val = (value == NULL ? GetValue() : *value); + int index = int(mParamInfo.minValue) + int(val); + CFStringRef str = GetParamName (index); + if (str) { + CFRetain (str); + return str; + } + } + else if (ValuesHaveStrings()) + { + AudioUnitParameterStringFromValue stringValue; + stringValue.inParamID = mParameterID; + stringValue.inValue = value; + stringValue.outString = NULL; + UInt32 propertySize = sizeof(stringValue); + + OSStatus err = AudioUnitGetProperty (mAudioUnit, + kAudioUnitProperty_ParameterStringFromValue, + mScope, + 0, + &stringValue, + &propertySize); + + if (!err && stringValue.outString != NULL) + return stringValue.outString; + } + + Float32 val = (value == NULL ? GetValue() : *value); + AudioUnitParameterUnit unit = this->ParamInfo().unit; + if (unit == kAudioUnitParameterUnit_Cents || unit == kAudioUnitParameterUnit_AbsoluteCents) + return CreateLocalizedStringForParameterValue(val, this, 4, 0); + else + return CreateLocalizedStringForParameterValue(val, this, 4); +} + +Float32 CAAUParameter::GetValueFromString(CFStringRef str) const +{ + if (ValuesHaveStrings()) + { + AudioUnitParameterValueFromString valueString; + valueString.inParamID = mParameterID; + valueString.inString = str; + UInt32 propertySize = sizeof(valueString); + + OSStatus err = AudioUnitGetProperty (mAudioUnit, + kAudioUnitProperty_ParameterValueFromString, + mScope, + 0, + &valueString, + &propertySize); + + if (!err) { + return valueString.outValue; + } + } + + return (Float32) ValueForLocalizedParameterString(str, this); +} + +void CAAUParameter::SetValue( AUParameterListenerRef inListener, + void * inObject, + Float32 inValue) const +{ + // clip inValue as: maxValue >= inValue >= minValue before setting + Float32 valueToSet = inValue; + if (valueToSet > mParamInfo.maxValue) + valueToSet = mParamInfo.maxValue; + if (valueToSet < mParamInfo.minValue) + valueToSet = mParamInfo.minValue; + + AUParameterSet(inListener, inObject, this, valueToSet, 0); +} + +#if DEBUG +void CAAUParameter::Print() const +{ + UInt32 clump = 0; + GetClumpID (clump); + + UInt32 len = static_cast(CFStringGetLength(mParamName)); + char* chars = (char*)malloc (len * 2); // give us plenty of room for unichar chars + if (!CFStringGetCString (mParamName, chars, len * 2, kCFStringEncodingUTF8)) + chars[0] = 0; + + printf ("ID: %ld, Clump: %u, Name: %s\n", (long unsigned int) mParameterID, (unsigned int) clump, chars); + free (chars); +} +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAUParameter.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAUParameter.h new file mode 100644 index 0000000000..f51b392403 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAUParameter.h @@ -0,0 +1,191 @@ +/* + File: CAAUParameter.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAAUParameter_h__ +#define __CAAUParameter_h__ + +#include + +// ____________________________________________________________________________ +// CAAUParameter +// complete parameter specification + /*! @class CAAUParameter */ +class CAAUParameter : public AudioUnitParameter { +public: + /*! @ctor CAAUParameter.0 */ + CAAUParameter(); + /*! @ctor CAAUParameter.1 */ + CAAUParameter(AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element); + /*! @ctor CAAUParameter.2 */ + CAAUParameter(AudioUnitParameter &inParam); + /*! @ctor CAAUParameter.3 */ + CAAUParameter(const CAAUParameter &a); + /*! @dtor ~CAAUParameter */ + ~CAAUParameter(); + + /*! @method operator <@ */ + bool operator < (const CAAUParameter &a) const + { + return memcmp(this, &a, sizeof(AudioUnitParameter)) < 0; + } + + /*! @method operator ==@ */ + bool operator == (const CAAUParameter &a) const + { + return !memcmp(this, &a, sizeof(AudioUnitParameter)); + } + + /*! @method operator =@ */ + CAAUParameter & operator = (const CAAUParameter &a); + + /*! @method GetValue */ + Float32 GetValue() const; + /*! @method SetValue */ + void SetValue( AUParameterListenerRef inListener, + void * inObject, + Float32 inValue) const; + + /*! @method GetName */ + CFStringRef GetName() const { return mParamName; } + // borrowed reference! + + /*! @method GetStringFromValueCopy */ + CFStringRef GetStringFromValueCopy(const Float32 *value = NULL) const; + // returns a copy of the name of the current parameter value + // or null if there is no name associated + // caller must release + /*! @method ValuesHaveStrings */ + bool ValuesHaveStrings () const + { + return (mParamInfo.flags & kAudioUnitParameterFlag_ValuesHaveStrings) != 0; + } + + /*! @method GetValueFromString */ + Float32 GetValueFromString (CFStringRef str) const; + // caller must release + + /*! @method ParamInfo */ + const AudioUnitParameterInfo & + ParamInfo() const { return mParamInfo; } + + /*! @method GetParamTag */ + CFStringRef GetParamTag() const { return mParamTag; } + // this may return null! - + // in which case there is no descriptive tag for the parameter + + /*! @method GetParamName */ + CFStringRef GetParamName (int inIndex) const + // this can return null if there is no name for the parameter + { + return (mNamedParams && inIndex < mNumIndexedParams) + ? (CFStringRef) CFArrayGetValueAtIndex(mNamedParams, inIndex) + : 0; + } + + /*! @method GetNumIndexedParams */ + int GetNumIndexedParams () const { return mNumIndexedParams; } + + /*! @method IsIndexedParam */ + bool IsIndexedParam () const { return mNumIndexedParams != 0; } + + /*! @method HasNamedParams */ + bool HasNamedParams () const { return IsIndexedParam() && mNamedParams; } + + /*! @method GetClumpID */ + bool GetClumpID (UInt32 &outClumpID) const + { + if (mParamInfo.flags & kAudioUnitParameterFlag_HasClump) { + outClumpID = mParamInfo.clumpID; + return true; + } + return false; + } + + /*! @method HasDisplayTransformation */ + bool HasDisplayTransformation () const + { + return GetAudioUnitParameterDisplayType (mParamInfo.flags); + } + + /*! @method IsExpert */ + bool IsExpert () const + { + return mParamInfo.flags & kAudioUnitParameterFlag_ExpertMode; + } +#if DEBUG + void Print () const; +#endif + + // these methods are defined in CAPersistence.cpp + // they will persist and restore only the scope, element and param ID's of the AudioUnitParameter + // however, this is sufficient to be able to save/restore a CAAUParameter object + void Save (CFPropertyListRef &outData) const; + + static void Save (const AudioUnitParameter &inParam, CFPropertyListRef &outData); + + static OSStatus Restore (const CFPropertyListRef inData, AudioUnitParameter &outParam); + +protected: + // cached parameter info + /*! @var mParamInfo */ + AudioUnitParameterInfo mParamInfo; + /*! @var mParamName */ + CFStringRef mParamName; + /*! @var mParamTag */ + CFStringRef mParamTag; + /*! @var mNumIndexedParams */ + short mNumIndexedParams; + /*! @var mNamedParams */ + CFArrayRef mNamedParams; + +private: + void Init (AudioUnit au, AudioUnitParameterID param, AudioUnitScope scope, AudioUnitElement element); + +}; + + + +#endif // __CAAUParameter_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAtomic.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAtomic.h new file mode 100644 index 0000000000..5f9a16a90f --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAtomic.h @@ -0,0 +1,305 @@ +/* + File: CAAtomic.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +/* + This file implements all Atomic operations using Interlocked functions specified in + Winbase.h +NOTE: According to Microsoft documentation, all Interlocked functions generates a +full barrier. + On Windows: + As the Interlocked functions returns the Old value, Extra checks and operations + are made after the atomic operation to return value consistent with OSX counterparts. +*/ +#ifndef __CAAtomic_h__ +#define __CAAtomic_h__ + +#if TARGET_OS_WIN32 + #include + #include + #pragma intrinsic(_InterlockedOr) + #pragma intrinsic(_InterlockedAnd) +#else + #include + #include +#endif + +inline void CAMemoryBarrier() +{ +#if TARGET_OS_WIN32 + MemoryBarrier(); +#else + OSMemoryBarrier(); +#endif +} + +inline SInt32 CAAtomicAdd32Barrier(SInt32 theAmt, volatile SInt32* theValue) +{ +#if TARGET_OS_WIN32 + long lRetVal = InterlockedExchangeAdd((volatile long*)theValue, theAmt); + // InterlockedExchangeAdd returns the original value which differs from OSX version. + // At this point the addition would have occured and hence returning the new value + // to keep it sync with OSX. + return lRetVal + theAmt; +#else + return OSAtomicAdd32Barrier(theAmt, (volatile int32_t *)theValue); +#endif +} + +inline SInt32 CAAtomicOr32Barrier(UInt32 theMask, volatile UInt32* theValue) +{ +#if TARGET_OS_WIN32 + // InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic + // function instead. + long j = _InterlockedOr((volatile long*)theValue, theMask); + // _InterlockedOr returns the original value which differs from OSX version. + // Returning the new value similar to OSX + return (SInt32)(j | theMask); +#else + return OSAtomicOr32Barrier(theMask, (volatile uint32_t *)theValue); +#endif +} + +inline SInt32 CAAtomicAnd32Barrier(UInt32 theMask, volatile UInt32* theValue) +{ +#if TARGET_OS_WIN32 +// InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic +// function instead. + long j = _InterlockedAnd((volatile long*)theValue, theMask); + // _InterlockedAnd returns the original value which differs from OSX version. + // Returning the new value similar to OSX + return (SInt32)(j & theMask); +#else + return OSAtomicAnd32Barrier(theMask, (volatile uint32_t *)theValue); +#endif +} + +inline bool CAAtomicCompareAndSwap32Barrier(SInt32 oldValue, SInt32 newValue, volatile SInt32 *theValue) +{ +#if TARGET_OS_WIN32 + // InterlockedCompareExchange returns the old value. But we need to return bool value. + long lRetVal = InterlockedCompareExchange((volatile long*)theValue, newValue, oldValue); +// Hence we check if the new value is set and if it is we return true else false. +// If theValue is equal to oldValue then the swap happens. Otherwise swap doesn't happen. + return (oldValue == lRetVal); +#else + return OSAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile int32_t *)theValue); +#endif +} + + +inline SInt32 CAAtomicIncrement32(volatile SInt32* theValue) +{ +#if TARGET_OS_WIN32 + return (SInt32)InterlockedIncrement((volatile long*)theValue); +#else + return OSAtomicIncrement32((volatile int32_t *)theValue); +#endif +} + +inline SInt32 CAAtomicDecrement32(volatile SInt32* theValue) +{ +#if TARGET_OS_WIN32 + return (SInt32)InterlockedDecrement((volatile long*)theValue); +#else + return OSAtomicDecrement32((volatile int32_t *)theValue); +#endif +} + +inline SInt32 CAAtomicIncrement32Barrier(volatile SInt32* theValue) +{ +#if TARGET_OS_WIN32 + return CAAtomicIncrement32(theValue); +#else + return OSAtomicIncrement32Barrier((volatile int32_t *)theValue); +#endif +} + +inline SInt32 CAAtomicDecrement32Barrier(volatile SInt32* theValue) +{ +#if TARGET_OS_WIN32 + return CAAtomicDecrement32(theValue); +#else + return OSAtomicDecrement32Barrier((volatile int32_t *)theValue); +#endif +} + +inline bool CAAtomicTestAndClearBarrier(int bitToClear, void* theAddress) +{ +#if TARGET_OS_WIN32 + BOOL bOldVal = InterlockedBitTestAndReset((long*)theAddress, bitToClear); + return (bOldVal ? true : false); +#else + return OSAtomicTestAndClearBarrier(bitToClear, (volatile void *)theAddress); +#endif +} + +inline bool CAAtomicTestAndClear(int bitToClear, void* theAddress) +{ +#if TARGET_OS_WIN32 + BOOL bOldVal = CAAtomicTestAndClearBarrier(bitToClear, (long*)theAddress); + return (bOldVal ? true : false); +#else + return OSAtomicTestAndClear(bitToClear, (volatile void *)theAddress); +#endif +} + +inline bool CAAtomicTestAndSetBarrier(int bitToSet, void* theAddress) +{ +#if TARGET_OS_WIN32 + BOOL bOldVal = InterlockedBitTestAndSet((long*)theAddress, bitToSet); + return (bOldVal ? true : false); +#else + return OSAtomicTestAndSetBarrier(bitToSet, (volatile void *)theAddress); +#endif +} + +// int32_t flavors -- for C++ only since we can't overload in C +// CFBase.h defines SInt32 as signed int which is similar to int32_t. If CFBase.h is included, then +// this will generate redefinition error. But on Mac, CFBase.h, still includes MacTypes.h where +// SInt32 is defined as signed long so this would work there. +// So in order to fix the redefinition errors, we define these functions only if MacTypes.h is included. +#if defined(__cplusplus) && defined(__MACTYPES__) && !__LP64__ +inline int32_t CAAtomicAdd32Barrier(int32_t theAmt, volatile int32_t* theValue) +{ + return CAAtomicAdd32Barrier(theAmt, (volatile SInt32 *)theValue); +} + +inline int32_t CAAtomicOr32Barrier(uint32_t theMask, volatile uint32_t* theValue) +{ + return CAAtomicOr32Barrier(theMask, (volatile UInt32 *)theValue); +} + +inline int32_t CAAtomicAnd32Barrier(uint32_t theMask, volatile uint32_t* theValue) +{ + return CAAtomicAnd32Barrier(theMask, (volatile UInt32 *)theValue); +} + +inline bool CAAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue) +{ + return CAAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile SInt32 *)theValue); +} + +inline int32_t CAAtomicIncrement32(volatile int32_t* theValue) +{ + return CAAtomicIncrement32((volatile SInt32 *)theValue); +} + +inline int32_t CAAtomicDecrement32(volatile int32_t* theValue) +{ + return CAAtomicDecrement32((volatile SInt32 *)theValue); +} + +inline int32_t CAAtomicIncrement32Barrier(volatile int32_t* theValue) +{ + return CAAtomicIncrement32Barrier((volatile SInt32 *)theValue); +} + +inline int32_t CAAtomicDecrement32Barrier(volatile int32_t* theValue) +{ + return CAAtomicDecrement32Barrier((volatile SInt32 *)theValue); +} +#endif // __cplusplus && !__LP64__ + +#if __LP64__ +inline bool CAAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue ) +{ + return OSAtomicCompareAndSwap64Barrier(__oldValue, __newValue, __theValue); +} +#endif + +inline bool CAAtomicCompareAndSwapPtrBarrier(void *__oldValue, void *__newValue, volatile void ** __theValue) +{ +#if __LP64__ + return CAAtomicCompareAndSwap64Barrier((int64_t)__oldValue, (int64_t)__newValue, (int64_t *)__theValue); +#else + return CAAtomicCompareAndSwap32Barrier((int32_t)__oldValue, (int32_t)__newValue, (int32_t *)__theValue); +#endif +} + +/* Spinlocks. These use memory barriers as required to synchronize access to shared + * memory protected by the lock. The lock operation spins, but employs various strategies + * to back off if the lock is held, making it immune to most priority-inversion livelocks. + * The try operation immediately returns false if the lock was held, true if it took the + * lock. The convention is that unlocked is zero, locked is nonzero. + */ +#define CA_SPINLOCK_INIT 0 + +typedef int32_t CASpinLock; + +bool CASpinLockTry( volatile CASpinLock *__lock ); +void CASpinLockLock( volatile CASpinLock *__lock ); +void CASpinLockUnlock( volatile CASpinLock *__lock ); + +inline void CASpinLockLock( volatile CASpinLock *__lock ) +{ +#if TARGET_OS_MAC + OSSpinLockLock(__lock); +#else + while (CAAtomicTestAndSetBarrier(0, (void*)__lock)) + usleep(1000); // ??? +#endif +} + +inline void CASpinLockUnlock( volatile CASpinLock *__lock ) +{ +#if TARGET_OS_MAC + OSSpinLockUnlock(__lock); +#else + CAAtomicTestAndClearBarrier(0, (void*)__lock); +#endif +} + +inline bool CASpinLockTry( volatile CASpinLock *__lock ) +{ +#if TARGET_OS_MAC + return OSSpinLockTry(__lock); +#else + return (CAAtomicTestAndSetBarrier(0, (void*)__lock) == 0); +#endif +} + + +#endif // __CAAtomic_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAtomicStack.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAtomicStack.h new file mode 100644 index 0000000000..6ee083bf0d --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAtomicStack.h @@ -0,0 +1,239 @@ +/* + File: CAAtomicStack.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAAtomicStack_h__ +#define __CAAtomicStack_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4 + #include +#endif + +// linked list LIFO or FIFO (pop_all_reversed) stack, elements are pushed and popped atomically +// class T must implement T *& next(). +template +class TAtomicStack { +public: + TAtomicStack() : mHead(NULL) { } + + // non-atomic routines, for use when initializing/deinitializing, operate NON-atomically + void push_NA(T *item) + { + item->next() = mHead; + mHead = item; + } + + T * pop_NA() + { + T *result = mHead; + if (result) + mHead = result->next(); + return result; + } + + bool empty() const { return mHead == NULL; } + + T * head() { return mHead; } + + // atomic routines + void push_atomic(T *item) + { + T *head_; + do { + head_ = mHead; + item->next() = head_; + } while (!compare_and_swap(head_, item, &mHead)); + } + + void push_multiple_atomic(T *item) + // pushes entire linked list headed by item + { + T *head_, *p = item, *tail; + // find the last one -- when done, it will be linked to head + do { + tail = p; + p = p->next(); + } while (p); + do { + head_ = mHead; + tail->next() = head_; + } while (!compare_and_swap(head_, item, &mHead)); + } + + T * pop_atomic_single_reader() + // this may only be used when only one thread may potentially pop from the stack. + // if multiple threads may pop, this suffers from the ABA problem. + // TAtomicStack suffers from the ABA problem + { + T *result; + do { + if ((result = mHead) == NULL) + break; + } while (!compare_and_swap(result, result->next(), &mHead)); + return result; + } + + T * pop_atomic() + // This is inefficient for large linked lists. + // prefer pop_all() to a series of calls to pop_atomic. + // push_multiple_atomic has to traverse the entire list. + { + T *result = pop_all(); + if (result) { + T *next = result->next(); + if (next) + // push all the remaining items back onto the stack + push_multiple_atomic(next); + } + return result; + } + + T * pop_all() + { + T *result; + do { + if ((result = mHead) == NULL) + break; + } while (!compare_and_swap(result, NULL, &mHead)); + return result; + } + + T* pop_all_reversed() + { + TAtomicStack reversed; + T *p = pop_all(), *next; + while (p != NULL) { + next = p->next(); + reversed.push_NA(p); + p = next; + } + return reversed.mHead; + } + + static bool compare_and_swap(T *oldvalue, T *newvalue, T **pvalue) + { +#if TARGET_OS_MAC + #if __LP64__ + return ::OSAtomicCompareAndSwap64Barrier(int64_t(oldvalue), int64_t(newvalue), (int64_t *)pvalue); + #elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 + return ::OSAtomicCompareAndSwap32Barrier(int32_t(oldvalue), int32_t(newvalue), (int32_t *)pvalue); + #else + return ::CompareAndSwap(UInt32(oldvalue), UInt32(newvalue), (UInt32 *)pvalue); + #endif +#else + //return ::CompareAndSwap(UInt32(oldvalue), UInt32(newvalue), (UInt32 *)pvalue); + return CAAtomicCompareAndSwap32Barrier(SInt32(oldvalue), SInt32(newvalue), (SInt32*)pvalue); +#endif + } + +protected: + T * mHead; +}; + +#if ((MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) && !TARGET_OS_WIN32) +#include + +class CAAtomicStack { +public: + CAAtomicStack(size_t nextPtrOffset) : mNextPtrOffset(nextPtrOffset) { + /*OSQueueHead h = OS_ATOMIC_QUEUE_INIT; mHead = h;*/ + mHead.opaque1 = 0; mHead.opaque2 = 0; + } + // a subset of the above + void push_atomic(void *p) { OSAtomicEnqueue(&mHead, p, mNextPtrOffset); } + void push_NA(void *p) { push_atomic(p); } + + void * pop_atomic() { return OSAtomicDequeue(&mHead, mNextPtrOffset); } + void * pop_atomic_single_reader() { return pop_atomic(); } + void * pop_NA() { return pop_atomic(); } + +private: + OSQueueHead mHead; + size_t mNextPtrOffset; +}; + +// a more efficient subset of TAtomicStack using OSQueue. +template +class TAtomicStack2 { +public: + TAtomicStack2() { + /*OSQueueHead h = OS_ATOMIC_QUEUE_INIT; mHead = h;*/ + mHead.opaque1 = 0; mHead.opaque2 = 0; + mNextPtrOffset = -1; + } + void push_atomic(T *item) { + if (mNextPtrOffset < 0) { + T **pnext = &item->next(); // hack around offsetof not working with C++ + mNextPtrOffset = (Byte *)pnext - (Byte *)item; + } + OSAtomicEnqueue(&mHead, item, mNextPtrOffset); + } + void push_NA(T *item) { push_atomic(item); } + + T * pop_atomic() { return (T *)OSAtomicDequeue(&mHead, mNextPtrOffset); } + T * pop_atomic_single_reader() { return pop_atomic(); } + T * pop_NA() { return pop_atomic(); } + + // caution: do not try to implement pop_all_reversed here. the writer could add new elements + // while the reader is trying to pop old ones! + +private: + OSQueueHead mHead; + ssize_t mNextPtrOffset; +}; + +#else + +#define TAtomicStack2 TAtomicStack + +#endif // MAC_OS_X_VERSION_MAX_ALLOWED && !TARGET_OS_WIN32 + +#endif // __CAAtomicStack_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAudioChannelLayout.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAudioChannelLayout.cpp new file mode 100644 index 0000000000..8171e09542 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAudioChannelLayout.cpp @@ -0,0 +1,153 @@ +/* + File: CAAudioChannelLayout.cpp + Abstract: CAAudioChannelLayout.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CAAudioChannelLayout.h" +#include "CAAutoDisposer.h" +#include +#include + +//============================================================================= +// CAAudioChannelLayout +//============================================================================= + +AudioChannelLayout* CAAudioChannelLayout::Create(UInt32 inNumberChannelDescriptions) +{ + UInt32 theSize = CalculateByteSize(inNumberChannelDescriptions); + AudioChannelLayout* theAnswer = static_cast(CA_calloc(1, theSize)); + if(theAnswer != NULL) + { + SetAllToUnknown(*theAnswer, inNumberChannelDescriptions); + } + return theAnswer; +} + +void CAAudioChannelLayout::Destroy(AudioChannelLayout* inChannelLayout) +{ + free(inChannelLayout); +} + +void CAAudioChannelLayout::SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions) +{ + outChannelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions; + outChannelLayout.mChannelBitmap = 0; + outChannelLayout.mNumberChannelDescriptions = inNumberChannelDescriptions; + for(UInt32 theChannelIndex = 0; theChannelIndex < inNumberChannelDescriptions; ++theChannelIndex) + { + outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelLabel = kAudioChannelLabel_Unknown; + outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelFlags = 0; + outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[0] = 0; + outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[1] = 0; + outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[2] = 0; + } +} + +bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y) +{ + // compare based on the number of channel descriptions present + // (this may be too strict a comparison if all you care about are matching layout tags) + UInt32 theSize1 = CAAudioChannelLayout::CalculateByteSize(x.mNumberChannelDescriptions); + UInt32 theSize2 = CAAudioChannelLayout::CalculateByteSize(y.mNumberChannelDescriptions); + + if (theSize1 != theSize2) + return false; + + return !memcmp (&x, &y, theSize1); +} + +bool operator!= (const AudioChannelLayout &x, const AudioChannelLayout &y) +{ + return !(x == y); +} + +// counting the one bits in a word +inline UInt32 CountOnes(UInt32 x) +{ + // secret magic algorithm for counting bits in a word. + UInt32 t; + x = x - ((x >> 1) & 0x55555555); + t = ((x >> 2) & 0x33333333); + x = (x & 0x33333333) + t; + x = (x + (x >> 4)) & 0x0F0F0F0F; + x = x + (x << 8); + x = x + (x << 16); + return x >> 24; +} + +UInt32 CAAudioChannelLayout::NumberChannels (const AudioChannelLayout& inLayout) +{ + if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) + return inLayout.mNumberChannelDescriptions; + + if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) + return CountOnes (inLayout.mChannelBitmap); + + return AudioChannelLayoutTag_GetNumberOfChannels(inLayout.mChannelLayoutTag); +} + +void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout) +{ + if (layout == NULL) + { + fprintf (file, "\tNULL layout\n"); + return; + } + fprintf (file, "\tTag=0x%X, ", (int)layout->mChannelLayoutTag); + if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) + fprintf (file, "Using Bitmap:0x%X\n", (int)layout->mChannelBitmap); + else { + fprintf (file, "Num Chan Descs=%d\n", (int)layout->mNumberChannelDescriptions); + const AudioChannelDescription *desc = layout->mChannelDescriptions; + for (unsigned int i = 0; i < layout->mNumberChannelDescriptions; ++i, ++desc) { + fprintf (file, "\t\tLabel=%d, Flags=0x%X, ", (int)desc->mChannelLabel, (int)desc->mChannelFlags); + fprintf (file, "[az=%f,el=%f,dist=%f]\n", desc->mCoordinates[0], desc->mCoordinates[1], desc->mCoordinates[2]); + } + } +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAudioChannelLayout.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAudioChannelLayout.h new file mode 100644 index 0000000000..acc5e2b4ff --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAudioChannelLayout.h @@ -0,0 +1,199 @@ +/* + File: CAAudioChannelLayout.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAAudioChannelLayout_h__) +#define __CAAudioChannelLayout_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif +#include +#include +#include + +#include "CADebugMacros.h" +#include "CAAutoDisposer.h" + +#if !HAL_Build + #include "CAReferenceCounted.h" +#endif + +//============================================================================= +// CAAudioChannelLayout +//============================================================================= + +bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y); +bool operator!= (const AudioChannelLayout &x, const AudioChannelLayout &y); + +extern "C" void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout); + +class CAAudioChannelLayout +{ +// static Construction/Destruction +public: + static AudioChannelLayout* Create(UInt32 inNumberChannelDescriptions); + static void Destroy(AudioChannelLayout* inChannelLayout); + static UInt32 CalculateByteSize(UInt32 inNumberChannelDescriptions) { + return SizeOf32(AudioChannelLayout) - SizeOf32(AudioChannelDescription) + (inNumberChannelDescriptions * SizeOf32(AudioChannelDescription)); + } + static void SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions); + static UInt32 NumberChannels(const AudioChannelLayout& inLayout); + +#if !HAL_Build +// object methods +public: + CAAudioChannelLayout (); + + CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround); + // if inChooseSurround is false, then symmetrical speaker arrangements + // are chosen in place of surround layouts if there is a choice + // This call chooses layouts based on the expected defaults in + // AudioUnit usage + CAAudioChannelLayout (AudioChannelLayoutTag inTag); + CAAudioChannelLayout (const CAAudioChannelLayout &c); + CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout); + ~CAAudioChannelLayout(); + + CAAudioChannelLayout& operator= (const AudioChannelLayout* inChannelLayout); + CAAudioChannelLayout& operator= (const CAAudioChannelLayout& c); + bool operator== (const CAAudioChannelLayout &c) const; + bool operator!= (const CAAudioChannelLayout &c) const; + + void SetWithTag(AudioChannelLayoutTag inTag); + + bool IsValid() const { return NumberChannels() > 0; } + UInt32 Size() const { return mLayout ? mLayout->Size() : 0; } + + UInt32 NumberChannels() const { return mLayout ? mLayout->NumberChannels() : 0; } + + AudioChannelLayoutTag Tag() const { return Layout().mChannelLayoutTag; } + const AudioChannelLayout& Layout() const { return mLayout->Layout(); } + operator const AudioChannelLayout *() const { return &Layout(); } + + void Print () const { Print (stdout); } + void Print (FILE* file) const; + + OSStatus Save (CFPropertyListRef *outData) const; + OSStatus Restore (CFPropertyListRef &inData); + +private: + class RefCountedLayout : public CAReferenceCounted { + void * operator new(size_t /* size */, size_t aclSize) + { + return CA_malloc(sizeof(RefCountedLayout) - sizeof(AudioChannelLayout) + aclSize); + } + + void operator delete(void *mem) + { + free(mem); + } + + + RefCountedLayout(UInt32 inDataSize) : + mByteSize(inDataSize) + { + memset(&mACL, 0, inDataSize); + } + + public: + static RefCountedLayout *CreateWithNumberChannelDescriptions(unsigned nChannels) { + size_t size = CAAudioChannelLayout::CalculateByteSize(nChannels); + return new(size) RefCountedLayout((UInt32)size); + } + + static RefCountedLayout *CreateWithLayout(const AudioChannelLayout *layout) { + size_t size = CAAudioChannelLayout::CalculateByteSize(layout->mNumberChannelDescriptions); + RefCountedLayout *acl = new(size) RefCountedLayout((UInt32)size); + memcpy(&acl->mACL, layout, size); + return acl; + } + static RefCountedLayout *CreateWithLayoutTag(AudioChannelLayoutTag layoutTag) { + RefCountedLayout *acl = CreateWithNumberChannelDescriptions(0); + acl->mACL.mChannelLayoutTag = layoutTag; + return acl; + } + + const AudioChannelLayout & Layout() const { return mACL; } + + UInt32 Size () const { return mByteSize; } + + UInt32 NumberChannels() { return CAAudioChannelLayout::NumberChannels(Layout()); } + + private: + const UInt32 mByteSize; + AudioChannelLayout mACL; + // * * * mACL is variable length and thus must be last * * * + + // only the constructors can change the actual state of the layout + friend CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround); + friend OSStatus CAAudioChannelLayout::Restore (CFPropertyListRef &inData); + friend CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout); + friend void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag); + + AudioChannelLayout * GetLayout() { return &mACL; } + + private: + // prohibited methods: private and unimplemented. + RefCountedLayout(); + RefCountedLayout(const RefCountedLayout& c); + RefCountedLayout& operator=(const RefCountedLayout& c); + }; + + RefCountedLayout *mLayout; +#endif // HAL_Build + +}; + +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAutoDisposer.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAutoDisposer.h new file mode 100644 index 0000000000..bb8faf2ced --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAAutoDisposer.h @@ -0,0 +1,508 @@ +/* + File: CAAutoDisposer.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAPtr_h__) +#define __CAPtr_h__ + +#include // for malloc +#include // for bad_alloc +#include // for memset + +inline void* CA_malloc(size_t size) +{ + void* p = malloc(size); + if (!p && size) throw std::bad_alloc(); + return p; +} + +inline void* CA_realloc(void* old, size_t size) +{ +#if TARGET_OS_WIN32 + void* p = realloc(old, size); +#else + void* p = reallocf(old, size); // reallocf ensures the old pointer is freed if memory is full (p is NULL). +#endif + if (!p && size) throw std::bad_alloc(); + return p; +} + +#ifndef UINTPTR_MAX +#if __LP64__ +#define UINTPTR_MAX 18446744073709551615ULL +#else +#define UINTPTR_MAX 4294967295U +#endif +#endif + +inline void* CA_calloc(size_t n, size_t size) +{ + // ensure that multiplication will not overflow + if (n && UINTPTR_MAX / n < size) throw std::bad_alloc(); + + size_t nsize = n*size; + void* p = malloc(nsize); + if (!p && nsize) throw std::bad_alloc(); + + memset(p, 0, nsize); + return p; +} + + +// helper class for automatic conversions +template +struct CAPtrRef +{ + T* ptr_; + + explicit CAPtrRef(T* ptr) : ptr_(ptr) {} +}; + +template +class CAAutoFree +{ +private: + T* ptr_; + +public: + + CAAutoFree() : ptr_(0) {} + + explicit CAAutoFree(T* ptr) : ptr_(ptr) {} + + template + CAAutoFree(CAAutoFree& that) : ptr_(that.release()) {} // take ownership + + // C++ std says: a template constructor is never a copy constructor + CAAutoFree(CAAutoFree& that) : ptr_(that.release()) {} // take ownership + + CAAutoFree(size_t n, bool clear = false) + // this becomes an ambiguous call if n == 0 + : ptr_(0) + { + size_t maxItems = ~size_t(0) / sizeof(T); + if (n > maxItems) + throw std::bad_alloc(); + + ptr_ = static_cast(clear ? CA_calloc(n, sizeof(T)) : CA_malloc(n * sizeof(T))); + } + + ~CAAutoFree() { free(); } + + void alloc(size_t numItems, bool clear = false) + { + size_t maxItems = ~size_t(0) / sizeof(T); + if (numItems > maxItems) throw std::bad_alloc(); + + free(); + ptr_ = static_cast(clear ? CA_calloc(numItems, sizeof(T)) : CA_malloc(numItems * sizeof(T))); + } + + void allocBytes(size_t numBytes, bool clear = false) + { + free(); + ptr_ = static_cast(clear ? CA_calloc(1, numBytes) : CA_malloc(numBytes)); + } + + void reallocBytes(size_t numBytes) + { + ptr_ = static_cast(CA_realloc(ptr_, numBytes)); + } + + void reallocItems(size_t numItems) + { + size_t maxItems = ~size_t(0) / sizeof(T); + if (numItems > maxItems) throw std::bad_alloc(); + + ptr_ = static_cast(CA_realloc(ptr_, numItems * sizeof(T))); + } + + template + CAAutoFree& operator=(CAAutoFree& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoFree& operator=(CAAutoFree& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoFree& operator=(T* ptr) + { + set(ptr); + return *this; + } + + template + CAAutoFree& operator=(U* ptr) + { + set(ptr); + return *this; + } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + + T* operator()() const { return ptr_; } + T* get() const { return ptr_; } + operator T*() const { return ptr_; } + + bool operator==(CAAutoFree const& that) const { return ptr_ == that.ptr_; } + bool operator!=(CAAutoFree const& that) const { return ptr_ != that.ptr_; } + bool operator==(T* ptr) const { return ptr_ == ptr; } + bool operator!=(T* ptr) const { return ptr_ != ptr; } + + T* release() + { + // release ownership + T* result = ptr_; + ptr_ = 0; + return result; + } + + void set(T* ptr) + { + if (ptr != ptr_) + { + ::free(ptr_); + ptr_ = ptr; + } + } + + void free() + { + set(0); + } + + + // automatic conversions to allow assignment from results of functions. + // hard to explain. see auto_ptr implementation and/or Josuttis' STL book. + CAAutoFree(CAPtrRef ref) : ptr_(ref.ptr_) { } + + CAAutoFree& operator=(CAPtrRef ref) + { + set(ref.ptr_); + return *this; + } + + template + operator CAPtrRef() + { return CAPtrRef(release()); } + + template + operator CAAutoFree() + { return CAAutoFree(release()); } + +}; + + +template +class CAAutoDelete +{ +private: + T* ptr_; + +public: + CAAutoDelete() : ptr_(0) {} + + explicit CAAutoDelete(T* ptr) : ptr_(ptr) {} + + template + CAAutoDelete(CAAutoDelete& that) : ptr_(that.release()) {} // take ownership + + // C++ std says: a template constructor is never a copy constructor + CAAutoDelete(CAAutoDelete& that) : ptr_(that.release()) {} // take ownership + + ~CAAutoDelete() { free(); } + + template + CAAutoDelete& operator=(CAAutoDelete& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoDelete& operator=(CAAutoDelete& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoDelete& operator=(T* ptr) + { + set(ptr); + return *this; + } + + template + CAAutoDelete& operator=(U* ptr) + { + set(ptr); + return *this; + } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + + T* operator()() const { return ptr_; } + T* get() const { return ptr_; } + operator T*() const { return ptr_; } + + bool operator==(CAAutoDelete const& that) const { return ptr_ == that.ptr_; } + bool operator!=(CAAutoDelete const& that) const { return ptr_ != that.ptr_; } + bool operator==(T* ptr) const { return ptr_ == ptr; } + bool operator!=(T* ptr) const { return ptr_ != ptr; } + + T* release() + { + // release ownership + T* result = ptr_; + ptr_ = 0; + return result; + } + + void set(T* ptr) + { + if (ptr != ptr_) + { + delete ptr_; + ptr_ = ptr; + } + } + + void free() + { + set(0); + } + + + // automatic conversions to allow assignment from results of functions. + // hard to explain. see auto_ptr implementation and/or Josuttis' STL book. + CAAutoDelete(CAPtrRef ref) : ptr_(ref.ptr_) { } + + CAAutoDelete& operator=(CAPtrRef ref) + { + set(ref.ptr_); + return *this; + } + + template + operator CAPtrRef() + { return CAPtrRef(release()); } + + template + operator CAAutoFree() + { return CAAutoFree(release()); } + +}; + + +template +class CAAutoArrayDelete +{ +private: + T* ptr_; + +public: + CAAutoArrayDelete() : ptr_(0) {} + + explicit CAAutoArrayDelete(T* ptr) : ptr_(ptr) {} + + template + CAAutoArrayDelete(CAAutoArrayDelete& that) : ptr_(that.release()) {} // take ownership + + // C++ std says: a template constructor is never a copy constructor + CAAutoArrayDelete(CAAutoArrayDelete& that) : ptr_(that.release()) {} // take ownership + + // this becomes an ambiguous call if n == 0 + CAAutoArrayDelete(size_t n) : ptr_(new T[n]) {} + + ~CAAutoArrayDelete() { free(); } + + void alloc(size_t numItems) + { + free(); + ptr_ = new T [numItems]; + } + + template + CAAutoArrayDelete& operator=(CAAutoArrayDelete& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoArrayDelete& operator=(CAAutoArrayDelete& that) + { + set(that.release()); // take ownership + return *this; + } + + CAAutoArrayDelete& operator=(T* ptr) + { + set(ptr); + return *this; + } + + template + CAAutoArrayDelete& operator=(U* ptr) + { + set(ptr); + return *this; + } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + + T* operator()() const { return ptr_; } + T* get() const { return ptr_; } + operator T*() const { return ptr_; } + + bool operator==(CAAutoArrayDelete const& that) const { return ptr_ == that.ptr_; } + bool operator!=(CAAutoArrayDelete const& that) const { return ptr_ != that.ptr_; } + bool operator==(T* ptr) const { return ptr_ == ptr; } + bool operator!=(T* ptr) const { return ptr_ != ptr; } + + T* release() + { + // release ownership + T* result = ptr_; + ptr_ = 0; + return result; + } + + void set(T* ptr) + { + if (ptr != ptr_) + { + delete [] ptr_; + ptr_ = ptr; + } + } + + void free() + { + set(0); + } + + + // automatic conversions to allow assignment from results of functions. + // hard to explain. see auto_ptr implementation and/or Josuttis' STL book. + CAAutoArrayDelete(CAPtrRef ref) : ptr_(ref.ptr_) { } + + CAAutoArrayDelete& operator=(CAPtrRef ref) + { + set(ref.ptr_); + return *this; + } + + template + operator CAPtrRef() + { return CAPtrRef(release()); } + + template + operator CAAutoArrayDelete() + { return CAAutoFree(release()); } + +}; + + + + + +// convenience function +template +void free(CAAutoFree& p) +{ + p.free(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if 0 +// example program showing ownership transfer + +CAAutoFree source() +{ + // source allocates and returns ownership to the caller. + const char* str = "this is a test"; + size_t size = strlen(str) + 1; + CAAutoFree captr(size, false); + strlcpy(captr(), str, size); + printf("source %08X %08X '%s'\n", &captr, captr(), captr()); + return captr; +} + +void user(CAAutoFree const& captr) +{ + // passed by const reference. user can access the pointer but does not take ownership. + printf("user: %08X %08X '%s'\n", &captr, captr(), captr()); +} + +void sink(CAAutoFree captr) +{ + // passed by value. sink takes ownership and frees the pointer on return. + printf("sink: %08X %08X '%s'\n", &captr, captr(), captr()); +} + + +int main (int argc, char * const argv[]) +{ + + CAAutoFree captr(source()); + printf("main captr A %08X %08X\n", &captr, captr()); + user(captr); + sink(captr); + printf("main captr B %08X %08X\n", &captr, captr()); + return 0; +} +#endif + +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CADebugMacros.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CADebugMacros.h new file mode 100644 index 0000000000..66a678aa0f --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CADebugMacros.h @@ -0,0 +1,581 @@ +/* + File: CADebugMacros.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CADebugMacros_h__) +#define __CADebugMacros_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include "CoreAudioTypes.h" +#endif + +//============================================================================= +// CADebugMacros +//============================================================================= + +//#define CoreAudio_StopOnFailure 1 +//#define CoreAudio_TimeStampMessages 1 +//#define CoreAudio_ThreadStampMessages 1 +//#define CoreAudio_FlushDebugMessages 1 + +#if TARGET_RT_BIG_ENDIAN + #define CA4CCToCString(the4CC) { ((char*)&the4CC)[0], ((char*)&the4CC)[1], ((char*)&the4CC)[2], ((char*)&the4CC)[3], 0 } + #define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[0]; theCString[1] = ((char*)&the4CC)[1]; theCString[2] = ((char*)&the4CC)[2]; theCString[3] = ((char*)&the4CC)[3]; theCString[4] = 0; } +#else + #define CA4CCToCString(the4CC) { ((char*)&the4CC)[3], ((char*)&the4CC)[2], ((char*)&the4CC)[1], ((char*)&the4CC)[0], 0 } + #define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[3]; theCString[1] = ((char*)&the4CC)[2]; theCString[2] = ((char*)&the4CC)[1]; theCString[3] = ((char*)&the4CC)[0]; theCString[4] = 0; } +#endif + +// This is a macro that does a sizeof and casts the result to a UInt32. This is useful for all the +// places where -wshorten64-32 catches assigning a sizeof expression to a UInt32. +// For want of a better place to park this, we'll park it here. +#define SizeOf32(X) ((UInt32)sizeof(X)) + +// This is a macro that does a offsetof and casts the result to a UInt32. This is useful for all the +// places where -wshorten64-32 catches assigning an offsetof expression to a UInt32. +// For want of a better place to park this, we'll park it here. +#define OffsetOf32(X, Y) ((UInt32)offsetof(X, Y)) + +// This macro casts the expression to a UInt32. It is called out specially to allow us to track casts +// that have been added purely to avert -wshorten64-32 warnings on 64 bit platforms. +// For want of a better place to park this, we'll park it here. +#define ToUInt32(X) ((UInt32)(X)) +#define ToSInt32(X) ((SInt32)(X)) + +#pragma mark Basic Definitions + +#if DEBUG || CoreAudio_Debug + // can be used to break into debugger immediately, also see CADebugger + #define BusError() { long* p=NULL; *p=0; } + + // basic debugging print routines + #if TARGET_OS_MAC && !TARGET_API_MAC_CARBON + extern void DebugStr(const unsigned char* debuggerMsg); + #define DebugMessage(msg) DebugStr("\p"msg) + #define DebugMessageN1(msg, N1) + #define DebugMessageN2(msg, N1, N2) + #define DebugMessageN3(msg, N1, N2, N3) + #else + #include "CADebugPrintf.h" + + #if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile) + #define FlushRtn ,fflush(DebugPrintfFile) + #else + #define FlushRtn + #endif + + #if CoreAudio_ThreadStampMessages + #include + #include "CAHostTimeBase.h" + #if TARGET_RT_64_BIT + #define DebugPrintfThreadIDFormat "%16p" + #else + #define DebugPrintfThreadIDFormat "%8p" + #endif + #define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " DebugPrintfThreadIDFormat " " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), pthread_self(), ## __VA_ARGS__) FlushRtn + #elif CoreAudio_TimeStampMessages + #include "CAHostTimeBase.h" + #define DebugMsg(inFormat, ...) DebugPrintf("%17qd: " inFormat, CAHostTimeBase::GetCurrentTimeInNanos(), ## __VA_ARGS__) FlushRtn + #else + #define DebugMsg(inFormat, ...) DebugPrintf(inFormat, ## __VA_ARGS__) FlushRtn + #endif + #endif + void DebugPrint(const char *fmt, ...); // can be used like printf + #ifndef DEBUGPRINT + #define DEBUGPRINT(msg) DebugPrint msg // have to double-parenthesize arglist (see Debugging.h) + #endif + #if VERBOSE + #define vprint(msg) DEBUGPRINT(msg) + #else + #define vprint(msg) + #endif + + // Original macro keeps its function of turning on and off use of CADebuggerStop() for both asserts and throws. + // For backwards compat, it overrides any setting of the two sub-macros. + #if CoreAudio_StopOnFailure + #include "CADebugger.h" + #undef CoreAudio_StopOnAssert + #define CoreAudio_StopOnAssert 1 + #undef CoreAudio_StopOnThrow + #define CoreAudio_StopOnThrow 1 + #define STOP CADebuggerStop() + #else + #define STOP + #endif + + #if CoreAudio_StopOnAssert + #if !CoreAudio_StopOnFailure + #include "CADebugger.h" + #define STOP + #endif + #define __ASSERT_STOP CADebuggerStop() + #else + #define __ASSERT_STOP + #endif + + #if CoreAudio_StopOnThrow + #if !CoreAudio_StopOnFailure + #include "CADebugger.h" + #define STOP + #endif + #define __THROW_STOP CADebuggerStop() + #else + #define __THROW_STOP + #endif + +#else + #define DebugMsg(inFormat, ...) + #ifndef DEBUGPRINT + #define DEBUGPRINT(msg) + #endif + #define vprint(msg) + #define STOP + #define __ASSERT_STOP + #define __THROW_STOP +#endif + +// Old-style numbered DebugMessage calls are implemented in terms of DebugMsg() now +#define DebugMessage(msg) DebugMsg(msg) +#define DebugMessageN1(msg, N1) DebugMsg(msg, N1) +#define DebugMessageN2(msg, N1, N2) DebugMsg(msg, N1, N2) +#define DebugMessageN3(msg, N1, N2, N3) DebugMsg(msg, N1, N2, N3) +#define DebugMessageN4(msg, N1, N2, N3, N4) DebugMsg(msg, N1, N2, N3, N4) +#define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugMsg(msg, N1, N2, N3, N4, N5) +#define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugMsg(msg, N1, N2, N3, N4, N5, N6) +#define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7) +#define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7, N8) +#define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugMsg(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) + +void LogError(const char *fmt, ...); // writes to syslog (and stderr if debugging) +void LogWarning(const char *fmt, ...); // writes to syslog (and stderr if debugging) + +#define NO_ACTION (void)0 + +#if DEBUG || CoreAudio_Debug + +#pragma mark Debug Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + DebugMessage(inMessage); \ + __ASSERT_STOP; \ + } + +#define AssertFileLine(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + DebugMessageN3("%s, line %d: %s", __FILE__, __LINE__, inMessage); \ + __ASSERT_STOP; \ + } + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNotNULL(inPtr, inMessage) \ + { \ + if((inPtr) == NULL) \ + { \ + DebugMessage(inMessage); \ + __ASSERT_STOP; \ + } \ + } + +#define FailIf(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + goto inHandler; \ + } + +#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelError(inKernelError, inAction, inHandler, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfError(inError, inAction, inHandler, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %ld (%s)", (long int)__Err, __4CC); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfNoMessage(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithActionNoMessage(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULLNoMessage(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelErrorNoMessage(inKernelError, inAction, inHandler, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfErrorNoMessage(inError, inAction, inHandler, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#if defined(__cplusplus) + +#define Throw(inException) __THROW_STOP; throw (inException) + +#define ThrowIf(inCondition, inException, inMessage) \ + if(inCondition) \ + { \ + DebugMessage(inMessage); \ + Throw(inException); \ + } + +#define ThrowIfNULL(inPointer, inException, inMessage) \ + if((inPointer) == NULL) \ + { \ + DebugMessage(inMessage); \ + Throw(inException); \ + } + +#define ThrowIfKernelError(inKernelError, inException, inMessage) \ + { \ + int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + Throw(inException); \ + } \ + } + +#define ThrowIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \ + Throw(inException); \ + } \ + } + +#if TARGET_OS_WIN32 +#define ThrowIfWinError(inError, inException, inMessage) \ + { \ + HRESULT __Err = (inError); \ + if(FAILED(__Err)) \ + { \ + DebugMessageN2(inMessage ", Code: %d, Facility: 0x%X", HRESULT_CODE(__Err), HRESULT_FACILITY(__Err)); \ + Throw(inException); \ + } \ + } +#endif + +#define SubclassResponsibility(inMethodName, inException) \ + { \ + DebugMessage(inMethodName": Subclasses must implement this method"); \ + Throw(inException); \ + } + +#endif // defined(__cplusplus) + +#else + +#pragma mark Release Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + __ASSERT_STOP; \ + } + +#define AssertFileLine(inCondition, inMessage) Assert(inCondition, inMessage) + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + __ASSERT_STOP; \ + } \ + } + +#define AssertNotNULL(inPtr, inMessage) \ + { \ + if((inPtr) == NULL) \ + { \ + __ASSERT_STOP; \ + } \ + } + +#define FailIf(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithAction(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelError(inKernelError, inAction, inHandler, inMessage) \ + if((inKernelError) != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfError(inError, inAction, inHandler, inMessage) \ + if((inError) != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNoMessage(inCondition, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + goto inHandler; \ + } + +#define FailWithActionNoMessage(inCondition, inAction, inHandler, inMessage) \ + if(inCondition) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfNULLNoMessage(inPointer, inAction, inHandler, inMessage) \ + if((inPointer) == NULL) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } + +#define FailIfKernelErrorNoMessage(inKernelError, inAction, inHandler, inMessage) \ + { \ + unsigned int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#define FailIfErrorNoMessage(inError, inAction, inHandler, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#if defined(__cplusplus) + +#define Throw(inException) __THROW_STOP; throw (inException) + +#define ThrowIf(inCondition, inException, inMessage) \ + if(inCondition) \ + { \ + Throw(inException); \ + } + +#define ThrowIfNULL(inPointer, inException, inMessage) \ + if((inPointer) == NULL) \ + { \ + Throw(inException); \ + } + +#define ThrowIfKernelError(inKernelError, inException, inMessage) \ + { \ + int __Err = (inKernelError); \ + if(__Err != 0) \ + { \ + Throw(inException); \ + } \ + } + +#define ThrowIfError(inError, inException, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + Throw(inException); \ + } \ + } + +#if TARGET_OS_WIN32 +#define ThrowIfWinError(inError, inException, inMessage) \ + { \ + HRESULT __Err = (inError); \ + if(FAILED(__Err)) \ + { \ + Throw(inException); \ + } \ + } +#endif + +#define SubclassResponsibility(inMethodName, inException) \ + { \ + Throw(inException); \ + } + +#endif // defined(__cplusplus) + +#endif // DEBUG || CoreAudio_Debug + +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CADebugPrintf.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CADebugPrintf.h new file mode 100644 index 0000000000..37bad12054 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CADebugPrintf.h @@ -0,0 +1,115 @@ +/* + File: CADebugPrintf.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CADebugPrintf_h__) +#define __CADebugPrintf_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include "CoreAudioTypes.h" +#endif + +//============================================================================= +// Macros to redirect debugging output to various logging services +//============================================================================= + +//#define CoreAudio_UseSysLog 1 +//#define CoreAudio_UseSideFile "/CoreAudio-%d.txt" + +#if DEBUG || CoreAudio_Debug + + #if TARGET_OS_WIN32 + #if defined(__cplusplus) + extern "C" + #endif + extern int CAWin32DebugPrintf(char* inFormat, ...); + #define DebugPrintfRtn CAWin32DebugPrintf + #define DebugPrintfFile + #define DebugPrintfLineEnding "\n" + #define DebugPrintfFileComma + #else + #if CoreAudio_UseSysLog + #include + #define DebugPrintfRtn syslog + #define DebugPrintfFile LOG_NOTICE + #define DebugPrintfLineEnding "" + #define DebugPrintfFileComma DebugPrintfFile, + #elif defined(CoreAudio_UseSideFile) + #include + #if defined(__cplusplus) + extern "C" + #endif + void OpenDebugPrintfSideFile(); + extern FILE* sDebugPrintfSideFile; + #define DebugPrintfRtn fprintf + #define DebugPrintfFile ((sDebugPrintfSideFile != NULL) ? sDebugPrintfSideFile : stderr) + #define DebugPrintfLineEnding "\n" + #define DebugPrintfFileComma DebugPrintfFile, + #else + #include + #define DebugPrintfRtn fprintf + #define DebugPrintfFile stderr + #define DebugPrintfLineEnding "\n" + #define DebugPrintfFileComma DebugPrintfFile, + #endif + #endif + + #define DebugPrintf(inFormat, ...) DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__) +#else + #define DebugPrintfRtn + #define DebugPrintfFile + #define DebugPrintfLineEnding + #define DebugPrintfFileComma + #define DebugPrintf(inFormat, ...) +#endif + + +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAException.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAException.h new file mode 100644 index 0000000000..1c207f191a --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAException.h @@ -0,0 +1,83 @@ +/* + File: CAException.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAException_h__) +#define __CAException_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include "CoreAudioTypes.h" +#endif + +//============================================================================= +// CAException +//============================================================================= + +class CAException +{ + +public: + CAException(OSStatus inError) : mError(inError) {} + CAException(const CAException& inException) : mError(inException.mError) {} + CAException& operator=(const CAException& inException) { mError = inException.mError; return *this; } + ~CAException() {} + + OSStatus GetError() const { return mError; } + +protected: + OSStatus mError; +}; + +#define CATry try{ +#define CACatch } catch(...) {} +#define CASwallowException(inExpression) try { inExpression; } catch(...) {} + +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAHostTimeBase.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAHostTimeBase.h new file mode 100644 index 0000000000..5098308011 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAHostTimeBase.h @@ -0,0 +1,234 @@ +/* + File: CAHostTimeBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__CAHostTimeBase_h__) +#define __CAHostTimeBase_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#if TARGET_OS_MAC + #include + #include +#elif TARGET_OS_WIN32 + #include + #include "WinPThreadDefs.h" +#else + #error Unsupported operating system +#endif + +#include "CADebugPrintf.h" + +//============================================================================= +// CAHostTimeBase +// +// This class provides platform independent access to the host's time base. +//============================================================================= + +#if CoreAudio_Debug +// #define Log_Host_Time_Base_Parameters 1 +// #define Track_Host_TimeBase 1 +#endif + +class CAHostTimeBase +{ + +public: + static UInt64 ConvertToNanos(UInt64 inHostTime); + static UInt64 ConvertFromNanos(UInt64 inNanos); + + static UInt64 GetTheCurrentTime(); +#if TARGET_OS_MAC + static UInt64 GetCurrentTime() { return GetTheCurrentTime(); } +#endif + static UInt64 GetCurrentTimeInNanos(); + + static Float64 GetFrequency() { pthread_once(&sIsInited, Initialize); return sFrequency; } + static Float64 GetInverseFrequency() { pthread_once(&sIsInited, Initialize); return sInverseFrequency; } + static UInt32 GetMinimumDelta() { pthread_once(&sIsInited, Initialize); return sMinDelta; } + + static UInt64 AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime); + static SInt64 HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime); + + static UInt64 MultiplyByRatio(UInt64 inMuliplicand, UInt32 inNumerator, UInt32 inDenominator); + +private: + static void Initialize(); + + static pthread_once_t sIsInited; + + static Float64 sFrequency; + static Float64 sInverseFrequency; + static UInt32 sMinDelta; + static UInt32 sToNanosNumerator; + static UInt32 sToNanosDenominator; +#if Track_Host_TimeBase + static UInt64 sLastTime; +#endif +}; + +inline UInt64 CAHostTimeBase::GetTheCurrentTime() +{ + UInt64 theTime = 0; + + #if TARGET_OS_MAC + theTime = mach_absolute_time(); + #elif TARGET_OS_WIN32 + LARGE_INTEGER theValue; + QueryPerformanceCounter(&theValue); + theTime = *((UInt64*)&theValue); + #endif + + #if Track_Host_TimeBase + if(sLastTime != 0) + { + if(theTime <= sLastTime) + { + DebugPrintf("CAHostTimeBase::GetTheCurrentTime: the current time is earlier than the last time, now: %qd, then: %qd", theTime, sLastTime); + } + sLastTime = theTime; + } + else + { + sLastTime = theTime; + } + #endif + + return theTime; +} + +inline UInt64 CAHostTimeBase::ConvertToNanos(UInt64 inHostTime) +{ + pthread_once(&sIsInited, Initialize); + + UInt64 theAnswer = MultiplyByRatio(inHostTime, sToNanosNumerator, sToNanosDenominator); + #if CoreAudio_Debug + if(((sToNanosNumerator > sToNanosDenominator) && (theAnswer < inHostTime)) || ((sToNanosDenominator > sToNanosNumerator) && (theAnswer > inHostTime))) + { + DebugPrintf("CAHostTimeBase::ConvertToNanos: The conversion wrapped"); + } + #endif + + return theAnswer; +} + +inline UInt64 CAHostTimeBase::ConvertFromNanos(UInt64 inNanos) +{ + pthread_once(&sIsInited, Initialize); + + UInt64 theAnswer = MultiplyByRatio(inNanos, sToNanosDenominator, sToNanosNumerator); + #if CoreAudio_Debug + if(((sToNanosDenominator > sToNanosNumerator) && (theAnswer < inNanos)) || ((sToNanosNumerator > sToNanosDenominator) && (theAnswer > inNanos))) + { + DebugPrintf("CAHostTimeBase::ConvertFromNanos: The conversion wrapped"); + } + #endif + + return theAnswer; +} + +inline UInt64 CAHostTimeBase::GetCurrentTimeInNanos() +{ + return ConvertToNanos(GetTheCurrentTime()); +} + +inline UInt64 CAHostTimeBase::AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime) +{ + UInt64 theAnswer; + + if(inStartTime <= inEndTime) + { + theAnswer = inEndTime - inStartTime; + } + else + { + theAnswer = inStartTime - inEndTime; + } + + return ConvertToNanos(theAnswer); +} + +inline SInt64 CAHostTimeBase::HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime) +{ + SInt64 theAnswer; + SInt64 theSign = 1; + + if(inStartTime <= inEndTime) + { + theAnswer = static_cast(inEndTime - inStartTime); + } + else + { + theAnswer = static_cast(inStartTime - inEndTime); + theSign = -1; + } + + return theSign * static_cast(ConvertToNanos(static_cast(theAnswer))); +} + +inline UInt64 CAHostTimeBase::MultiplyByRatio(UInt64 inMuliplicand, UInt32 inNumerator, UInt32 inDenominator) +{ +#if TARGET_OS_MAC && TARGET_RT_64_BIT + __uint128_t theAnswer = inMuliplicand; +#else + long double theAnswer = inMuliplicand; +#endif + if(inNumerator != inDenominator) + { + theAnswer *= inNumerator; + theAnswer /= inDenominator; + } + return static_cast(theAnswer); +} + +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMath.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMath.h new file mode 100644 index 0000000000..d291d1f8bd --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMath.h @@ -0,0 +1,68 @@ +/* + File: CAMath.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAMath_h__ +#define __CAMath_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +inline bool fiszero(Float64 f) { return (f == 0.); } +inline bool fiszero(Float32 f) { return (f == 0.f); } + +inline bool fnonzero(Float64 f) { return !fiszero(f); } +inline bool fnonzero(Float32 f) { return !fiszero(f); } + +inline bool fequal(const Float64 &a, const Float64 &b) { return a == b; } +inline bool fequal(const Float32 &a, const Float32 &b) { return a == b; } + +inline bool fnotequal(const Float64 &a, const Float64 &b) { return !fequal(a, b); } +inline bool fnotequal(const Float32 &a, const Float32 &b) { return !fequal(a, b); } + +#endif // __CAMath_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMutex.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMutex.cpp new file mode 100644 index 0000000000..e3d3b83adf --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMutex.cpp @@ -0,0 +1,345 @@ +/* + File: CAMutex.cpp + Abstract: CAMutex.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAMutex.h" + +#if TARGET_OS_MAC + #include +#endif + +// PublicUtility Includes +#include "CADebugMacros.h" +#include "CAException.h" +#include "CAHostTimeBase.h" + +//================================================================================================== +// Logging +//================================================================================================== + +#if CoreAudio_Debug +// #define Log_Ownership 1 +// #define Log_Errors 1 +// #define Log_LongLatencies 1 +// #define LongLatencyThreshholdNS 1000000ULL // nanoseconds +#endif + +//================================================================================================== +// CAMutex +//================================================================================================== + +CAMutex::CAMutex(const char* inName) +: + mName(inName), + mOwner(0) +{ +#if TARGET_OS_MAC + OSStatus theError = pthread_mutex_init(&mMutex, NULL); + ThrowIf(theError != 0, CAException(theError), "CAMutex::CAMutex: Could not init the mutex"); + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::CAMutex: creating %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); + #endif +#elif TARGET_OS_WIN32 + mMutex = CreateMutex(NULL, false, NULL); + ThrowIfNULL(mMutex, CAException(GetLastError()), "CAMutex::CAMutex: could not create the mutex."); + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::CAMutex: creating %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); + #endif +#endif +} + +CAMutex::~CAMutex() +{ +#if TARGET_OS_MAC + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::~CAMutex: destroying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); + #endif + pthread_mutex_destroy(&mMutex); +#elif TARGET_OS_WIN32 + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::~CAMutex: destroying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); + #endif + if(mMutex != NULL) + { + CloseHandle(mMutex); + } +#endif +} + +bool CAMutex::Lock() +{ + bool theAnswer = false; + +#if TARGET_OS_MAC + pthread_t theCurrentThread = pthread_self(); + if(!pthread_equal(theCurrentThread, mOwner)) + { + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Lock: thread %p is locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); + #endif + + #if Log_LongLatencies + UInt64 lockTryTime = CAHostTimeBase::GetCurrentTimeInNanos(); + #endif + + OSStatus theError = pthread_mutex_lock(&mMutex); + ThrowIf(theError != 0, CAException(theError), "CAMutex::Lock: Could not lock the mutex"); + mOwner = theCurrentThread; + theAnswer = true; + + #if Log_LongLatencies + UInt64 lockAcquireTime = CAHostTimeBase::GetCurrentTimeInNanos(); + if (lockAcquireTime - lockTryTime >= LongLatencyThresholdNS) + DebugPrintfRtn(DebugPrintfFileComma "Thread %p took %.6fs to acquire the lock %s\n", theCurrentThread, (lockAcquireTime - lockTryTime) * 1.0e-9 /* nanos to seconds */, mName); + #endif + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Lock: thread %p has locked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + } +#elif TARGET_OS_WIN32 + if(mOwner != GetCurrentThreadId()) + { + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Lock: thread %lu is locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + OSStatus theError = WaitForSingleObject(mMutex, INFINITE); + ThrowIfError(theError, CAException(theError), "CAMutex::Lock: could not lock the mutex"); + mOwner = GetCurrentThreadId(); + theAnswer = true; + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Lock: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + } +#endif + + return theAnswer; +} + +void CAMutex::Unlock() +{ +#if TARGET_OS_MAC + if(pthread_equal(pthread_self(), mOwner)) + { + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Unlock: thread %p is unlocking %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + + mOwner = 0; + OSStatus theError = pthread_mutex_unlock(&mMutex); + ThrowIf(theError != 0, CAException(theError), "CAMutex::Unlock: Could not unlock the mutex"); + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Unlock: thread %p has unlocked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + } + else + { + DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own"); + } +#elif TARGET_OS_WIN32 + if(mOwner == GetCurrentThreadId()) + { + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Unlock: thread %lu is unlocking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + mOwner = 0; + bool wasReleased = ReleaseMutex(mMutex); + ThrowIf(!wasReleased, CAException(GetLastError()), "CAMutex::Unlock: Could not unlock the mutex"); + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Unlock: thread %lu has unlocked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + } + else + { + DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own"); + } +#endif +} + +bool CAMutex::Try(bool& outWasLocked) +{ + bool theAnswer = false; + outWasLocked = false; + +#if TARGET_OS_MAC + pthread_t theCurrentThread = pthread_self(); + if(!pthread_equal(theCurrentThread, mOwner)) + { + // this means the current thread doesn't already own the lock + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p is try-locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); + #endif + + // go ahead and call trylock to see if we can lock it. + int theError = pthread_mutex_trylock(&mMutex); + if(theError == 0) + { + // return value of 0 means we successfully locked the lock + mOwner = theCurrentThread; + theAnswer = true; + outWasLocked = true; + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p has locked %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); + #endif + } + else if(theError == EBUSY) + { + // return value of EBUSY means that the lock was already locked by another thread + theAnswer = false; + outWasLocked = false; + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p failed to lock %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); + #endif + } + else + { + // any other return value means something really bad happenned + ThrowIfError(theError, CAException(theError), "CAMutex::Try: call to pthread_mutex_trylock failed"); + } + } + else + { + // this means the current thread already owns the lock + theAnswer = true; + outWasLocked = false; + } +#elif TARGET_OS_WIN32 + if(mOwner != GetCurrentThreadId()) + { + // this means the current thread doesn't own the lock + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu is try-locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + // try to acquire the mutex + OSStatus theError = WaitForSingleObject(mMutex, 0); + if(theError == WAIT_OBJECT_0) + { + // this means we successfully locked the lock + mOwner = GetCurrentThreadId(); + theAnswer = true; + outWasLocked = true; + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + } + else if(theError == WAIT_TIMEOUT) + { + // this means that the lock was already locked by another thread + theAnswer = false; + outWasLocked = false; + + #if Log_Ownership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu failed to lock %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + } + else + { + // any other return value means something really bad happenned + ThrowIfError(theError, CAException(GetLastError()), "CAMutex::Try: call to lock the mutex failed"); + } + } + else + { + // this means the current thread already owns the lock + theAnswer = true; + outWasLocked = false; + } +#endif + + return theAnswer; +} + +bool CAMutex::IsFree() const +{ + return mOwner == 0; +} + +bool CAMutex::IsOwnedByCurrentThread() const +{ + bool theAnswer = true; + +#if TARGET_OS_MAC + theAnswer = pthread_equal(pthread_self(), mOwner); +#elif TARGET_OS_WIN32 + theAnswer = (mOwner == GetCurrentThreadId()); +#endif + + return theAnswer; +} + + +CAMutex::Unlocker::Unlocker(CAMutex& inMutex) +: mMutex(inMutex), + mNeedsLock(false) +{ + Assert(mMutex.IsOwnedByCurrentThread(), "Major problem: Unlocker attempted to unlock a mutex not owned by the current thread!"); + + mMutex.Unlock(); + mNeedsLock = true; +} + +CAMutex::Unlocker::~Unlocker() +{ + if(mNeedsLock) + { + mMutex.Lock(); + } +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMutex.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMutex.h new file mode 100644 index 0000000000..ea3681338f --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAMutex.h @@ -0,0 +1,163 @@ +/* + File: CAMutex.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAMutex_h__ +#define __CAMutex_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#if TARGET_OS_MAC + #include +#elif TARGET_OS_WIN32 + #include +#else + #error Unsupported operating system +#endif + +//================================================================================================== +// A recursive mutex. +//================================================================================================== + +class CAMutex +{ +// Construction/Destruction +public: + CAMutex(const char* inName); + virtual ~CAMutex(); + +// Actions +public: + virtual bool Lock(); + virtual void Unlock(); + virtual bool Try(bool& outWasLocked); // returns true if lock is free, false if not + + virtual bool IsFree() const; + virtual bool IsOwnedByCurrentThread() const; + +// Implementation +protected: + const char* mName; +#if TARGET_OS_MAC + pthread_t mOwner; + pthread_mutex_t mMutex; +#elif TARGET_OS_WIN32 + UInt32 mOwner; + HANDLE mMutex; +#endif + +// Helper class to manage taking and releasing recursively +public: + class Locker + { + + // Construction/Destruction + public: + Locker(CAMutex& inMutex) : mMutex(&inMutex), mNeedsRelease(false) { mNeedsRelease = mMutex->Lock(); } + Locker(CAMutex* inMutex) : mMutex(inMutex), mNeedsRelease(false) { mNeedsRelease = (mMutex != NULL && mMutex->Lock()); } + // in this case the mutex can be null + ~Locker() { if(mNeedsRelease) { mMutex->Unlock(); } } + + + private: + Locker(const Locker&); + Locker& operator=(const Locker&); + + // Implementation + private: + CAMutex* mMutex; + bool mNeedsRelease; + + }; + +// Unlocker + class Unlocker + { + public: + Unlocker(CAMutex& inMutex); + ~Unlocker(); + + private: + CAMutex& mMutex; + bool mNeedsLock; + + // Hidden definitions of copy ctor, assignment operator + Unlocker(const Unlocker& copy); // Not implemented + Unlocker& operator=(const Unlocker& copy); // Not implemented + }; + +// you can use this with Try - if you take the lock in try, pass in the outWasLocked var + class Tryer { + + // Construction/Destruction + public: + Tryer (CAMutex &mutex) : mMutex(mutex), mNeedsRelease(false), mHasLock(false) { mHasLock = mMutex.Try (mNeedsRelease); } + ~Tryer () { if (mNeedsRelease) mMutex.Unlock(); } + + bool HasLock () const { return mHasLock; } + + private: + Tryer(const Tryer&); + Tryer& operator=(const Tryer&); + + // Implementation + private: + CAMutex & mMutex; + bool mNeedsRelease; + bool mHasLock; + }; +}; + + +#endif // __CAMutex_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAReferenceCounted.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAReferenceCounted.h new file mode 100644 index 0000000000..e16c3b4603 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAReferenceCounted.h @@ -0,0 +1,97 @@ +/* + File: CAReferenceCounted.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAReferenceCounted_h__ +#define __CAReferenceCounted_h__ + +#include "CAAtomic.h" + +// base class for reference-counted objects +class CAReferenceCounted { +public: + CAReferenceCounted() : mRefCount(1) {} + + void retain() { CAAtomicIncrement32(&mRefCount); } + + void release() + { + SInt32 rc = CAAtomicDecrement32(&mRefCount); + if (rc == 0) { + releaseObject(); + } + } + + + class Retainer { + public: + Retainer(CAReferenceCounted *obj) : mObject(obj) { mObject->retain(); } + ~Retainer() { mObject->release(); } + + private: + CAReferenceCounted * mObject; + }; + +protected: + virtual ~CAReferenceCounted() { } + + virtual void releaseObject () + { + delete this; + } + +#if DEBUG +public: +#endif + SInt32 GetReferenceCount() const { return mRefCount; } +private: + SInt32 mRefCount; + + CAReferenceCounted(const CAReferenceCounted &a); + CAReferenceCounted &operator=(const CAReferenceCounted &a); +}; + + +#endif // __CAReferenceCounted_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAStreamBasicDescription.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAStreamBasicDescription.cpp new file mode 100644 index 0000000000..dc1a579107 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAStreamBasicDescription.cpp @@ -0,0 +1,879 @@ +/* + File: CAStreamBasicDescription.cpp + Abstract: CAStreamBasicDescription.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "CAStreamBasicDescription.h" +#include "CAMath.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#pragma mark This file needs to compile on earlier versions of the OS, so please keep that in mind when editing it + +char *CAStringForOSType (OSType t, char *writeLocation, size_t bufsize) +{ + if (bufsize > 0) { + char *p = writeLocation, *pend = writeLocation + bufsize; + union { UInt32 i; unsigned char str[4]; } u; + unsigned char *q = u.str; + u.i = CFSwapInt32HostToBig(t); + + bool hasNonPrint = false; + for (int i = 0; i < 4; ++i) { + if (!(isprint(*q) && *q != '\\')) { + hasNonPrint = true; + break; + } + q++; + } + q = u.str; + + if (hasNonPrint) + p += snprintf (p, pend - p, "0x"); + else if (p < pend) + *p++ = '\''; + + for (int i = 0; i < 4 && p < pend; ++i) { + if (hasNonPrint) { + p += snprintf(p, pend - p, "%02X", *q++); + } else { + *p++ = *q++; + } + } + if (!hasNonPrint && p < pend) + *p++ = '\''; + if (p >= pend) p -= 1; + *p = '\0'; + } + return writeLocation; +} + + +const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +CAStreamBasicDescription::CAStreamBasicDescription() +{ + memset (this, 0, sizeof(AudioStreamBasicDescription)); +} + +CAStreamBasicDescription::CAStreamBasicDescription(const AudioStreamBasicDescription &desc) +{ + SetFrom(desc); +} + + +CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID, + UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, + UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, + UInt32 inBitsPerChannel, UInt32 inFormatFlags) +{ + mSampleRate = inSampleRate; + mFormatID = inFormatID; + mBytesPerPacket = inBytesPerPacket; + mFramesPerPacket = inFramesPerPacket; + mBytesPerFrame = inBytesPerFrame; + mChannelsPerFrame = inChannelsPerFrame; + mBitsPerChannel = inBitsPerChannel; + mFormatFlags = inFormatFlags; + mReserved = 0; +} + +char *CAStreamBasicDescription::AsString(char *buf, size_t _bufsize, bool brief /*=false*/) const +{ + int bufsize = (int)_bufsize; // must be signed to protect against overflow + char *theBuffer = buf; + int nc; + char formatID[24]; + CAStringForOSType(mFormatID, formatID, sizeof(formatID)); + if (brief) { + CommonPCMFormat com; + bool interleaved; + if (IdentifyCommonPCMFormat(com, &interleaved) && com != kPCMFormatOther) { + const char *desc; + switch (com) { + case kPCMFormatInt16: + desc = "Int16"; + break; + case kPCMFormatFixed824: + desc = "Int8.24"; + break; + case kPCMFormatFloat32: + desc = "Float32"; + break; + case kPCMFormatFloat64: + desc = "Float64"; + break; + default: + desc = NULL; + break; + } + if (desc) { + const char *inter =""; + if (mChannelsPerFrame > 1) + inter = !interleaved ? ", non-inter" : ", inter"; + snprintf(buf, static_cast(bufsize), "%2d ch, %6.0f Hz, %s%s", (int)mChannelsPerFrame, mSampleRate, desc, inter); + return theBuffer; + } + } + if (mChannelsPerFrame == 0 && mSampleRate == 0.0 && mFormatID == 0) { + snprintf(buf, static_cast(bufsize), "%2d ch, %6.0f Hz", (int)mChannelsPerFrame, mSampleRate); + return theBuffer; + } + } + + nc = snprintf(buf, static_cast(bufsize), "%2d ch, %6.0f Hz, %s (0x%08X) ", (int)NumberChannels(), mSampleRate, formatID, (int)mFormatFlags); + buf += nc; if ((bufsize -= nc) <= 0) goto exit; + if (mFormatID == kAudioFormatLinearPCM) { + bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat); + int wordSize = static_cast(SampleWordSize()); + const char *endian = (wordSize > 1) ? + ((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : ""; + const char *sign = isInt ? + ((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : ""; + const char *floatInt = isInt ? "integer" : "float"; + char packed[32]; + if (wordSize > 0 && PackednessIsSignificant()) { + if (mFormatFlags & kLinearPCMFormatFlagIsPacked) + snprintf(packed, sizeof(packed), "packed in %d bytes", wordSize); + else + snprintf(packed, sizeof(packed), "unpacked in %d bytes", wordSize); + } else + packed[0] = '\0'; + const char *align = (wordSize > 0 && AlignmentIsSignificant()) ? + ((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : ""; + const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : ""; + const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : ""; + char bitdepth[20]; + + int fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift; + if (fracbits > 0) + snprintf(bitdepth, sizeof(bitdepth), "%d.%d", (int)mBitsPerChannel - fracbits, fracbits); + else + snprintf(bitdepth, sizeof(bitdepth), "%d", (int)mBitsPerChannel); + + /*nc =*/ snprintf(buf, static_cast(bufsize), "%s-bit%s%s %s%s%s%s%s", + bitdepth, endian, sign, floatInt, + commaSpace, packed, align, deinter); + // buf += nc; if ((bufsize -= nc) <= 0) goto exit; + } else if (mFormatID == kAudioFormatAppleLossless) { + int sourceBits = 0; + switch (mFormatFlags) + { + case 1: // kAppleLosslessFormatFlag_16BitSourceData + sourceBits = 16; + break; + case 2: // kAppleLosslessFormatFlag_20BitSourceData + sourceBits = 20; + break; + case 3: // kAppleLosslessFormatFlag_24BitSourceData + sourceBits = 24; + break; + case 4: // kAppleLosslessFormatFlag_32BitSourceData + sourceBits = 32; + break; + } + if (sourceBits) + nc = snprintf(buf, static_cast(bufsize), "from %d-bit source, ", sourceBits); + else + nc = snprintf(buf, static_cast(bufsize), "from UNKNOWN source bit depth, "); + buf += nc; if ((bufsize -= nc) <= 0) goto exit; + /*nc =*/ snprintf(buf, static_cast(bufsize), "%d frames/packet", (int)mFramesPerPacket); + // buf += nc; if ((bufsize -= nc) <= 0) goto exit; + } + else + /*nc =*/ snprintf(buf, static_cast(bufsize), "%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame", + (int)mBitsPerChannel, (int)mBytesPerPacket, (int)mFramesPerPacket, (int)mBytesPerFrame); +exit: + return theBuffer; +} + +void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription) +{ + // the only thing that changes is to make mixable linear PCM into the canonical linear PCM format + if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0)) + { + // the canonical linear PCM format + ioDescription.mFormatFlags = kAudioFormatFlagsCanonical; + ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; + ioDescription.mFramesPerPacket = 1; + ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; + ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType); + } +} + +void CAStreamBasicDescription::NormalizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription) +{ + // the only thing that changes is to make mixable linear PCM into the canonical linear PCM format + if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0)) + { + // the canonical linear PCM format + ioDescription.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked; + if(inNativeEndian) + { +#if TARGET_RT_BIG_ENDIAN + ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian; +#endif + } + else + { +#if TARGET_RT_LITTLE_ENDIAN + ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian; +#endif + } + ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; + ioDescription.mFramesPerPacket = 1; + ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame; + ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType); + } +} + +void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription) +{ + ioDescription.mSampleRate = 0; + ioDescription.mFormatID = 0; + ioDescription.mBytesPerPacket = 0; + ioDescription.mFramesPerPacket = 0; + ioDescription.mBytesPerFrame = 0; + ioDescription.mChannelsPerFrame = 0; + ioDescription.mBitsPerChannel = 0; + ioDescription.mFormatFlags = 0; +} + +void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription) +{ + if(fiszero(ioDescription.mSampleRate)) + { + ioDescription.mSampleRate = inTemplateDescription.mSampleRate; + } + if(ioDescription.mFormatID == 0) + { + ioDescription.mFormatID = inTemplateDescription.mFormatID; + } + if(ioDescription.mFormatFlags == 0) + { + ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags; + } + if(ioDescription.mBytesPerPacket == 0) + { + ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket; + } + if(ioDescription.mFramesPerPacket == 0) + { + ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket; + } + if(ioDescription.mBytesPerFrame == 0) + { + ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame; + } + if(ioDescription.mChannelsPerFrame == 0) + { + ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame; + } + if(ioDescription.mBitsPerChannel == 0) + { + ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel; + } +} + +void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate, bool inIncludeSampleRate) +{ + if(inIncludeSampleRate) + { + int theCharactersWritten = snprintf(outName, inMaxNameLength, "%.0f ", inDescription.mSampleRate); + outName += theCharactersWritten; + inMaxNameLength -= static_cast(theCharactersWritten); + } + + switch(inDescription.mFormatID) + { + case kAudioFormatLinearPCM: + { + const char* theEndianString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) + { + #if TARGET_RT_LITTLE_ENDIAN + theEndianString = "Big Endian"; + #endif + } + else + { + #if TARGET_RT_BIG_ENDIAN + theEndianString = "Little Endian"; + #endif + } + + const char* theKindString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0) + { + theKindString = (inAbbreviate ? "Float" : "Floating Point"); + } + else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0) + { + theKindString = (inAbbreviate ? "SInt" : "Signed Integer"); + } + else + { + theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer"); + } + + const char* thePackingString = NULL; + if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0) + { + if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0) + { + thePackingString = "High"; + } + else + { + thePackingString = "Low"; + } + } + + const char* theMixabilityString = NULL; + if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0) + { + theMixabilityString = "Mixable"; + } + else + { + theMixabilityString = "Unmixable"; + } + + if(inAbbreviate) + { + if(theEndianString != NULL) + { + if(thePackingString != NULL) + { + snprintf(outName, inMaxNameLength, "%s %d Ch %s %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel); + } + } + else + { + if(thePackingString != NULL) + { + snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8)); + } + else + { + snprintf(outName, inMaxNameLength, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel); + } + } + } + else + { + if(theEndianString != NULL) + { + if(thePackingString != NULL) + { + snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString); + } + } + else + { + if(thePackingString != NULL) + { + snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8); + } + else + { + snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString); + } + } + } + } + break; + + case kAudioFormatAC3: + strlcpy(outName, "AC-3", sizeof(outName)); + break; + + case kAudioFormat60958AC3: + strlcpy(outName, "AC-3 for SPDIF", sizeof(outName)); + break; + + default: + CACopy4CCToCString(outName, inDescription.mFormatID); + break; + }; +} + +#if CoreAudio_Debug +#include "CALogMacros.h" + +void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc) +{ + PrintFloat (" Sample Rate: ", inDesc.mSampleRate); + Print4CharCode (" Format ID: ", inDesc.mFormatID); + PrintHex (" Format Flags: ", inDesc.mFormatFlags); + PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket); + PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket); + PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame); + PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame); + PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel); +} +#endif + +bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + bool theAnswer = false; + bool isDone = false; + + // note that if either side is 0, that field is skipped + + // format ID is the first order sort + if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0))) + { + if(x.mFormatID != y.mFormatID) + { + // formats are sorted numerically except that linear + // PCM is always first + if(x.mFormatID == kAudioFormatLinearPCM) + { + theAnswer = true; + } + else if(y.mFormatID == kAudioFormatLinearPCM) + { + theAnswer = false; + } + else + { + theAnswer = x.mFormatID < y.mFormatID; + } + isDone = true; + } + } + + + // mixable is always better than non-mixable for linear PCM and should be the second order sort item + if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) + { + if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0)) + { + theAnswer = true; + isDone = true; + } + else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0)) + { + theAnswer = false; + isDone = true; + } + } + + // floating point vs integer for linear PCM only + if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) + { + if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat)) + { + // floating point is better than integer + theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat; + isDone = true; + } + } + + // bit depth + if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0))) + { + if(x.mBitsPerChannel != y.mBitsPerChannel) + { + // deeper bit depths are higher quality + theAnswer = x.mBitsPerChannel < y.mBitsPerChannel; + isDone = true; + } + } + + // sample rate + if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate)) + { + if(fnotequal(x.mSampleRate, y.mSampleRate)) + { + // higher sample rates are higher quality + theAnswer = x.mSampleRate < y.mSampleRate; + isDone = true; + } + } + + // number of channels + if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0))) + { + if(x.mChannelsPerFrame != y.mChannelsPerFrame) + { + // more channels is higher quality + theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame; + //isDone = true; + } + } + + return theAnswer; +} + +void CAStreamBasicDescription::ModifyFormatFlagsForMatching(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y, UInt32& xFlags, UInt32& yFlags, bool converterOnly ) +{ + // match wildcards + if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0) + { + // Obliterate all flags. + xFlags = yFlags = 0; + return; + } + + if (x.mFormatID == kAudioFormatLinearPCM) { + // knock off the all clear flag + xFlags = xFlags & ~kAudioFormatFlagsAreAllClear; + yFlags = yFlags & ~kAudioFormatFlagsAreAllClear; + + // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit. + if (xFlags & yFlags & kAudioFormatFlagIsPacked) { + xFlags = xFlags & ~static_cast(kAudioFormatFlagIsAlignedHigh); + yFlags = yFlags & ~static_cast(kAudioFormatFlagIsAlignedHigh); + } + + // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit. + if (xFlags & yFlags & kAudioFormatFlagIsFloat) { + xFlags = xFlags & ~static_cast(kAudioFormatFlagIsSignedInteger); + yFlags = yFlags & ~static_cast(kAudioFormatFlagIsSignedInteger); + } + + // if the bit depth is 8 bits or less and the format is packed, we don't care about endianness + if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + xFlags = xFlags & ~static_cast(kAudioFormatFlagIsBigEndian); + } + if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked)) + { + yFlags = yFlags & ~static_cast(kAudioFormatFlagIsBigEndian); + } + + // if the number of channels is 1, we don't care about non-interleavedness + if (x.mChannelsPerFrame == 1 && y.mChannelsPerFrame == 1) { + xFlags &= ~static_cast(kLinearPCMFormatFlagIsNonInterleaved); + yFlags &= ~static_cast(kLinearPCMFormatFlagIsNonInterleaved); + } + + if (converterOnly) { + CAStreamBasicDescription cas_x = CAStreamBasicDescription(x); + CAStreamBasicDescription cas_y = CAStreamBasicDescription(y); + if (!cas_x.PackednessIsSignificant() && !cas_y.PackednessIsSignificant()) { + xFlags &= ~static_cast(kAudioFormatFlagIsPacked); + yFlags &= ~static_cast(kAudioFormatFlagIsPacked); + } + if (!cas_x.AlignmentIsSignificant() && !cas_y.AlignmentIsSignificant()) { + xFlags &= ~static_cast(kAudioFormatFlagIsAlignedHigh); + yFlags &= ~static_cast(kAudioFormatFlagIsAlignedHigh); + } + // We don't care about whether the streams are mixable in this case + xFlags &= ~static_cast(kAudioFormatFlagIsNonMixable); + yFlags &= ~static_cast(kAudioFormatFlagIsNonMixable); + } + } +} + +static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + UInt32 xFlags = x.mFormatFlags; + UInt32 yFlags = y.mFormatFlags; + + CAStreamBasicDescription::ModifyFormatFlagsForMatching(x, y, xFlags, yFlags, false); + return xFlags == yFlags; +} + +bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) +{ + // the semantics for equality are: + // 1) Values must match exactly -- except for PCM format flags, see above. + // 2) wildcard's are ignored in the comparison + +#define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name)) + + return + // check all but the format flags + CAStreamBasicDescription::FlagIndependentEquivalence(x, y) + // check the format flags + && MatchFormatFlags(x, y); +} + +bool CAStreamBasicDescription::FlagIndependentEquivalence(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y) +{ + return + // check the sample rate + (fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate)) + + // check the format ids + && MATCH(mFormatID) + + // check the bytes per packet + && MATCH(mBytesPerPacket) + + // check the frames per packet + && MATCH(mFramesPerPacket) + + // check the bytes per frame + && MATCH(mBytesPerFrame) + + // check the channels per frame + && MATCH(mChannelsPerFrame) + + // check the channels per frame + && MATCH(mBitsPerChannel) ; +} + +bool CAStreamBasicDescription::IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards) const +{ + if (interpretingWildcards) + return *this == other; + return memcmp(this, &other, offsetof(AudioStreamBasicDescription, mReserved)) == 0; +} + +bool CAStreamBasicDescription::IsFunctionallyEquivalent(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y) +{ + UInt32 xFlags = x.mFormatFlags, yFlags = y.mFormatFlags; + CAStreamBasicDescription::ModifyFormatFlagsForMatching(x, y, xFlags, yFlags, true); + + return + // check all but the format flags + CAStreamBasicDescription::FlagIndependentEquivalence(x, y) + // check the format flags with converter focus + && (xFlags == yFlags); + +} + +bool SanityCheck(const AudioStreamBasicDescription& x) +{ + // This function returns false if there are sufficiently insane values in any field. + // It is very conservative so even some very unlikely values will pass. + // This is just meant to catch the case where the data from a file is corrupted. + + return + (x.mSampleRate >= 0.) + && (x.mSampleRate < 3e6) // SACD sample rate is 2.8224 MHz + && (x.mBytesPerPacket < 1000000) + && (x.mFramesPerPacket < 1000000) + && (x.mBytesPerFrame < 1000000) + && (x.mChannelsPerFrame <= 1024) + && (x.mBitsPerChannel <= 1024) + && (x.mFormatID != 0) + && !(x.mFormatID == kAudioFormatLinearPCM && (x.mFramesPerPacket != 1 || x.mBytesPerPacket != x.mBytesPerFrame)); +} + +bool CAStreamBasicDescription::FromText(const char *inTextDesc, AudioStreamBasicDescription &fmt) +{ + const char *p = inTextDesc; + + memset(&fmt, 0, sizeof(fmt)); + + bool isPCM = true; // until proven otherwise + UInt32 pcmFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; + + if (p[0] == '-') // previously we required a leading dash on PCM formats + ++p; + + if (p[0] == 'B' && p[1] == 'E') { + pcmFlags |= kLinearPCMFormatFlagIsBigEndian; + p += 2; + } else if (p[0] == 'L' && p[1] == 'E') { + p += 2; + } else { + // default is native-endian +#if TARGET_RT_BIG_ENDIAN + pcmFlags |= kLinearPCMFormatFlagIsBigEndian; +#endif + } + if (p[0] == 'F') { + pcmFlags = (pcmFlags & ~static_cast(kAudioFormatFlagIsSignedInteger)) | kAudioFormatFlagIsFloat; + ++p; + } else { + if (p[0] == 'U') { + pcmFlags &= ~static_cast(kAudioFormatFlagIsSignedInteger); + ++p; + } + if (p[0] == 'I') + ++p; + else { + // it's not PCM; presumably some other format (NOT VALIDATED; use AudioFormat for that) + isPCM = false; + p = inTextDesc; // go back to the beginning + char buf[4] = { ' ',' ',' ',' ' }; + for (int i = 0; i < 4; ++i) { + if (*p != '\\') { + if ((buf[i] = *p++) == '\0') { + // special-case for 'aac' + if (i != 3) return false; + --p; // keep pointing at the terminating null + buf[i] = ' '; + break; + } + } else { + // "\xNN" is a hex byte + if (*++p != 'x') return false; + int x; + if (sscanf(++p, "%02X", &x) != 1) return false; + buf[i] = static_cast(x); + p += 2; + } + } + + if (strchr("-@/#", buf[3])) { + // further special-casing for 'aac' + buf[3] = ' '; + --p; + } + + memcpy(&fmt.mFormatID, buf, 4); + fmt.mFormatID = CFSwapInt32BigToHost(fmt.mFormatID); + } + } + + if (isPCM) { + fmt.mFormatID = kAudioFormatLinearPCM; + fmt.mFormatFlags = pcmFlags; + fmt.mFramesPerPacket = 1; + fmt.mChannelsPerFrame = 1; + UInt32 bitdepth = 0, fracbits = 0; + while (isdigit(*p)) + bitdepth = 10 * bitdepth + static_cast(*p++ - '0'); + if (*p == '.') { + ++p; + if (!isdigit(*p)) { + fprintf(stderr, "Expected fractional bits following '.'\n"); + goto Bail; + } + while (isdigit(*p)) + fracbits = 10 * fracbits + static_cast(*p++ - '0'); + bitdepth += fracbits; + fmt.mFormatFlags |= (fracbits << kLinearPCMFormatFlagsSampleFractionShift); + } + fmt.mBitsPerChannel = bitdepth; + fmt.mBytesPerPacket = fmt.mBytesPerFrame = (bitdepth + 7) / 8; + if (bitdepth & 7) { + // assume unpacked. (packed odd bit depths are describable but not supported in AudioConverter.) + fmt.mFormatFlags &= ~static_cast(kLinearPCMFormatFlagIsPacked); + // alignment matters; default to high-aligned. use ':L_' for low. + fmt.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh; + } + } + if (*p == '@') { + ++p; + while (isdigit(*p)) + fmt.mSampleRate = 10 * fmt.mSampleRate + (*p++ - '0'); + } + if (*p == '/') { + UInt32 flags = 0; + while (true) { + char c = *++p; + if (c >= '0' && c <= '9') + flags = (flags << 4) | static_cast(c - '0'); + else if (c >= 'A' && c <= 'F') + flags = (flags << 4) | static_cast(c - 'A' + 10); + else if (c >= 'a' && c <= 'f') + flags = (flags << 4) | static_cast(c - 'a' + 10); + else break; + } + fmt.mFormatFlags = flags; + } + if (*p == '#') { + ++p; + while (isdigit(*p)) + fmt.mFramesPerPacket = 10 * fmt.mFramesPerPacket + static_cast(*p++ - '0'); + } + if (*p == ':') { + ++p; + fmt.mFormatFlags &= ~static_cast(kLinearPCMFormatFlagIsPacked); + if (*p == 'L') + fmt.mFormatFlags &= ~static_cast(kLinearPCMFormatFlagIsAlignedHigh); + else if (*p == 'H') + fmt.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh; + else + goto Bail; + ++p; + UInt32 bytesPerFrame = 0; + while (isdigit(*p)) + bytesPerFrame = 10 * bytesPerFrame + static_cast(*p++ - '0'); + fmt.mBytesPerFrame = fmt.mBytesPerPacket = bytesPerFrame; + } + if (*p == ',') { + ++p; + int ch = 0; + while (isdigit(*p)) + ch = 10 * ch + (*p++ - '0'); + fmt.mChannelsPerFrame = static_cast(ch); + if (*p == 'D') { + ++p; + if (fmt.mFormatID != kAudioFormatLinearPCM) { + fprintf(stderr, "non-interleaved flag invalid for non-PCM formats\n"); + goto Bail; + } + fmt.mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } else { + if (*p == 'I') ++p; // default + if (fmt.mFormatID == kAudioFormatLinearPCM) + fmt.mBytesPerPacket = fmt.mBytesPerFrame *= static_cast(ch); + } + } + if (*p != '\0') { + fprintf(stderr, "extra characters at end of format string: %s\n", p); + goto Bail; + } + return true; + +Bail: + fprintf(stderr, "Invalid format string: %s\n", inTextDesc); + fprintf(stderr, "Syntax of format strings is: \n"); + return false; +} + +const char *CAStreamBasicDescription::sTextParsingUsageString = + "format[@sample_rate_hz][/format_flags][#frames_per_packet][:LHbytesPerFrame][,channelsDI].\n" + "Format for PCM is [-][BE|LE]{F|I|UI}{bitdepth}; else a 4-char format code (e.g. aac, alac).\n"; diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAStreamBasicDescription.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAStreamBasicDescription.h new file mode 100644 index 0000000000..d80dbfbf30 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAStreamBasicDescription.h @@ -0,0 +1,424 @@ +/* + File: CAStreamBasicDescription.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAStreamBasicDescription_h__ +#define __CAStreamBasicDescription_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include "CoreAudioTypes.h" + #include "CoreFoundation.h" +#endif + +#include "CADebugMacros.h" +#include // for memset, memcpy +#include // for FILE * + +#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it + +extern char *CAStringForOSType (OSType t, char *writeLocation, size_t bufsize); + +// define Leopard specific symbols for backward compatibility if applicable +#if COREAUDIOTYPES_VERSION < 1050 +typedef Float32 AudioSampleType; +enum { kAudioFormatFlagsCanonical = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked }; +#endif +#if COREAUDIOTYPES_VERSION < 1051 +typedef Float32 AudioUnitSampleType; +enum { + kLinearPCMFormatFlagsSampleFractionShift = 7, + kLinearPCMFormatFlagsSampleFractionMask = (0x3F << kLinearPCMFormatFlagsSampleFractionShift), +}; +#endif + +// define the IsMixable format flag for all versions of the system +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) + enum { kIsNonMixableFlag = kAudioFormatFlagIsNonMixable }; +#else + enum { kIsNonMixableFlag = (1L << 6) }; +#endif + +//============================================================================= +// CAStreamBasicDescription +// +// This is a wrapper class for the AudioStreamBasicDescription struct. +// It adds a number of convenience routines, but otherwise adds nothing +// to the footprint of the original struct. +//============================================================================= +class CAStreamBasicDescription : + public AudioStreamBasicDescription +{ + +// Constants +public: + static const AudioStreamBasicDescription sEmpty; + + enum CommonPCMFormat { + kPCMFormatOther = 0, + kPCMFormatFloat32 = 1, + kPCMFormatInt16 = 2, + kPCMFormatFixed824 = 3, + kPCMFormatFloat64 = 4 + }; + +// Construction/Destruction +public: + CAStreamBasicDescription(); + + CAStreamBasicDescription(const AudioStreamBasicDescription &desc); + + CAStreamBasicDescription( double inSampleRate, UInt32 inFormatID, + UInt32 inBytesPerPacket, UInt32 inFramesPerPacket, + UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame, + UInt32 inBitsPerChannel, UInt32 inFormatFlags); + + CAStreamBasicDescription( double inSampleRate, UInt32 inNumChannels, CommonPCMFormat pcmf, bool inIsInterleaved) { + unsigned wordsize; + + mSampleRate = inSampleRate; + mFormatID = kAudioFormatLinearPCM; + mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + mFramesPerPacket = 1; + mChannelsPerFrame = inNumChannels; + mBytesPerFrame = mBytesPerPacket = 0; + mReserved = 0; + + switch (pcmf) { + default: + return; + case kPCMFormatFloat32: + wordsize = 4; + mFormatFlags |= kAudioFormatFlagIsFloat; + break; + case kPCMFormatFloat64: + wordsize = 8; + mFormatFlags |= kAudioFormatFlagIsFloat; + break; + case kPCMFormatInt16: + wordsize = 2; + mFormatFlags |= kAudioFormatFlagIsSignedInteger; + break; + case kPCMFormatFixed824: + wordsize = 4; + mFormatFlags |= kAudioFormatFlagIsSignedInteger | (24 << kLinearPCMFormatFlagsSampleFractionShift); + break; + } + mBitsPerChannel = wordsize * 8; + if (inIsInterleaved) + mBytesPerFrame = mBytesPerPacket = wordsize * inNumChannels; + else { + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + mBytesPerFrame = mBytesPerPacket = wordsize; + } + } + +// Assignment + CAStreamBasicDescription& operator=(const AudioStreamBasicDescription& v) { SetFrom(v); return *this; } + + void SetFrom(const AudioStreamBasicDescription &desc) + { + memcpy(this, &desc, sizeof(AudioStreamBasicDescription)); + } + + bool FromText(const char *inTextDesc) { return FromText(inTextDesc, *this); } + static bool FromText(const char *inTextDesc, AudioStreamBasicDescription &outDesc); + // return true if parsing was successful + + static const char *sTextParsingUsageString; + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // interrogation + + bool IsPCM() const { return mFormatID == kAudioFormatLinearPCM; } + + bool PackednessIsSignificant() const + { + Assert(IsPCM(), "PackednessIsSignificant only applies for PCM"); + return (SampleWordSize() << 3) != mBitsPerChannel; + } + + bool AlignmentIsSignificant() const + { + return PackednessIsSignificant() || (mBitsPerChannel & 7) != 0; + } + + bool IsInterleaved() const + { + return !(mFormatFlags & kAudioFormatFlagIsNonInterleaved); + } + + bool IsSignedInteger() const + { + return IsPCM() && (mFormatFlags & kAudioFormatFlagIsSignedInteger); + } + + bool IsFloat() const + { + return IsPCM() && (mFormatFlags & kAudioFormatFlagIsFloat); + } + + bool IsNativeEndian() const + { + return (mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian; + } + + // for sanity with interleaved/deinterleaved possibilities, never access mChannelsPerFrame, use these: + UInt32 NumberInterleavedChannels() const { return IsInterleaved() ? mChannelsPerFrame : 1; } + UInt32 NumberChannelStreams() const { return IsInterleaved() ? 1 : mChannelsPerFrame; } + UInt32 NumberChannels() const { return mChannelsPerFrame; } + UInt32 SampleWordSize() const { + return (mBytesPerFrame > 0 && NumberInterleavedChannels()) ? mBytesPerFrame / NumberInterleavedChannels() : 0; + } + + UInt32 FramesToBytes(UInt32 nframes) const { return nframes * mBytesPerFrame; } + UInt32 BytesToFrames(UInt32 nbytes) const { + Assert(mBytesPerFrame > 0, "bytesPerFrame must be > 0 in BytesToFrames"); + return nbytes / mBytesPerFrame; + } + + bool SameChannelsAndInterleaving(const CAStreamBasicDescription &a) const + { + return this->NumberChannels() == a.NumberChannels() && this->IsInterleaved() == a.IsInterleaved(); + } + + bool IdentifyCommonPCMFormat(CommonPCMFormat &outFormat, bool *outIsInterleaved=NULL) const + { // return true if it's a valid PCM format. + + outFormat = kPCMFormatOther; + // trap out patently invalid formats. + if (mFormatID != kAudioFormatLinearPCM || mFramesPerPacket != 1 || mBytesPerFrame != mBytesPerPacket || mBitsPerChannel/8 > mBytesPerFrame || mChannelsPerFrame == 0) + return false; + bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + if (outIsInterleaved != NULL) *outIsInterleaved = interleaved; + unsigned wordsize = mBytesPerFrame; + if (interleaved) { + if (wordsize % mChannelsPerFrame != 0) return false; + wordsize /= mChannelsPerFrame; + } + + if ((mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian + && wordsize * 8 == mBitsPerChannel) { + // packed and native endian, good + if (mFormatFlags & kLinearPCMFormatFlagIsFloat) { + // float: reject nonsense bits + if (mFormatFlags & (kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagsSampleFractionMask)) + return false; + if (wordsize == 4) + outFormat = kPCMFormatFloat32; + if (wordsize == 8) + outFormat = kPCMFormatFloat64; + } else if (mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) { + // signed int + unsigned fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift; + if (wordsize == 4 && fracbits == 24) + outFormat = kPCMFormatFixed824; + else if (wordsize == 2 && fracbits == 0) + outFormat = kPCMFormatInt16; + } + } + return true; + } + + bool IsCommonFloat32(bool *outIsInterleaved=NULL) const { + CommonPCMFormat fmt; + return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFloat32; + } + bool IsCommonFloat64(bool *outIsInterleaved=NULL) const { + CommonPCMFormat fmt; + return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFloat64; + } + bool IsCommonFixed824(bool *outIsInterleaved=NULL) const { + CommonPCMFormat fmt; + return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFixed824; + } + bool IsCommonInt16(bool *outIsInterleaved=NULL) const { + CommonPCMFormat fmt; + return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatInt16; + } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // manipulation + + void SetCanonical(UInt32 nChannels, bool interleaved) + // note: leaves sample rate untouched + { + mFormatID = kAudioFormatLinearPCM; + UInt32 sampleSize = SizeOf32(AudioSampleType); + mFormatFlags = kAudioFormatFlagsCanonical; + mBitsPerChannel = 8 * sampleSize; + mChannelsPerFrame = nChannels; + mFramesPerPacket = 1; + if (interleaved) + mBytesPerPacket = mBytesPerFrame = nChannels * sampleSize; + else { + mBytesPerPacket = mBytesPerFrame = sampleSize; + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } + } + + bool IsCanonical() const + { + if (mFormatID != kAudioFormatLinearPCM) return false; + UInt32 reqFormatFlags; + UInt32 flagsMask = (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagsSampleFractionMask); + bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + unsigned sampleSize = SizeOf32(AudioSampleType); + reqFormatFlags = kAudioFormatFlagsCanonical; + UInt32 reqFrameSize = interleaved ? (mChannelsPerFrame * sampleSize) : sampleSize; + + return ((mFormatFlags & flagsMask) == reqFormatFlags + && mBitsPerChannel == 8 * sampleSize + && mFramesPerPacket == 1 + && mBytesPerFrame == reqFrameSize + && mBytesPerPacket == reqFrameSize); + } + + void SetAUCanonical(UInt32 nChannels, bool interleaved) + { + mFormatID = kAudioFormatLinearPCM; +#if CA_PREFER_FIXED_POINT + mFormatFlags = kAudioFormatFlagsCanonical | (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift); +#else + mFormatFlags = kAudioFormatFlagsCanonical; +#endif + mChannelsPerFrame = nChannels; + mFramesPerPacket = 1; + mBitsPerChannel = 8 * SizeOf32(AudioUnitSampleType); + if (interleaved) + mBytesPerPacket = mBytesPerFrame = nChannels * SizeOf32(AudioUnitSampleType); + else { + mBytesPerPacket = mBytesPerFrame = SizeOf32(AudioUnitSampleType); + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } + } + + void ChangeNumberChannels(UInt32 nChannels, bool interleaved) + // alter an existing format + { + Assert(IsPCM(), "ChangeNumberChannels only works for PCM formats"); + UInt32 wordSize = SampleWordSize(); // get this before changing ANYTHING + if (wordSize == 0) + wordSize = (mBitsPerChannel + 7) / 8; + mChannelsPerFrame = nChannels; + mFramesPerPacket = 1; + if (interleaved) { + mBytesPerPacket = mBytesPerFrame = nChannels * wordSize; + mFormatFlags &= ~static_cast(kAudioFormatFlagIsNonInterleaved); + } else { + mBytesPerPacket = mBytesPerFrame = wordSize; + mFormatFlags |= kAudioFormatFlagIsNonInterleaved; + } + } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // other + + bool IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards=true) const; + static bool FlagIndependentEquivalence(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y); + static bool IsFunctionallyEquivalent(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y); + + void Print() const { + Print (stdout); + } + + void Print(FILE* file) const { + PrintFormat (file, "", "AudioStreamBasicDescription:"); + } + + void PrintFormat(FILE *f, const char *indent, const char *name) const { + char buf[256]; + fprintf(f, "%s%s %s\n", indent, name, AsString(buf, sizeof(buf))); + } + + void PrintFormat2(FILE *f, const char *indent, const char *name) const { // no trailing newline + char buf[256]; + fprintf(f, "%s%s %s", indent, name, AsString(buf, sizeof(buf))); + } + + char * AsString(char *buf, size_t bufsize, bool brief=false) const; + + static void Print (const AudioStreamBasicDescription &inDesc) + { + CAStreamBasicDescription desc(inDesc); + desc.Print (); + } + + OSStatus Save(CFPropertyListRef *outData) const; + + OSStatus Restore(CFPropertyListRef &inData); + +// Operations + static bool IsMixable(const AudioStreamBasicDescription& inDescription) { return (inDescription.mFormatID == kAudioFormatLinearPCM) && ((inDescription.mFormatFlags & kIsNonMixableFlag) == 0); } + static void NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription); + static void NormalizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription); + static void ResetFormat(AudioStreamBasicDescription& ioDescription); + static void FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription); + static void GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate, bool inIncludeSampleRate = false); + static void ModifyFormatFlagsForMatching(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y, UInt32& xFlags, UInt32& yFlags, bool converterOnly); + +#if CoreAudio_Debug + static void PrintToLog(const AudioStreamBasicDescription& inDesc); +#endif +}; + +bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); +bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y); +#if TARGET_OS_MAC || (TARGET_OS_WIN32 && (_MSC_VER > 600)) +inline bool operator!=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x == y); } +inline bool operator<=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return (x < y) || (x == y); } +inline bool operator>=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x < y); } +inline bool operator>(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !((x < y) || (x == y)); } +#endif + +bool SanityCheck(const AudioStreamBasicDescription& x); + + +#endif // __CAStreamBasicDescription_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAThreadSafeList.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAThreadSafeList.h new file mode 100644 index 0000000000..479f519f61 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAThreadSafeList.h @@ -0,0 +1,233 @@ +/* + File: CAThreadSafeList.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAThreadSafeList_h__ +#define __CAThreadSafeList_h__ + +#include "CAAtomicStack.h" + +// linked list of T's +// T must define operator == +template +class TThreadSafeList { +private: + enum EEventType { kAdd, kRemove, kClear }; + class Node { + public: + Node * mNext; + EEventType mEventType; + T mObject; + + Node *& next() { return mNext; } + }; + +public: + class iterator { + public: + iterator() { } + iterator(Node *n) : mNode(n) { } + + bool operator == (const iterator &other) const { return this->mNode == other.mNode; } + bool operator != (const iterator &other) const { return this->mNode != other.mNode; } + + T & operator * () const { return mNode->mObject; } + + iterator & operator ++ () { mNode = mNode->next(); return *this; } // preincrement + iterator operator ++ (int) { iterator tmp = *this; mNode = mNode->next(); return tmp; } // postincrement + + private: + Node * mNode; + }; + + TThreadSafeList() { } + ~TThreadSafeList() + { + mActiveList.free_all(); + mPendingList.free_all(); + mFreeList.free_all(); + } + + // These may be called on any thread + + void deferred_add(const T &obj) // can be called on any thread + { + Node *node = AllocNode(); + node->mEventType = kAdd; + node->mObject = obj; + mPendingList.push_atomic(node); + //mPendingList.dump("pending after add"); + } + + void deferred_remove(const T &obj) // can be called on any thread + { + Node *node = AllocNode(); + node->mEventType = kRemove; + node->mObject = obj; + mPendingList.push_atomic(node); + //mPendingList.dump("pending after remove"); + } + + void deferred_clear() // can be called on any thread + { + Node *node = AllocNode(); + node->mEventType = kClear; + mPendingList.push_atomic(node); + } + + // These must be called from only one thread + + void update() // must only be called from one thread + { + NodeStack reversed; + Node *event, *node, *next; + bool workDone = false; + + // reverse the events so they are in order + event = mPendingList.pop_all(); + while (event != NULL) { + next = event->mNext; + reversed.push_NA(event); + event = next; + workDone = true; + } + if (workDone) { + //reversed.dump("pending popped"); + //mActiveList.dump("active before update"); + + // now process them + while ((event = reversed.pop_NA()) != NULL) { + switch (event->mEventType) { + case kAdd: + { + Node **pnode; + bool needToInsert = true; + for (pnode = mActiveList.phead(); *pnode != NULL; pnode = &node->mNext) { + node = *pnode; + if (node->mObject == event->mObject) { + //printf("already active!!!\n"); + FreeNode(event); + needToInsert = false; + break; + } + } + if (needToInsert) { + // link the new event in at the end of the active list + *pnode = event; + event->mNext = NULL; + } + } + break; + case kRemove: + // find matching node in the active list, remove it + for (Node **pnode = mActiveList.phead(); *pnode != NULL; ) { + node = *pnode; + if (node->mObject == event->mObject) { + *pnode = node->mNext; // remove from linked list + FreeNode(node); + break; + } + pnode = &node->mNext; + } + // dispose the request node + FreeNode(event); + break; + case kClear: + for (node = mActiveList.head(); node != NULL; ) { + next = node->mNext; + FreeNode(node); + node = next; + } + FreeNode(event); + break; + default: + //printf("invalid node type %d!\n", event->mEventType); + break; + } + } + //mActiveList.dump("active after update"); + } + } + + iterator begin() const { + //mActiveList.dump("active at begin"); + return iterator(mActiveList.head()); + } + iterator end() const { return iterator(NULL); } + + +private: + Node * AllocNode() + { + Node *node = mFreeList.pop_atomic(); + if (node == NULL) + node = (Node *)CA_malloc(sizeof(Node)); + return node; + } + + void FreeNode(Node *node) + { + mFreeList.push_atomic(node); + } + +private: + class NodeStack : public TAtomicStack { + public: + void free_all() { + Node *node; + while ((node = this->pop_NA()) != NULL) + free(node); + } + + Node ** phead() { return &this->mHead; } + Node * head() const { return this->mHead; } + }; + + NodeStack mActiveList; // what's actually in the container - only accessed on one thread + NodeStack mPendingList; // add or remove requests - threadsafe + NodeStack mFreeList; // free nodes for reuse - threadsafe +}; + +#endif // __CAThreadSafeList_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnit.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnit.cpp new file mode 100644 index 0000000000..9b651cd16b --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnit.cpp @@ -0,0 +1,194 @@ +/* + File: CAVectorUnit.cpp + Abstract: CAVectorUnit.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "CAVectorUnit.h" + +#if !TARGET_OS_WIN32 + #include +#elif HAS_IPP + #include "ippdefs.h" + #include "ippcore.h" +#endif + +int gCAVectorUnitType = kVecUninitialized; + +#if TARGET_OS_WIN32 +// Use cpuid to check if SSE2 is available. +// Before calling this function make sure cpuid is available +static SInt32 IsSSE2Available() +{ + int return_value; + + { + int r_edx; + _asm + { + mov eax, 0x01 + cpuid + mov r_edx, edx + } + return_value = (r_edx >> 26) & 0x1; + } + return return_value; +} + +// Use cpuid to check if SSE3 is available. +// Before calling this function make sure cpuid is available +static SInt32 IsSSE3Available() +{ + SInt32 return_value; + + { + SInt32 r_ecx; + _asm + { + mov eax, 0x01 + cpuid + mov r_ecx, ecx + } + return_value = r_ecx & 0x1; + } + return return_value; +} + +// Return true if the cpuid instruction is available. +// The cpuid instruction is available if bit 21 in the EFLAGS register can be changed +// This function may not work on Intel CPUs prior to Pentium (didn't test) +static bool IsCpuidAvailable() +{ + SInt32 return_value = 0x0; + _asm{ + pushfd ; //push original EFLAGS + pop eax ; //get original EFLAGS + mov ecx, eax ; //save original EFLAGS + xor eax, 200000h ; //flip ID bit in EFLAGS + push eax ; //save new EFLAGS value on stack + popfd ; //replace current EFLAGS value + pushfd ; //get new EFLAGS + pop eax ; //store new EFLAGS in EAX + xor eax, ecx ; + je end_cpuid_identify ; //can't toggle ID bit + mov return_value, 0x1; +end_cpuid_identify: + nop; + } + return return_value; +} + +#endif + +SInt32 CAVectorUnit_Examine() +{ + int result = kVecNone; + +#if TARGET_OS_WIN32 +#if HAS_IPP + // Initialize the static IPP library! This needs to be done before + // any IPP function calls, otherwise we may have a performance penalty + int status = ippStaticInit(); + if ( status == ippStsNonIntelCpu ) + { + IppCpuType cpuType = ippGetCpuType(); + if ( cpuType >= ippCpuSSE || cpuType <= ippCpuSSE42 ) + ippStaticInitCpu( cpuType ); + } +#endif + { + // On Windows we use cpuid to detect the vector unit because it works on Intel and AMD. + // The IPP library does not detect SSE on AMD processors. + if (IsCpuidAvailable()) + { + if(IsSSE3Available()) + { + result = kVecSSE3; + } + else if(IsSSE2Available()) + { + result = kVecSSE2; + } + } + } +#elif TARGET_OS_MAC +#if DEBUG + if (getenv("CA_NoVector")) { + fprintf(stderr, "CA_NoVector set; Vector unit optimized routines will be bypassed\n"); + return result; + } + else +#endif + { + #if (TARGET_CPU_PPC || TARGET_CPU_PPC64) + int sels[2] = { CTL_HW, HW_VECTORUNIT }; + int vType = 0; //0 == scalar only + size_t length = sizeof(vType); + int error = sysctl(sels, 2, &vType, &length, NULL, 0); + if (!error && vType > 0) + result = kVecAltivec; + #elif (TARGET_CPU_X86 || TARGET_CPU_X86_64) + static const struct { const char* kName; const int kVectype; } kStringVectypes[] = { + { "hw.optional.avx1_0", kVecAVX1 }, { "hw.optional.sse3", kVecSSE3 }, { "hw.optional.sse2", kVecSSE2 } + }; + static const size_t kNumStringVectypes = sizeof(kStringVectypes)/sizeof(kStringVectypes[0]); + int i = 0, answer = 0; + while(i != kNumStringVectypes) + { + size_t length = sizeof(answer); + int error = sysctlbyname(kStringVectypes[i].kName, &answer, &length, NULL, 0); + if (!error && answer) + { + result = kStringVectypes[i].kVectype; + break; + } + ++i; + }; + #elif CA_ARM_NEON + result = kVecNeon; + #endif + } +#endif + gCAVectorUnitType = result; + return result; +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnit.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnit.h new file mode 100644 index 0000000000..6693392a3d --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnit.h @@ -0,0 +1,101 @@ +/* + File: CAVectorUnit.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAVectorUnit_h__ +#define __CAVectorUnit_h__ + +#include +#include "CAVectorUnitTypes.h" +#include +#include + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include "CFBase.h" +#endif + +// Unify checks for vector units. +// Allow setting an environment variable "CA_NoVector" to turn off vectorized code at runtime (very useful for performance testing). + +extern int gCAVectorUnitType; + +#ifdef __cplusplus +extern "C" { +#endif + +extern SInt32 CAVectorUnit_Examine(); // expensive. use GetType() for lazy initialization and caching. + +static inline SInt32 CAVectorUnit_GetType() +{ + int x = gCAVectorUnitType; + return (x != kVecUninitialized) ? x : CAVectorUnit_Examine(); +} + +static inline Boolean CAVectorUnit_HasVectorUnit() +{ + return CAVectorUnit_GetType() > kVecNone; +} + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +class CAVectorUnit { +public: + static SInt32 GetVectorUnitType() { return CAVectorUnit_GetType(); } + static bool HasVectorUnit() { return GetVectorUnitType() > kVecNone; } + static bool HasAltivec() { return GetVectorUnitType() == kVecAltivec; } + static bool HasSSE2() { return GetVectorUnitType() >= kVecSSE2; } + static bool HasSSE3() { return GetVectorUnitType() >= kVecSSE3; } + static bool HasAVX1() { return GetVectorUnitType() >= kVecAVX1; } + static bool HasNeon() { return GetVectorUnitType() == kVecNeon; } +}; +#endif + +#endif // __CAVectorUnit_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnitTypes.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnitTypes.h new file mode 100644 index 0000000000..5181f602ed --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAVectorUnitTypes.h @@ -0,0 +1,60 @@ +/* + File: CAVectorUnitTypes.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAVectorUnitTypes_h__ +#define __CAVectorUnitTypes_h__ + +enum { + kVecUninitialized = -1, + kVecNone = 0, + kVecAltivec = 1, + kVecSSE2 = 100, + kVecSSE3 = 101, + kVecAVX1 = 110, + kVecNeon = 200 +}; + +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAXException.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAXException.h new file mode 100644 index 0000000000..4027cb8822 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CAXException.h @@ -0,0 +1,361 @@ +/* + File: CAXException.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CAXException_h__ +#define __CAXException_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include + #include +#endif +#include "CADebugMacros.h" +#include +//#include +#include + + +class CAX4CCString { +public: + CAX4CCString(OSStatus error) { + // see if it appears to be a 4-char-code + UInt32 beErr = CFSwapInt32HostToBig(error); + char *str = mStr; + memcpy(str + 1, &beErr, 4); + if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) { + str[0] = str[5] = '\''; + str[6] = '\0'; + } else if (error > -200000 && error < 200000) + // no, format it as an integer + snprintf(str, sizeof(mStr), "%d", (int)error); + else + snprintf(str, sizeof(mStr), "0x%x", (int)error); + } + const char *get() const { return mStr; } + operator const char *() const { return mStr; } +private: + char mStr[16]; +}; + +class CAX4CCStringNoQuote { +public: + CAX4CCStringNoQuote(OSStatus error) { + // see if it appears to be a 4-char-code + UInt32 beErr = CFSwapInt32HostToBig(error); + char *str = mStr; + memcpy(str, &beErr, 4); + if (isprint(str[0]) && isprint(str[1]) && isprint(str[2]) && isprint(str[3])) { + str[4] = '\0'; + } else if (error > -200000 && error < 200000) + // no, format it as an integer + snprintf(str, sizeof(mStr), "%d", (int)error); + else + snprintf(str, sizeof(mStr), "0x%x", (int)error); + } + const char *get() const { return mStr; } + operator const char *() const { return mStr; } +private: + char mStr[16]; +}; + + +// An extended exception class that includes the name of the failed operation +class CAXException { +public: + CAXException(const char *operation, OSStatus err) : + mError(err) + { + if (operation == NULL) + mOperation[0] = '\0'; + else if (strlen(operation) >= sizeof(mOperation)) { + memcpy(mOperation, operation, sizeof(mOperation) - 1); + mOperation[sizeof(mOperation) - 1] = '\0'; + } else + + strlcpy(mOperation, operation, sizeof(mOperation)); + } + + char *FormatError(char *str, size_t strsize) const + { + return FormatError(str, strsize, mError); + } + + char mOperation[256]; + const OSStatus mError; + + // ------------------------------------------------- + + typedef void (*WarningHandler)(const char *msg, OSStatus err); + + static char *FormatError(char *str, size_t strsize, OSStatus error) + { + strlcpy(str, CAX4CCString(error), strsize); + return str; + } + + static void Warning(const char *s, OSStatus error) + { + if (sWarningHandler) + (*sWarningHandler)(s, error); + } + + static void SetWarningHandler(WarningHandler f) { sWarningHandler = f; } +private: + static WarningHandler sWarningHandler; +}; + +#if DEBUG || CoreAudio_Debug + #define XThrowIfError(error, operation) \ + do { \ + OSStatus __err = error; \ + if (__err) { \ + DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), operation);\ + __THROW_STOP; \ + throw CAXException(operation, __err); \ + } \ + } while (0) + + #define XThrowIf(condition, error, operation) \ + do { \ + if (condition) { \ + OSStatus __err = error; \ + DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), operation);\ + __THROW_STOP; \ + throw CAXException(operation, __err); \ + } \ + } while (0) + + #define XRequireNoError(error, label) \ + do { \ + OSStatus __err = error; \ + if (__err) { \ + DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), #error);\ + STOP; \ + goto label; \ + } \ + } while (0) + + #define XAssert(assertion) \ + do { \ + if (!(assertion)) { \ + DebugMessageN3("%s:%d: error: failed assertion: %s", __FILE__, __LINE__, #assertion); \ + __ASSERT_STOP; \ + } \ + } while (0) + + #define XAssertNoError(error) \ + do { \ + OSStatus __err = error; \ + if (__err) { \ + DebugMessageN4("%s:%d: error %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), #error);\ + STOP; \ + } \ + } while (0) + + #define ca_require_noerr(errorCode, exceptionLabel) \ + do \ + { \ + int evalOnceErrorCode = (errorCode); \ + if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \ + { \ + DebugMessageN5("ca_require_noerr: [%s, %d] (goto %s;) %s:%d", \ + #errorCode, evalOnceErrorCode, \ + #exceptionLabel, \ + __FILE__, \ + __LINE__); \ + goto exceptionLabel; \ + } \ + } while ( 0 ) + + #define ca_verify_noerr(errorCode) \ + do \ + { \ + int evalOnceErrorCode = (errorCode); \ + if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \ + { \ + DebugMessageN4("ca_verify_noerr: [%s, %d] %s:%d", \ + #errorCode, evalOnceErrorCode, \ + __FILE__, \ + __LINE__); \ + } \ + } while ( 0 ) + + #define ca_debug_string(message) \ + do \ + { \ + DebugMessageN3("ca_debug_string: %s %s:%d", \ + message, \ + __FILE__, \ + __LINE__); \ + } while ( 0 ) + + + #define ca_verify(assertion) \ + do \ + { \ + if ( __builtin_expect(!(assertion), 0) ) \ + { \ + DebugMessageN3("ca_verify: %s %s:%d", \ + #assertion, \ + __FILE__, \ + __LINE__); \ + } \ + } while ( 0 ) + + #define ca_require(assertion, exceptionLabel) \ + do \ + { \ + if ( __builtin_expect(!(assertion), 0) ) \ + { \ + DebugMessageN4("ca_require: %s %s %s:%d", \ + #assertion, \ + #exceptionLabel, \ + __FILE__, \ + __LINE__); \ + goto exceptionLabel; \ + } \ + } while ( 0 ) + + #define ca_check(assertion) \ + do \ + { \ + if ( __builtin_expect(!(assertion), 0) ) \ + { \ + DebugMessageN3("ca_check: %s %s:%d", \ + #assertion, \ + __FILE__, \ + __LINE__); \ + } \ + } while ( 0 ) + +#else + #define XThrowIfError(error, operation) \ + do { \ + OSStatus __err = error; \ + if (__err) { \ + throw CAXException(operation, __err); \ + } \ + } while (0) + + #define XThrowIf(condition, error, operation) \ + do { \ + if (condition) { \ + OSStatus __err = error; \ + throw CAXException(operation, __err); \ + } \ + } while (0) + + #define XRequireNoError(error, label) \ + do { \ + OSStatus __err = error; \ + if (__err) { \ + goto label; \ + } \ + } while (0) + + #define XAssert(assertion) \ + do { \ + if (!(assertion)) { \ + } \ + } while (0) + + #define XAssertNoError(error) \ + do { \ + /*OSStatus __err =*/ error; \ + } while (0) + + #define ca_require_noerr(errorCode, exceptionLabel) \ + do \ + { \ + if ( __builtin_expect(0 != (errorCode), 0) ) \ + { \ + goto exceptionLabel; \ + } \ + } while ( 0 ) + + #define ca_verify_noerr(errorCode) \ + do \ + { \ + if ( 0 != (errorCode) ) \ + { \ + } \ + } while ( 0 ) + + #define ca_debug_string(message) + + #define ca_verify(assertion) \ + do \ + { \ + if ( !(assertion) ) \ + { \ + } \ + } while ( 0 ) + + #define ca_require(assertion, exceptionLabel) \ + do \ + { \ + if ( __builtin_expect(!(assertion), 0) ) \ + { \ + goto exceptionLabel; \ + } \ + } while ( 0 ) + + #define ca_check(assertion) \ + do \ + { \ + if ( !(assertion) ) \ + { \ + } \ + } while ( 0 ) + + +#endif + +#define XThrow(error, operation) XThrowIf(true, error, operation) +#define XThrowIfErr(error) XThrowIfError(error, #error) + +#endif // __CAXException_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CarbonEventHandler.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CarbonEventHandler.cpp new file mode 100644 index 0000000000..ac76327c62 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CarbonEventHandler.cpp @@ -0,0 +1,90 @@ +/* + File: CarbonEventHandler.cpp + Abstract: CarbonEventHandler.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "CarbonEventHandler.h" + +static pascal OSStatus TheEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData) +{ + CarbonEventHandler *handler = (CarbonEventHandler *)inUserData; + if (handler->HandleEvent(inHandlerRef, inEvent)) + return noErr; + else return eventNotHandledErr; +} + +CarbonEventHandler::CarbonEventHandler() : + mHandlers(NULL) +{ +} + +CarbonEventHandler::~CarbonEventHandler() +{ + if (mHandlers != NULL) { + int count = static_cast(CFDictionaryGetCount(mHandlers)); + EventHandlerRef *theHandlers = (EventHandlerRef*) malloc(count * sizeof(EventHandlerRef)); + CFDictionaryGetKeysAndValues(mHandlers, NULL, (const void **)theHandlers); + + for (int i = 0; i < count; i++) + RemoveEventHandler(theHandlers[i]); + CFDictionaryRemoveAllValues(mHandlers); + CFRelease (mHandlers); + free(theHandlers); + } +} + +void CarbonEventHandler::WantEventTypes(EventTargetRef target, UInt32 inNumTypes, const EventTypeSpec *inList) +{ + if (mHandlers == NULL) + mHandlers = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + + EventHandlerRef handler; + + if (CFDictionaryGetValueIfPresent (mHandlers, target, (const void **)&handler)) // if there is already a handler for the target, add the type + verify_noerr(AddEventTypesToHandler(handler, inNumTypes, inList)); + else { + verify_noerr(InstallEventHandler(target, TheEventHandler, inNumTypes, inList, this, &handler)); + CFDictionaryAddValue(mHandlers, target, handler); + } +} diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CarbonEventHandler.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CarbonEventHandler.h new file mode 100644 index 0000000000..4ba4995fc3 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/CarbonEventHandler.h @@ -0,0 +1,71 @@ +/* + File: CarbonEventHandler.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __CarbonEventHandler_h__ +#define __CarbonEventHandler_h__ + +#include + + /*! @class CarbonEventHandler */ +class CarbonEventHandler { +public: + /*! @ctor CarbonEventHandler */ + CarbonEventHandler(); + /*! @dtor ~CarbonEventHandler */ + virtual ~CarbonEventHandler(); + + /*! @method WantEventTypes */ + virtual void WantEventTypes(EventTargetRef target, UInt32 inNumTypes, const EventTypeSpec *inList); + + /*! @method HandleEvent */ + virtual bool HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event) = 0; + +protected: + /*! @var mHandlers */ + CFMutableDictionaryRef mHandlers; +}; + +#endif // __CarbonEventHandler_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/ComponentBase.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/ComponentBase.cpp new file mode 100644 index 0000000000..50a5438310 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/ComponentBase.cpp @@ -0,0 +1,369 @@ +/* + File: ComponentBase.cpp + Abstract: ComponentBase.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "ComponentBase.h" +#include "CAXException.h" + +#if TARGET_OS_MAC +pthread_mutex_t ComponentInitLocker::sComponentOpenMutex = PTHREAD_MUTEX_INITIALIZER; +pthread_once_t ComponentInitLocker::sOnce = PTHREAD_ONCE_INIT; + +void ComponentInitLocker::InitComponentInitLocker() +{ + // have to do this because OS X lacks PTHREAD_MUTEX_RECURSIVE_INITIALIZER_NP + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&sComponentOpenMutex, &attr); + pthread_mutexattr_destroy(&attr); +} + +#elif TARGET_OS_WIN32 +CAGuard ComponentInitLocker::sComponentOpenGuard("sComponentOpenGuard"); +#endif + +ComponentBase::EInstanceType ComponentBase::sNewInstanceType; + +static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc); +#if !CA_USE_AUDIO_PLUGIN_ONLY && !TARGET_OS_WIN32 + static OSStatus CMgr_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc); +#endif + +ComponentBase::ComponentBase(AudioComponentInstance inInstance) + : mComponentInstance(inInstance), + mInstanceType(sNewInstanceType) +{ + GetComponentDescription(); +} + +ComponentBase::~ComponentBase() +{ +} + +void ComponentBase::PostConstructor() +{ +} + +void ComponentBase::PreDestructor() +{ +} + +#define ACPI ((AudioComponentPlugInInstance *)self) +#define ACImp ((ComponentBase *)&ACPI->mInstanceStorage) + +OSStatus ComponentBase::AP_Open(void *self, AudioUnit compInstance) +{ + OSStatus result = noErr; + try { + ComponentInitLocker lock; + + ComponentBase::sNewInstanceType = ComponentBase::kAudioComponentInstance; + ComponentBase *cb = (ComponentBase *)(*ACPI->mConstruct)(&ACPI->mInstanceStorage, compInstance); + cb->PostConstructor(); // allows base class to do additional initialization + // once the derived class is fully constructed + result = noErr; + } + COMPONENT_CATCH + if (result) + delete ACPI; + return result; +} + +OSStatus ComponentBase::AP_Close(void *self) +{ + OSStatus result = noErr; + try { + if (ACImp) { + ACImp->PreDestructor(); + (*ACPI->mDestruct)(&ACPI->mInstanceStorage); + free(self); + } + } + COMPONENT_CATCH + return result; +} + +#if !CA_USE_AUDIO_PLUGIN_ONLY +OSStatus ComponentBase::Version() +{ + return 0x00000001; +} + +OSStatus ComponentBase::ComponentEntryDispatch(ComponentParameters *p, ComponentBase *This) +{ + if (This == NULL) return kAudio_ParamError; + + OSStatus result = noErr; + + switch (p->what) { + case kComponentCloseSelect: + This->PreDestructor(); + delete This; + break; + + case kComponentVersionSelect: + result = This->Version(); + break; + + case kComponentCanDoSelect: + switch (GetSelectorForCanDo(p)) { + case kComponentOpenSelect: + case kComponentCloseSelect: + case kComponentVersionSelect: + case kComponentCanDoSelect: + return 1; + default: + return 0; + } + + default: + result = badComponentSelector; + break; + } + return result; +} + +SInt16 ComponentBase::GetSelectorForCanDo(ComponentParameters *params) +{ + if (params->what != kComponentCanDoSelect) return 0; + + #if TARGET_CPU_X86 + SInt16 sel = params->params[0]; + #elif TARGET_CPU_X86_64 + SInt16 sel = params->params[1]; + #elif TARGET_CPU_PPC + SInt16 sel = (params->params[0] >> 16); + #else + SInt16 sel = params->params[0]; + #endif + + return sel; +/* + printf ("flags:%d, paramSize: %d, what: %d\n\t", params->flags, params->paramSize, params->what); + for (int i = 0; i < params->paramSize; ++i) { + printf ("[%d]:%d(0x%x), ", i, params->params[i], params->params[i]); + } + printf("\n\tsel:%d\n", sel); +*/ +} + +#endif + +#if CA_DO_NOT_USE_AUDIO_COMPONENT +static OSStatus ComponentBase_GetComponentDescription (const AudioComponentInstance & inInstance, AudioComponentDescription &outDesc); +#endif + +AudioComponentDescription ComponentBase::GetComponentDescription() const +{ + AudioComponentDescription desc; + OSStatus result = 1; + + if (IsPluginObject()) { + ca_require_noerr(result = CB_GetComponentDescription (mComponentInstance, &desc), home); + } +#if !CA_USE_AUDIO_PLUGIN_ONLY + else { + ca_require_noerr(result = CMgr_GetComponentDescription (mComponentInstance, &desc), home); + } +#endif + +home: + if (result) + memset (&desc, 0, sizeof(AudioComponentDescription)); + + return desc; +} + +#if CA_USE_AUDIO_PLUGIN_ONLY +// everything we need is there and we should be linking against it +static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc) +{ + AudioComponent comp = AudioComponentInstanceGetComponent(inInstance); + if (comp) + return AudioComponentGetDescription(comp, outDesc); + + return kAudio_ParamError; +} + +#elif !TARGET_OS_WIN32 +// these are the direct dependencies on ComponentMgr calls that an AU +// that is a component mgr is dependent on + +// these are dynamically loaded so that these calls will work on Leopard +#include + +static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc) +{ + typedef AudioComponent (*AudioComponentInstanceGetComponentProc) (AudioComponentInstance); + static AudioComponentInstanceGetComponentProc aciGCProc = NULL; + + typedef OSStatus (*AudioComponentGetDescriptionProc)(AudioComponent, AudioComponentDescription *); + static AudioComponentGetDescriptionProc acGDProc = NULL; + + static int doneInit = 0; + if (doneInit == 0) { + doneInit = 1; + void* theImage = dlopen("/System/Library/Frameworks/AudioUnit.framework/AudioUnit", RTLD_LAZY); + if (theImage != NULL) + { + aciGCProc = (AudioComponentInstanceGetComponentProc)dlsym (theImage, "AudioComponentInstanceGetComponent"); + if (aciGCProc) { + acGDProc = (AudioComponentGetDescriptionProc)dlsym (theImage, "AudioComponentGetDescription"); + } + } + } + + OSStatus result = kAudio_UnimplementedError; + if (acGDProc && aciGCProc) { + AudioComponent comp = (*aciGCProc)(inInstance); + if (comp) + result = (*acGDProc)(comp, outDesc); + } +#if !CA_USE_AUDIO_PLUGIN_ONLY + else { + result = CMgr_GetComponentDescription (inInstance, outDesc); + } +#endif + + return result; +} + +#if !CA_USE_AUDIO_PLUGIN_ONLY +// these are the direct dependencies on ComponentMgr calls that an AU +// that is a component mgr is dependent on + +// these are dynamically loaded + +#include +#include +#include "CAXException.h" +#include "ComponentBase.h" + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Component Manager +// Used for fast dispatch with audio units +typedef Handle (*GetComponentInstanceStorageProc)(ComponentInstance aComponentInstance); +static GetComponentInstanceStorageProc sGetComponentInstanceStorageProc = NULL; + +typedef OSErr (*GetComponentInfoProc)(Component, ComponentDescription *, void*, void*, void*); +static GetComponentInfoProc sGetComponentInfoProc = NULL; + +typedef void (*SetComponentInstanceStorageProc)(ComponentInstance, Handle); +static SetComponentInstanceStorageProc sSetComponentInstanceStorageProc = NULL; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +static void CSInitOnce(void* /*unused*/) +{ + void *theImage = dlopen("/System/Library/Frameworks/CoreServices.framework/CoreServices", RTLD_LAZY); + if (!theImage) return; + + sGetComponentInstanceStorageProc = (GetComponentInstanceStorageProc) dlsym(theImage, "GetComponentInstanceStorage"); + sGetComponentInfoProc = (GetComponentInfoProc)dlsym (theImage, "GetComponentInfo"); + sSetComponentInstanceStorageProc = (SetComponentInstanceStorageProc) dlsym(theImage, "SetComponentInstanceStorage"); +} + +#if TARGET_OS_MAC + +#include + +static dispatch_once_t sCSInitOnce = 0; + +static void CSInit () +{ + dispatch_once_f(&sCSInitOnce, NULL, CSInitOnce); +} + +#else + +static void CSInit () +{ + static int sDoCSLoad = 1; + if (sDoCSLoad) { + sDoCSLoad = 0; + CSInitOnce(NULL); + } +} + +#endif + +OSStatus CMgr_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc) +{ + CSInit(); + if (sGetComponentInfoProc) + return (*sGetComponentInfoProc)((Component)inInstance, (ComponentDescription*)outDesc, NULL, NULL, NULL); + return kAudio_UnimplementedError; +} + +Handle CMgr_GetComponentInstanceStorage(ComponentInstance aComponentInstance) +{ + CSInit(); + if (sGetComponentInstanceStorageProc) + return (*sGetComponentInstanceStorageProc)(aComponentInstance); + return NULL; +} + +void CMgr_SetComponentInstanceStorage(ComponentInstance aComponentInstance, Handle theStorage) +{ + CSInit(); + if (sSetComponentInstanceStorageProc) + (*sSetComponentInstanceStorageProc)(aComponentInstance, theStorage); +} +#endif // !CA_USE_AUDIO_PLUGIN_ONLY + +#else +//#include "ComponentManagerDependenciesWin.h" +// everything we need is there and we should be linking against it +static OSStatus CB_GetComponentDescription (const AudioComponentInstance inInstance, AudioComponentDescription * outDesc) +{ + AudioComponent comp = AudioComponentInstanceGetComponent(inInstance); + if (comp) + return AudioComponentGetDescription(comp, outDesc); + + return kAudio_ParamError; +} + +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/ComponentBase.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/ComponentBase.h new file mode 100644 index 0000000000..6eb03214d5 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/ComponentBase.h @@ -0,0 +1,353 @@ +/* + File: ComponentBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __ComponentBase_h__ +#define __ComponentBase_h__ + +#include +#include "CADebugMacros.h" +#include "CAXException.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include + + #if !CA_USE_AUDIO_PLUGIN_ONLY + #include + + #if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) + #define AudioComponentInstance ComponentInstance + #define AudioComponentDescription ComponentDescription + #define AudioComponent Component + #endif + Handle CMgr_GetComponentInstanceStorage(ComponentInstance aComponentInstance); + void CMgr_SetComponentInstanceStorage(ComponentInstance aComponentInstance, Handle theStorage); + #endif + + #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 + typedef Float32 AudioUnitParameterValue; + #endif + #if COREAUDIOTYPES_VERSION < 1051 + typedef Float32 AudioUnitSampleType; + #endif + + #if !TARGET_OS_WIN32 + #include + #endif + + #if TARGET_OS_WIN32 + #include "CAGuard.h" + #endif +#else + #include "CoreAudioTypes.h" + #if !CA_USE_AUDIO_PLUGIN_ONLY + #include "ComponentManagerDependenciesWin.h" + #endif + #include "AudioUnit.h" + #include "CAGuard.h" +#endif + +#ifndef COMPONENT_THROW + #if VERBOSE_COMPONENT_THROW + #define COMPONENT_THROW(throw_err) \ + do { DebugMessage(#throw_err); throw static_cast(throw_err); } while (0) + #else + #define COMPONENT_THROW(throw_err) \ + throw static_cast(throw_err) + #endif +#endif + +#define COMPONENT_CATCH \ + catch (const CAXException &ex) { result = ex.mError; } \ + catch (std::bad_alloc &) { result = kAudio_MemFullError; } \ + catch (OSStatus catch_err) { result = catch_err; } \ + catch (OSErr catch_err) { result = catch_err; } \ + catch (...) { result = -1; } + +/*! @class ComponentBase */ +class ComponentBase { +public: + // classic MacErrors + enum { noErr = 0}; + + /*! @ctor ComponentBase */ + ComponentBase(AudioComponentInstance inInstance); + + /*! @dtor ~ComponentBase */ + virtual ~ComponentBase(); + + /*! @method PostConstructor */ + virtual void PostConstructor(); + + /*! @method PreDestructor */ + virtual void PreDestructor(); + +#if !CA_USE_AUDIO_PLUGIN_ONLY + /*! @method Version */ + virtual OSStatus Version(); + + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch(ComponentParameters *p, ComponentBase *This); + + /*! GetSelectorForCanDo */ + static SInt16 GetSelectorForCanDo(ComponentParameters *params); +#endif + + /*! @method GetComponentInstance */ + AudioComponentInstance GetComponentInstance() const { return mComponentInstance; } + + /*! @method GetComponentDescription */ + AudioComponentDescription GetComponentDescription() const; + + // This global variable is so that new instances know how they were instantiated: via the Component Manager, + // or as AudioComponents. It's ugly, but preferable to altering the constructor of every class in the hierarchy. + // It's safe because construction is protected by ComponentInitLocker. + enum EInstanceType { kComponentMgrInstance, kAudioComponentInstance }; + static EInstanceType sNewInstanceType; + + /*! @method IsPluginObject */ + bool IsPluginObject () const { return mInstanceType == kAudioComponentInstance; } + /*! @method IsCMgrObject */ + bool IsCMgrObject () const { return mInstanceType == kComponentMgrInstance; } + + /*! @method AP_Open */ + static OSStatus AP_Open(void *self, AudioUnit compInstance); + + /*! @method AP_Close */ + static OSStatus AP_Close(void *self); + +protected: + /*! @var mComponentInstance */ + AudioComponentInstance mComponentInstance; + EInstanceType mInstanceType; +}; + +class ComponentInitLocker +{ +#if TARGET_OS_MAC +public: + ComponentInitLocker() + { + pthread_once(&sOnce, InitComponentInitLocker); + pthread_mutex_lock(&sComponentOpenMutex); + mPreviousNewInstanceType = ComponentBase::sNewInstanceType; + } + ~ComponentInitLocker() + { + ComponentBase::sNewInstanceType = mPreviousNewInstanceType; + pthread_mutex_unlock(&sComponentOpenMutex); + } + + // There are situations (11844772) where we need to be able to release the lock early. + class Unlocker { + public: + Unlocker() + { + pthread_mutex_unlock(&sComponentOpenMutex); + } + ~Unlocker() + { + pthread_mutex_lock(&sComponentOpenMutex); + } + }; + +private: + static pthread_mutex_t sComponentOpenMutex; + static pthread_once_t sOnce; + static void InitComponentInitLocker(); + +#elif TARGET_OS_WIN32 +public: + bool sNeedsUnlocking; + ComponentInitLocker() { sNeedsUnlocking = sComponentOpenGuard.Lock(); } + ~ComponentInitLocker() { if(sNeedsUnlocking) { sComponentOpenGuard.Unlock(); } } +private: + static CAGuard sComponentOpenGuard; +#endif + +private: + ComponentBase::EInstanceType mPreviousNewInstanceType; +}; + +/*! @class AudioComponentPlugInInstance */ +struct AudioComponentPlugInInstance { + AudioComponentPlugInInterface mPlugInInterface; + void * (*mConstruct)(void *memory, AudioComponentInstance ci); + void (*mDestruct)(void *memory); + void * mPad[2]; // pad to a 16-byte boundary (in either 32 or 64 bit mode) + UInt32 mInstanceStorage; // the ACI implementation object is constructed into this memory + // this member is just a placeholder. it is aligned to a 16byte boundary +}; + +/*! @class APFactory */ +template +class APFactory { +public: + static void *Construct(void *memory, AudioComponentInstance compInstance) + { + return new(memory) Implementor(compInstance); + } + + static void Destruct(void *memory) + { + ((Implementor *)memory)->~Implementor(); + } + + // This is the AudioComponentFactoryFunction. It returns an AudioComponentPlugInInstance. + // The actual implementation object is not created until Open(). + static AudioComponentPlugInInterface *Factory(const AudioComponentDescription * /* inDesc */) + { + AudioComponentPlugInInstance *acpi = + (AudioComponentPlugInInstance *)malloc( offsetof(AudioComponentPlugInInstance, mInstanceStorage) + sizeof(Implementor) ); + acpi->mPlugInInterface.Open = ComponentBase::AP_Open; + acpi->mPlugInInterface.Close = ComponentBase::AP_Close; + acpi->mPlugInInterface.Lookup = APMethodLookup::Lookup; + acpi->mPlugInInterface.reserved = NULL; + acpi->mConstruct = Construct; + acpi->mDestruct = Destruct; + acpi->mPad[0] = NULL; + acpi->mPad[1] = NULL; + return (AudioComponentPlugInInterface*)acpi; + } + + // This is for runtime registration (not for plug-ins loaded from bundles). + static AudioComponent Register(UInt32 type, UInt32 subtype, UInt32 manuf, CFStringRef name, UInt32 vers, UInt32 flags=0) + { + AudioComponentDescription desc = { type, subtype, manuf, flags, 0 }; + return AudioComponentRegister(&desc, name, vers, Factory); + } +}; + +#if !CA_USE_AUDIO_PLUGIN_ONLY +/*! @class ComponentEntryPoint + * @discussion This is only used for a component manager version +*/ +template +class ComponentEntryPoint { +public: + /*! @method Dispatch */ + static OSStatus Dispatch(ComponentParameters *params, Class *obj) + { + OSStatus result = noErr; + + try { + if (params->what == kComponentOpenSelect) { + // solve a host of initialization thread safety issues. + ComponentInitLocker lock; + + ComponentBase::sNewInstanceType = ComponentBase::kComponentMgrInstance; + ComponentInstance ci = (ComponentInstance)(params->params[0]); + Class *This = new Class((AudioComponentInstance)ci); + This->PostConstructor(); // allows base class to do additional initialization + // once the derived class is fully constructed + + CMgr_SetComponentInstanceStorage(ci, (Handle)This); + } else + result = Class::ComponentEntryDispatch(params, obj); + } + COMPONENT_CATCH + + return result; + } + + /*! @method Register */ + static Component Register(OSType compType, OSType subType, OSType manufacturer) + { + ComponentDescription description = {compType, subType, manufacturer, 0, 0}; + Component component = RegisterComponent(&description, (ComponentRoutineUPP) Dispatch, registerComponentGlobal, NULL, NULL, NULL); + if (component != NULL) { + SetDefaultComponent(component, defaultComponentAnyFlagsAnyManufacturerAnySubType); + } + return component; + } +}; + +// NOTE: Component Mgr is deprecated in ML. +// this macro should not be used with new audio components +// it is only for backwards compatibility with Lion and SL. +// this macro registers both a plugin and a component mgr version. +#define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \ + extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj); \ + extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \ + return ComponentEntryPoint::Dispatch(params, obj); \ + } \ + extern "C" void * Class##Factory(const AudioComponentDescription *inDesc); \ + extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \ + return FactoryType::Factory(inDesc); \ + } + // the only component we still support are the carbon based view components + // you should be using this macro now to exclusively register those types +#define VIEW_COMPONENT_ENTRY(Class) \ + extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj); \ + extern "C" OSStatus Class##Entry(ComponentParameters *params, Class *obj) { \ + return ComponentEntryPoint::Dispatch(params, obj); \ + } + + /*! @class ComponentRegistrar */ +template +class ComponentRegistrar { +public: + /*! @ctor ComponentRegistrar */ + ComponentRegistrar() { ComponentEntryPoint::Register(Type, Subtype, Manufacturer); } +}; + +#define COMPONENT_REGISTER(Class,Type,Subtype,Manufacturer) \ + static ComponentRegistrar gRegistrar##Class +#else +#define COMPONENT_ENTRY(Class) +#define COMPONENT_REGISTER(Class) +// this macro is used to generate the Entry Point for a given Audio Plugin +// you should be using this macro now with audio components +#define AUDIOCOMPONENT_ENTRY(FactoryType, Class) \ + extern "C" void * Class##Factory(const AudioComponentDescription *inDesc); \ + extern "C" void * Class##Factory(const AudioComponentDescription *inDesc) { \ + return FactoryType::Factory(inDesc); \ + } + +#endif // !CA_USE_AUDIO_PLUGIN_ONLY + + +#endif // __ComponentBase_h__ diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/MusicDeviceBase.cpp b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/MusicDeviceBase.cpp new file mode 100644 index 0000000000..8acf8cadfb --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/MusicDeviceBase.cpp @@ -0,0 +1,354 @@ +/* + File: MusicDeviceBase.cpp + Abstract: MusicDeviceBase.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "MusicDeviceBase.h" + +// compatibility with older OS SDK releases +typedef OSStatus +(*TEMP_MusicDeviceMIDIEventProc)( void * inComponentStorage, + UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame); + +typedef OSStatus +(*TEMP_MusicDeviceStartNoteProc)( void * inComponentStorage, + MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams); + +typedef OSStatus +(*TEMP_MusicDeviceStopNoteProc)(void * inComponentStorage, + MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame); + +#if !CA_USE_AUDIO_PLUGIN_ONLY + +static OSStatus MusicDeviceBaseMIDIEvent(void * inComponentStorage, + UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame); + +static OSStatus MusicDeviceBaseStartNote( void * inComponentStorage, + MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams); + +static OSStatus MusicDeviceBaseStopNote(void * inComponentStorage, + MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame); + +#endif + +MusicDeviceBase::MusicDeviceBase(AudioComponentInstance inInstance, + UInt32 numInputs, + UInt32 numOutputs, + UInt32 numGroups) + : AUBase(inInstance, numInputs, numOutputs, numGroups), + AUMIDIBase(this) +{ +} + +OSStatus MusicDeviceBase::GetPropertyInfo(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable) +{ + OSStatus result; + + switch (inID) + { +#if !TARGET_OS_IPHONE + case kMusicDeviceProperty_InstrumentCount: + if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope; + outDataSize = sizeof(UInt32); + outWritable = false; + result = noErr; + break; +#endif + default: + result = AUBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); + + if (result == kAudioUnitErr_InvalidProperty) + result = AUMIDIBase::DelegateGetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); + break; + } + return result; +} + +OSStatus MusicDeviceBase::GetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData) +{ + OSStatus result; + + switch (inID) + { +#if !CA_USE_AUDIO_PLUGIN_ONLY + case kAudioUnitProperty_FastDispatch: + if (!IsCMgrObject()) return kAudioUnitErr_InvalidProperty; + if (inElement == kMusicDeviceMIDIEventSelect) { + *(TEMP_MusicDeviceMIDIEventProc *)outData = MusicDeviceBaseMIDIEvent; + return noErr; + } + else if (inElement == kMusicDeviceStartNoteSelect) { + *(TEMP_MusicDeviceStartNoteProc *)outData = MusicDeviceBaseStartNote; + return noErr; + } + else if (inElement == kMusicDeviceStopNoteSelect) { + *(TEMP_MusicDeviceStopNoteProc *)outData = MusicDeviceBaseStopNote; + return noErr; + } + return kAudioUnitErr_InvalidElement; +#endif + +#if !TARGET_OS_IPHONE + case kMusicDeviceProperty_InstrumentCount: + if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope; + return GetInstrumentCount (*(UInt32*)outData); +#endif + default: + result = AUBase::GetProperty (inID, inScope, inElement, outData); + + if (result == kAudioUnitErr_InvalidProperty) + result = AUMIDIBase::DelegateGetProperty (inID, inScope, inElement, outData); + } + + return result; +} + + +OSStatus MusicDeviceBase::SetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize) + +{ + + OSStatus result = AUBase::SetProperty (inID, inScope, inElement, inData, inDataSize); + + if (result == kAudioUnitErr_InvalidProperty) + result = AUMIDIBase::DelegateSetProperty (inID, inScope, inElement, inData, inDataSize); + + return result; +} + +// For a MusicDevice that doesn't support separate instruments (ie. is mono-timbral) +// then this call should return an instrument count of zero and noErr +OSStatus MusicDeviceBase::GetInstrumentCount (UInt32 &outInstCount) const +{ + outInstCount = 0; + return noErr; +} + +OSStatus MusicDeviceBase::HandleNoteOn( UInt8 inChannel, + UInt8 inNoteNumber, + UInt8 inVelocity, + UInt32 inStartFrame) +{ + MusicDeviceNoteParams params; + params.argCount = 2; + params.mPitch = inNoteNumber; + params.mVelocity = inVelocity; + return StartNote (kMusicNoteEvent_UseGroupInstrument, inChannel, NULL, inStartFrame, params); +} + +OSStatus MusicDeviceBase::HandleNoteOff( UInt8 inChannel, + UInt8 inNoteNumber, + UInt8 inVelocity, + UInt32 inStartFrame) +{ + return StopNote (inChannel, inNoteNumber, inStartFrame); +} + +OSStatus +MusicDeviceBase::HandleStartNoteMessage (MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) +{ + if (inParams == NULL || outNoteInstanceID == NULL) return kAudio_ParamError; + + if (!IsInitialized()) return kAudioUnitErr_Uninitialized; + + return StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams); +} + +#if TARGET_OS_MAC + #if __LP64__ + // comp instance, parameters in forward order + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_index + 1]; + #else + // parameters in reverse order, then comp instance + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_nparams - 1 - _index]; + #endif +#elif TARGET_OS_WIN32 + // (no comp instance), parameters in forward order + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_index]; +#endif + +#if !CA_USE_AUDIO_PLUGIN_ONLY +OSStatus MusicDeviceBase::ComponentEntryDispatch( ComponentParameters * params, + MusicDeviceBase * This) +{ + if (This == NULL) return kAudio_ParamError; + + OSStatus result; + + switch (params->what) { + case kMusicDeviceMIDIEventSelect: + case kMusicDeviceSysExSelect: + { + result = AUMIDIBase::ComponentEntryDispatch (params, This); + } + break; + case kMusicDevicePrepareInstrumentSelect: + { + PARAM(MusicDeviceInstrumentID, inInstrument, 0, 1); + result = This->PrepareInstrument(inInstrument); + } + break; + case kMusicDeviceReleaseInstrumentSelect: + { + PARAM(MusicDeviceInstrumentID, inInstrument, 0, 1); + result = This->ReleaseInstrument(inInstrument); + } + break; + case kMusicDeviceStartNoteSelect: + { + PARAM(MusicDeviceInstrumentID, pbinInstrument, 0, 5); + PARAM(MusicDeviceGroupID, pbinGroupID, 1, 5); + PARAM(NoteInstanceID *, pboutNoteInstanceID, 2, 5); + PARAM(UInt32, pbinOffsetSampleFrame, 3, 5); + PARAM(const MusicDeviceNoteParams *, pbinParams, 4, 5); + result = This->HandleStartNoteMessage(pbinInstrument, pbinGroupID, pboutNoteInstanceID, pbinOffsetSampleFrame, pbinParams); + } + break; + case kMusicDeviceStopNoteSelect: + { + PARAM(MusicDeviceGroupID, pbinGroupID, 0, 3); + PARAM(NoteInstanceID, pbinNoteInstanceID, 1, 3); + PARAM(UInt32, pbinOffsetSampleFrame, 2, 3); + result = This->StopNote(pbinGroupID, pbinNoteInstanceID, pbinOffsetSampleFrame); + } + break; + + default: + result = AUBase::ComponentEntryDispatch(params, This); + break; + } + + return result; +} +#endif + +#if !CA_USE_AUDIO_PLUGIN_ONLY + +// fast dispatch +static OSStatus MusicDeviceBaseMIDIEvent(void * inComponentStorage, + UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) +{ + OSStatus result = noErr; + try { + MusicDeviceBase *This = static_cast(inComponentStorage); + if (This == NULL) return kAudio_ParamError; + result = This->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame); + } + COMPONENT_CATCH + return result; +} + +OSStatus MusicDeviceBaseStartNote( void * inComponentStorage, + MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) +{ + OSStatus result = noErr; + try { + if (inParams == NULL || outNoteInstanceID == NULL) return kAudio_ParamError; + MusicDeviceBase *This = static_cast(inComponentStorage); + if (This == NULL) return kAudio_ParamError; + result = This->StartNote(inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams); + } + COMPONENT_CATCH + return result; +} + +OSStatus MusicDeviceBaseStopNote(void * inComponentStorage, + MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) +{ + OSStatus result = noErr; + try { + MusicDeviceBase *This = static_cast(inComponentStorage); + if (This == NULL) return kAudio_ParamError; + result = This->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame); + } + COMPONENT_CATCH + return result; +} + +#endif diff --git a/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/MusicDeviceBase.h b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/MusicDeviceBase.h new file mode 100644 index 0000000000..475bab3f28 --- /dev/null +++ b/modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/MusicDeviceBase.h @@ -0,0 +1,126 @@ +/* + File: MusicDeviceBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __MusicDeviceBase_h__ +#define __MusicDeviceBase_h__ + +#include "AUMIDIBase.h" + +// ________________________________________________________________________ +// MusicDeviceBase +// + +/*! @class MusicDeviceBase */ +class MusicDeviceBase : public AUBase, public AUMIDIBase { +public: + /*! @ctor MusicDeviceBase */ + MusicDeviceBase( AudioComponentInstance inInstance, + UInt32 numInputs, + UInt32 numOutputs, + UInt32 numGroups = 0); + + + virtual OSStatus MIDIEvent( UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) + { + return AUMIDIBase::MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame); + } + + /*! @method SysEx */ + virtual OSStatus SysEx( const UInt8 * inData, + UInt32 inLength) + { + return AUMIDIBase::SysEx (inData, inLength); + } + + /*! @method GetPropertyInfo */ + virtual OSStatus GetPropertyInfo(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable); + + /*! @method GetProperty */ + virtual OSStatus GetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData); + + /*! @method SetProperty */ + virtual OSStatus SetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize); + + /*! @method HandleNoteOn */ + virtual OSStatus HandleNoteOn( UInt8 inChannel, + UInt8 inNoteNumber, + UInt8 inVelocity, + UInt32 inStartFrame); + + /*! @method HandleNoteOff */ + virtual OSStatus HandleNoteOff( UInt8 inChannel, + UInt8 inNoteNumber, + UInt8 inVelocity, + UInt32 inStartFrame); + + /*! @method GetInstrumentCount */ + virtual OSStatus GetInstrumentCount ( UInt32 &outInstCount) const; + +#if !CA_USE_AUDIO_PLUGIN_ONLY + // component dispatcher + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch( ComponentParameters * params, + MusicDeviceBase * This); +#endif +private: + OSStatus HandleStartNoteMessage (MusicDeviceInstrumentID inInstrument, MusicDeviceGroupID inGroupID, NoteInstanceID *outNoteInstanceID, UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams *inParams); +}; + +#endif // __MusicDeviceBase_h__ diff --git a/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm b/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm index 77832f4bbf..1718025e48 100644 --- a/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm +++ b/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm @@ -64,8 +64,8 @@ juce website for more info on how to get them: http://www.juce.com/forum/topic/aus-xcode */ -#include "AUMIDIEffectBase.h" -#include "MusicDeviceBase.h" +#include "CoreAudioUtilityClasses/AUMIDIEffectBase.h" +#include "CoreAudioUtilityClasses/MusicDeviceBase.h" #undef Point #undef Component @@ -84,7 +84,7 @@ #if BUILD_AU_CARBON_UI #undef Button #define Point CarbonDummyPointName - #include "AUCarbonViewBase.h" + #include "CoreAudioUtilityClasses/AUCarbonViewBase.h" #undef Point #endif @@ -1647,7 +1647,7 @@ JUCE_FACTORY_ENTRY (JuceAU, JucePlugin_AUExportPrefix) #endif #if ! JUCE_DISABLE_AU_FACTORY_ENTRY - #include "AUPlugInDispatch.cpp" + #include "CoreAudioUtilityClasses/AUPlugInDispatch.cpp" #endif #endif diff --git a/modules/juce_audio_plugin_client/juce_module_info b/modules/juce_audio_plugin_client/juce_module_info index 425670fe27..84e01af4fd 100644 --- a/modules/juce_audio_plugin_client/juce_module_info +++ b/modules/juce_audio_plugin_client/juce_module_info @@ -26,6 +26,27 @@ { "file": "RTAS/juce_RTAS_Wrapper.cpp", "warnings": "disabled", "stdcall": "1", "target": "xcode, msvc" }, { "file": "AU/juce_AU_Resources.r", "target": "xcode", "AudioUnitOnly": "1" }, { "file": "AU/juce_AU_Wrapper.mm", "target": "xcode" }, + { "file": "AU/CoreAudioUtilityClasses/AUBase.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUBuffer.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUCarbonViewBase.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUCarbonViewControl.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUCarbonViewDispatch.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUDispatch.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUEffectBase.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUInputElement.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUMIDIBase.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUMIDIEffectBase.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUOutputBase.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUOutputElement.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/AUScopeElement.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/CAAUParameter.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/CAAudioChannelLayout.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/CAMutex.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/CAStreamBasicDescription.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/CAVectorUnit.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/CarbonEventHandler.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/ComponentBase.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, + { "file": "AU/CoreAudioUtilityClasses/MusicDeviceBase.cpp", "warnings": "disabled", "target": "xcode", "AudioUnitOnly": "1" }, { "file": "AAX/juce_AAX_Wrapper.cpp", "target": "xcode, msvc" }, { "file": "AAX/juce_AAX_Wrapper.mm", "target": "xcode" }, { "file": "utility/juce_PluginUtilities.cpp" }