From f73640618c6b9dde4854b1f847f10fdcb5c5b52f Mon Sep 17 00:00:00 2001 From: falkTX Date: Thu, 24 Jan 2019 11:49:56 +0100 Subject: Add CoreAudio 10.6 files Signed-off-by: falkTX --- .../AudioUnits/AUPublic/AUBase/AUBase.cpp | 2124 ++++++++++++++++++++ .../AudioUnits/AUPublic/AUBase/AUBase.h | 893 ++++++++ .../AudioUnits/AUPublic/AUBase/AUDispatch.cpp | 477 +++++ .../AudioUnits/AUPublic/AUBase/AUDispatch.h | 71 + .../AudioUnits/AUPublic/AUBase/AUInputElement.cpp | 146 ++ .../AudioUnits/AUPublic/AUBase/AUInputElement.h | 111 + .../AudioUnits/AUPublic/AUBase/AUOutputElement.cpp | 56 + .../AudioUnits/AUPublic/AUBase/AUOutputElement.h | 60 + .../AudioUnits/AUPublic/AUBase/AUResources.r | 134 ++ .../AudioUnits/AUPublic/AUBase/AUScopeElement.cpp | 506 +++++ .../AudioUnits/AUPublic/AUBase/AUScopeElement.h | 535 +++++ .../AudioUnits/AUPublic/AUBase/ComponentBase.cpp | 189 ++ .../AudioUnits/AUPublic/AUBase/ComponentBase.h | 226 +++ .../AUPublic/AUCarbonViewBase/AUCarbonViewBase.cpp | 386 ++++ .../AUPublic/AUCarbonViewBase/AUCarbonViewBase.h | 182 ++ .../AUCarbonViewBase/AUCarbonViewControl.cpp | 667 ++++++ .../AUCarbonViewBase/AUCarbonViewControl.h | 224 +++ .../AUCarbonViewBase/AUCarbonViewDispatch.cpp | 119 ++ .../AUPublic/AUCarbonViewBase/AUControlGroup.cpp | 343 ++++ .../AUPublic/AUCarbonViewBase/AUControlGroup.h | 84 + .../AUCarbonViewBase/CarbonEventHandler.cpp | 84 + .../AUPublic/AUCarbonViewBase/CarbonEventHandler.h | 65 + .../AUPublic/AUInstrumentBase/AUInstrumentBase.cpp | 760 +++++++ .../AUPublic/AUInstrumentBase/AUInstrumentBase.h | 246 +++ .../AUPublic/AUInstrumentBase/LockFreeFIFO.h | 167 ++ .../AUPublic/AUInstrumentBase/SynthElement.cpp | 266 +++ .../AUPublic/AUInstrumentBase/SynthElement.h | 262 +++ .../AUPublic/AUInstrumentBase/SynthEvent.h | 140 ++ .../AUPublic/AUInstrumentBase/SynthNote.cpp | 113 ++ .../AUPublic/AUInstrumentBase/SynthNote.h | 170 ++ .../AUPublic/AUInstrumentBase/SynthNoteList.cpp | 87 + .../AUPublic/AUInstrumentBase/SynthNoteList.h | 226 +++ .../AUViewBase/AUViewLocalizedStringKeys.h | 82 + .../AUPublic/OtherBases/AUEffectBase.cpp | 483 +++++ .../AudioUnits/AUPublic/OtherBases/AUEffectBase.h | 269 +++ .../AudioUnits/AUPublic/OtherBases/AUMIDIBase.cpp | 481 +++++ .../AudioUnits/AUPublic/OtherBases/AUMIDIBase.h | 207 ++ .../AUPublic/OtherBases/AUMIDIEffectBase.cpp | 158 ++ .../AUPublic/OtherBases/AUMIDIEffectBase.h | 83 + .../AUPublic/OtherBases/AUOutputBase.cpp | 105 + .../AudioUnits/AUPublic/OtherBases/AUOutputBase.h | 76 + .../AUPublic/OtherBases/AUPannerBase.cpp | 700 +++++++ .../AudioUnits/AUPublic/OtherBases/AUPannerBase.h | 263 +++ .../AUPublic/OtherBases/MusicDeviceBase.cpp | 343 ++++ .../AUPublic/OtherBases/MusicDeviceBase.h | 123 ++ .../AudioUnits/AUPublic/Utility/AUBaseHelper.cpp | 128 ++ .../AudioUnits/AUPublic/Utility/AUBaseHelper.h | 74 + .../AudioUnits/AUPublic/Utility/AUBuffer.cpp | 203 ++ .../AudioUnits/AUPublic/Utility/AUBuffer.h | 261 +++ .../AUPublic/Utility/AUDebugDispatcher.cpp | 423 ++++ .../AUPublic/Utility/AUDebugDispatcher.h | 131 ++ .../AUPublic/Utility/AUInputFormatConverter.h | 149 ++ .../AudioUnits/AUPublic/Utility/AUSilentTimeout.h | 87 + .../AUPublic/Utility/AUTimestampGenerator.cpp | 185 ++ .../AUPublic/Utility/AUTimestampGenerator.h | 148 ++ .../src/CoreAudio106/PublicUtility/AUOutputBL.cpp | 163 ++ .../src/CoreAudio106/PublicUtility/AUOutputBL.h | 112 ++ .../src/CoreAudio106/PublicUtility/AUParamInfo.cpp | 133 ++ .../src/CoreAudio106/PublicUtility/AUParamInfo.h | 106 + .../src/CoreAudio106/PublicUtility/CAAUMIDIMap.cpp | 194 ++ .../src/CoreAudio106/PublicUtility/CAAUMIDIMap.h | 535 +++++ .../PublicUtility/CAAUMIDIMapManager.cpp | 227 +++ .../PublicUtility/CAAUMIDIMapManager.h | 96 + .../CoreAudio106/PublicUtility/CAAUParameter.cpp | 394 ++++ .../src/CoreAudio106/PublicUtility/CAAUParameter.h | 185 ++ distrho/src/CoreAudio106/PublicUtility/CAAtomic.h | 288 +++ .../src/CoreAudio106/PublicUtility/CAAtomicStack.h | 209 ++ .../PublicUtility/CAAudioBufferList.cpp | 225 +++ .../CoreAudio106/PublicUtility/CAAudioBufferList.h | 93 + .../PublicUtility/CAAudioChannelLayout.cpp | 142 ++ .../PublicUtility/CAAudioChannelLayout.h | 191 ++ .../PublicUtility/CAAudioChannelLayoutObject.cpp | 193 ++ .../PublicUtility/CAAudioFileFormats.cpp | 415 ++++ .../PublicUtility/CAAudioFileFormats.h | 143 ++ .../PublicUtility/CAAudioTimeStamp.cpp | 127 ++ .../CoreAudio106/PublicUtility/CAAudioTimeStamp.h | 90 + .../src/CoreAudio106/PublicUtility/CAAudioUnit.cpp | 1257 ++++++++++++ .../src/CoreAudio106/PublicUtility/CAAudioUnit.h | 417 ++++ .../PublicUtility/CAAudioUnitOutputCapturer.h | 137 ++ .../PublicUtility/CAAudioValueRange.cpp | 244 +++ .../CoreAudio106/PublicUtility/CAAudioValueRange.h | 114 ++ .../CoreAudio106/PublicUtility/CAAutoDisposer.h | 502 +++++ .../CoreAudio106/PublicUtility/CABitOperations.h | 192 ++ distrho/src/CoreAudio106/PublicUtility/CABool.h | 82 + .../CoreAudio106/PublicUtility/CABufferList.cpp | 252 +++ .../src/CoreAudio106/PublicUtility/CABufferList.h | 298 +++ .../CoreAudio106/PublicUtility/CABundleLocker.cpp | 78 + .../CoreAudio106/PublicUtility/CABundleLocker.h | 61 + .../src/CoreAudio106/PublicUtility/CAByteOrder.h | 155 ++ .../src/CoreAudio106/PublicUtility/CACFArray.cpp | 788 ++++++++ distrho/src/CoreAudio106/PublicUtility/CACFArray.h | 186 ++ distrho/src/CoreAudio106/PublicUtility/CACFData.h | 101 + .../CoreAudio106/PublicUtility/CACFDictionary.cpp | 561 ++++++ .../CoreAudio106/PublicUtility/CACFDictionary.h | 162 ++ .../PublicUtility/CACFDistributedNotification.cpp | 100 + .../PublicUtility/CACFDistributedNotification.h | 67 + .../CoreAudio106/PublicUtility/CACFMachPort.cpp | 138 ++ .../src/CoreAudio106/PublicUtility/CACFMachPort.h | 83 + .../CoreAudio106/PublicUtility/CACFMessagePort.cpp | 129 ++ .../CoreAudio106/PublicUtility/CACFMessagePort.h | 109 + .../src/CoreAudio106/PublicUtility/CACFNumber.cpp | 77 + .../src/CoreAudio106/PublicUtility/CACFNumber.h | 140 ++ .../src/CoreAudio106/PublicUtility/CACFObject.h | 100 + .../src/CoreAudio106/PublicUtility/CACFPlugIn.h | 95 + .../CoreAudio106/PublicUtility/CACFPreferences.cpp | 281 +++ .../CoreAudio106/PublicUtility/CACFPreferences.h | 86 + .../src/CoreAudio106/PublicUtility/CACFString.cpp | 104 + .../src/CoreAudio106/PublicUtility/CACFString.h | 163 ++ .../src/CoreAudio106/PublicUtility/CAComponent.cpp | 176 ++ .../src/CoreAudio106/PublicUtility/CAComponent.h | 115 ++ .../PublicUtility/CAComponentDescription.cpp | 104 + .../PublicUtility/CAComponentDescription.h | 135 ++ .../CoreAudio106/PublicUtility/CADebugMacros.cpp | 82 + .../src/CoreAudio106/PublicUtility/CADebugMacros.h | 448 +++++ .../CoreAudio106/PublicUtility/CADebugPrintf.cpp | 83 + .../src/CoreAudio106/PublicUtility/CADebugPrintf.h | 107 + .../src/CoreAudio106/PublicUtility/CADebugger.cpp | 71 + .../src/CoreAudio106/PublicUtility/CADebugger.h | 50 + .../src/CoreAudio106/PublicUtility/CAException.h | 77 + .../CoreAudio106/PublicUtility/CAFilePathUtils.cpp | 180 ++ .../CoreAudio106/PublicUtility/CAFilePathUtils.h | 62 + distrho/src/CoreAudio106/PublicUtility/CAGuard.cpp | 333 +++ distrho/src/CoreAudio106/PublicUtility/CAGuard.h | 127 ++ .../PublicUtility/CAHALAudioDevice.cpp | 1151 +++++++++++ .../CoreAudio106/PublicUtility/CAHALAudioDevice.h | 219 ++ .../PublicUtility/CAHALAudioObject.cpp | 357 ++++ .../CoreAudio106/PublicUtility/CAHALAudioObject.h | 131 ++ .../PublicUtility/CAHALAudioStream.cpp | 176 ++ .../CoreAudio106/PublicUtility/CAHALAudioStream.h | 88 + .../PublicUtility/CAHALAudioSystemObject.cpp | 146 ++ .../PublicUtility/CAHALAudioSystemObject.h | 83 + .../CoreAudio106/PublicUtility/CAHostTimeBase.cpp | 104 + .../CoreAudio106/PublicUtility/CAHostTimeBase.h | 225 +++ .../src/CoreAudio106/PublicUtility/CALogMacros.h | 134 ++ distrho/src/CoreAudio106/PublicUtility/CAMath.h | 62 + distrho/src/CoreAudio106/PublicUtility/CAMixMap.h | 121 ++ distrho/src/CoreAudio106/PublicUtility/CAMutex.cpp | 320 +++ distrho/src/CoreAudio106/PublicUtility/CAMutex.h | 138 ++ .../src/CoreAudio106/PublicUtility/CAPThread.cpp | 375 ++++ distrho/src/CoreAudio106/PublicUtility/CAPThread.h | 178 ++ .../CoreAudio106/PublicUtility/CAPersistence.cpp | 462 +++++ .../src/CoreAudio106/PublicUtility/CAProcess.cpp | 79 + distrho/src/CoreAudio106/PublicUtility/CAProcess.h | 69 + .../CoreAudio106/PublicUtility/CAPropertyAddress.h | 161 ++ .../PublicUtility/CAReferenceCounted.h | 78 + .../CoreAudio106/PublicUtility/CARingBuffer.cpp | 328 +++ .../src/CoreAudio106/PublicUtility/CARingBuffer.h | 124 ++ .../PublicUtility/CASettingsStorage.cpp | 686 +++++++ .../CoreAudio106/PublicUtility/CASettingsStorage.h | 116 ++ .../CoreAudio106/PublicUtility/CASharedLibrary.cpp | 112 ++ .../CoreAudio106/PublicUtility/CASharedLibrary.h | 58 + .../PublicUtility/CASpectralProcessor.cpp | 370 ++++ .../PublicUtility/CASpectralProcessor.h | 140 ++ .../PublicUtility/CAStreamBasicDescription.cpp | 573 ++++++ .../PublicUtility/CAStreamBasicDescription.h | 297 +++ .../PublicUtility/CAStreamRangedDescription.cpp | 70 + .../PublicUtility/CAStreamRangedDescription.h | 93 + .../CoreAudio106/PublicUtility/CAThreadSafeList.h | 250 +++ distrho/src/CoreAudio106/PublicUtility/CATink.h | 140 ++ .../src/CoreAudio106/PublicUtility/CATokenMap.h | 206 ++ .../CoreAudio106/PublicUtility/CAVectorUnit.cpp | 183 ++ .../src/CoreAudio106/PublicUtility/CAVectorUnit.h | 72 + .../CoreAudio106/PublicUtility/CAVectorUnitTypes.h | 52 + .../CoreAudio106/PublicUtility/CAVolumeCurve.cpp | 476 +++++ .../src/CoreAudio106/PublicUtility/CAVolumeCurve.h | 172 ++ .../CoreAudio106/PublicUtility/CAXException.cpp | 43 + .../src/CoreAudio106/PublicUtility/CAXException.h | 330 +++ .../PublicUtility/MatrixMixerVolumes.cpp | 143 ++ .../PublicUtility/MatrixMixerVolumes.h | 65 + 169 files changed, 38907 insertions(+) create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUDispatch.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUDispatch.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUInputElement.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUInputElement.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUOutputElement.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUOutputElement.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUResources.r create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUScopeElement.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUScopeElement.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/ComponentBase.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/ComponentBase.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewDispatch.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUControlGroup.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUControlGroup.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/AUViewBase/AUViewLocalizedStringKeys.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIBase.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIBase.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUOutputBase.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUOutputBase.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUPannerBase.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUPannerBase.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBaseHelper.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBaseHelper.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBuffer.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBuffer.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUDebugDispatcher.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUDebugDispatcher.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUInputFormatConverter.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUSilentTimeout.h create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUTimestampGenerator.cpp create mode 100755 distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUTimestampGenerator.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/AUOutputBL.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/AUOutputBL.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/AUParamInfo.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/AUParamInfo.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMap.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMap.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMapManager.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMapManager.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAUParameter.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAUParameter.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAtomic.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAtomicStack.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioBufferList.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioBufferList.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayout.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayout.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayoutObject.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioFileFormats.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioFileFormats.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioTimeStamp.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioTimeStamp.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioUnit.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioUnit.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioUnitOutputCapturer.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioValueRange.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAudioValueRange.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAAutoDisposer.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CABitOperations.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CABool.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CABufferList.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CABufferList.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CABundleLocker.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CABundleLocker.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAByteOrder.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFArray.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFArray.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFData.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFDictionary.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFDictionary.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFDistributedNotification.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFDistributedNotification.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFMachPort.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFMachPort.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFMessagePort.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFMessagePort.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFNumber.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFNumber.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFObject.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFPlugIn.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFPreferences.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFPreferences.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFString.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CACFString.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAComponent.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAComponent.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAComponentDescription.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAComponentDescription.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CADebugMacros.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CADebugMacros.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CADebugPrintf.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CADebugPrintf.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CADebugger.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CADebugger.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAException.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAFilePathUtils.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAFilePathUtils.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAGuard.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAGuard.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAHALAudioDevice.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAHALAudioDevice.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAHALAudioObject.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAHALAudioObject.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAHALAudioStream.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAHALAudioStream.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAHALAudioSystemObject.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAHALAudioSystemObject.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAHostTimeBase.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAHostTimeBase.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CALogMacros.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAMath.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAMixMap.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAMutex.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAMutex.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAPThread.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAPThread.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAPersistence.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAProcess.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAProcess.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAPropertyAddress.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAReferenceCounted.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CARingBuffer.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CARingBuffer.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CASettingsStorage.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CASettingsStorage.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CASharedLibrary.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CASharedLibrary.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CASpectralProcessor.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CASpectralProcessor.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAStreamBasicDescription.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAStreamBasicDescription.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAStreamRangedDescription.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAStreamRangedDescription.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAThreadSafeList.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CATink.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CATokenMap.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAVectorUnit.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAVectorUnit.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAVectorUnitTypes.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAVolumeCurve.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAVolumeCurve.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAXException.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/CAXException.h create mode 100755 distrho/src/CoreAudio106/PublicUtility/MatrixMixerVolumes.cpp create mode 100755 distrho/src/CoreAudio106/PublicUtility/MatrixMixerVolumes.h diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.cpp new file mode 100755 index 00000000..26ae4562 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.cpp @@ -0,0 +1,2124 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "AUBase.h" +#include "AUDispatch.h" +#include "AUInputElement.h" +#include "AUOutputElement.h" +#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, + UInt32 numPartElements) : + ComponentBase(inInstance), + mElementsCreated(false), + mInitialized(false), + mHasBegunInitializing(false), + mInitNumInputEls(numInputElements), mInitNumOutputEls(numOutputElements), +#if !TARGET_OS_IPHONE + mInitNumGroupEls(numGroupElements), mInitNumPartEls(numPartElements), +#endif + mRenderCallbacksTouched(false), + mRenderThreadID (NULL), + mWantsRenderThreadID (false), + mLastRenderedSampleTime(kNoLastRenderedSampleTime), + mLastRenderError(0), + mBuffersAllocated(false), + mLogString (NULL) + #if !TARGET_OS_IPHONE + , + mContextName(NULL), + mDebugDispatcher (NULL) + #endif +{ + 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 (mAudioUnitAPIVersion > 1) + mParamList.reserve (24); + +#if !TARGET_OS_IPHONE + memset (&mHostCallbackInfo, 0, sizeof (mHostCallbackInfo)); +#endif + + + mCurrentPreset.presetNumber = -1; + mCurrentPreset.presetName = kUntitledString; + CFRetain (mCurrentPreset.presetName); +} + +//_____________________________________________________________________________ +// +AUBase::~AUBase() +{ + if (mCurrentPreset.presetName) CFRelease (mCurrentPreset.presetName); +#if !TARGET_OS_IPHONE + if (mContextName) CFRelease (mContextName); +#endif + if (mLogString) delete [] mLogString; +} + +//_____________________________________________________________________________ +// +void AUBase::CreateElements() +{ + if (!mElementsCreated) { + Inputs().Initialize(this, kAudioUnitScope_Input, mInitNumInputEls); + Outputs().Initialize(this, kAudioUnitScope_Output, mInitNumOutputEls); +#if !TARGET_OS_IPHONE + Groups().Initialize(this, kAudioUnitScope_Group, mInitNumGroupEls); + Parts().Initialize(this, kAudioUnitScope_Part, mInitNumPartEls); +#endif + 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(); + + int i; + int nOutputs = Outputs().GetNumberOfElements(); + for (i = 0; i < nOutputs; ++i) { + AUOutputElement *output = GetOutput(i); + output->AllocateBuffer(); // does no work if already allocated + } + int nInputs = Inputs().GetNumberOfElements(); + for (i = 0; i < nInputs; ++i) { + AUInputElement *input = GetInput(i); + input->AllocateBuffer(); // does no work if already allocated + } + mBuffersAllocated = true; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::DoInitialize() +{ + OSStatus result = noErr; + + if (!mInitialized) { + result = Initialize(); + if (result == noErr) { + mHasBegunInitializing = true; + ReallocateBuffers(); // calls CreateElements() + mInitialized = true; // signal that it's okay to render +#if TARGET_OS_WIN32 + MemoryBarrier(); +#else + OSMemoryBarrier(); +#endif + } + } + + return result; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::Initialize() +{ + return noErr; +} + +//_____________________________________________________________________________ +// +void AUBase::PreDestructor() +{ + DoCleanup(); +} + +//_____________________________________________________________________________ +// +void AUBase::DoCleanup() +{ + if (mInitialized) + Cleanup(); + mInitialized = false; + mHasBegunInitializing = false; +} + +//_____________________________________________________________________________ +// +void AUBase::Cleanup() +{ +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::Reset( AudioUnitScope inScope, + AudioUnitElement inElement) +{ + mLastRenderedSampleTime = kNoLastRenderedSampleTime; + 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 !TARGET_OS_IPHONE +#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_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_AU_IS_ONLY_PLUGIN + case kAudioUnitProperty_FastDispatch: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(void *); + outWritable = false; + validateElement = false; + break; +#endif + +#if !TARGET_OS_IPHONE + case kAudioUnitProperty_ContextName: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof(CFStringRef); + outWritable = true; + break; + + case kAudioUnitProperty_GetUIComponentList: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = GetNumCustomUIComponents(); + if (outDataSize == 0) + goto InvalidProperty; + outDataSize *= sizeof (AudioComponentDescription); + + outWritable = false; + break; + + case kAudioUnitProperty_ParameterValueStrings: + result = GetParameterValueStrings(inScope, inElement, NULL); + if (result == noErr) { + outDataSize = sizeof(CFArrayRef); + outWritable = false; + validateElement = false; + } + break; + + case kAudioUnitProperty_HostCallbacks: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + outDataSize = sizeof (HostCallbackInfo); + 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 // !TARGET_OS_IPHONE + + case 'lrst' : // kAudioUnitProperty_LastRenderedSampleTime + outDataSize = sizeof(Float64); + outWritable = false; + 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_ClassInfo: + { + *(CFPropertyListRef *)outData = NULL; + result = SaveState((CFPropertyListRef *)outData); + } + break; + + case kAudioUnitProperty_FactoryPresets: + { + *(CFArrayRef *)outData = NULL; + result = GetPresets ((CFArrayRef *)outData); + } + break; + + case kAudioUnitProperty_PresentPreset: +#if !TARGET_OS_IPHONE +#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; + UInt32 num = SupportedNumChannels (&infoPtr); + 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 + + +#if !CA_AU_IS_ONLY_PLUGIN + case kAudioUnitProperty_FastDispatch: + switch (inElement) { + case kAudioUnitGetParameterSelect: + *(AudioUnitGetParameterProc *)outData = (AudioUnitGetParameterProc)AudioUnitBaseGetParameter; + break; + case kAudioUnitSetParameterSelect: + *(AudioUnitSetParameterProc *)outData = (AudioUnitSetParameterProc)AudioUnitBaseSetParameter; + break; + case kAudioUnitRenderSelect: + if (AudioUnitAPIVersion() > 1) + *(AudioUnitRenderProc *)outData = (AudioUnitRenderProc)AudioUnitBaseRender; + else result = kAudioUnitErr_InvalidElement; + break; + default: + result = GetProperty(inID, inScope, inElement, outData); + break; + } + break; +#endif + +#if !TARGET_OS_IPHONE + case kAudioUnitProperty_ParameterValueStrings: + result = GetParameterValueStrings(inScope, inElement, (CFArrayRef *)outData); + break; + + case kAudioUnitProperty_IconLocation: + { + CFURLRef iconLocation = CopyIconLocation(); + if (iconLocation) { + *(CFURLRef*)outData = iconLocation; + } else + result = kAudioUnitErr_InvalidProperty; + } + break; + + case kAudioUnitProperty_HostCallbacks: + *(HostCallbackInfo *)outData = mHostCallbackInfo; + break; + + case kAudioUnitProperty_GetUIComponentList: + GetUIComponentDescs ((ComponentDescription*)outData); + 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 // !TARGET_OS_IPHONE + + case 'lrst' : // kAudioUnitProperty_LastRenderedSampleTime + *(Float64*)outData = mLastRenderedSampleTime; + 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); + ca_require(inDataSize >= offsetof(AudioChannelLayout, mChannelDescriptions) + 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 !TARGET_OS_IPHONE +#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) + { + CFRelease (mCurrentPreset.presetName); + mCurrentPreset = newPreset; + CFRetain (mCurrentPreset.presetName); + 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 !TARGET_OS_IPHONE + case kAudioUnitProperty_SetExternalBuffer: + ca_require(inDataSize >= sizeof(AudioUnitExternalBuffer), InvalidPropertyValue); + ca_require(IsInitialized(), Uninitialized); + { + AudioUnitExternalBuffer &buf = *(AudioUnitExternalBuffer*)inData; + if (intptr_t(buf.buffer) & 0x0F) result = paramErr; + 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; + + case kAudioUnitProperty_HostCallbacks: + { + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + UInt32 availSize = (inDataSize < sizeof (mHostCallbackInfo) ? inDataSize : sizeof (mHostCallbackInfo)); + bool hasChanged = !memcmp (&mHostCallbackInfo, inData, availSize); + memset (&mHostCallbackInfo, 0, sizeof (mHostCallbackInfo)); + memcpy (&mHostCallbackInfo, inData, availSize); + if (hasChanged) + PropertyChanged(inID, inScope, inElement); + break; + } +#endif // !TARGET_OS_IPHONE + + 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 !TARGET_OS_IPHONE +Uninitialized: + return kAudioUnitErr_Uninitialized; +#endif +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || TARGET_OS_IPHONE +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 !TARGET_OS_IPHONE + case kAudioUnitProperty_ContextName: + if (mContextName) CFRelease(mContextName); + mContextName = NULL; + result = noErr; + break; + + 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 // !TARGET_OS_IPHONE + + default: + result = RemovePropertyValue (inID, inScope, inElement); + break; + } + + return result; +#if !TARGET_OS_IPHONE +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 = 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 paramErr; + + 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) +{ +#if !TARGET_OS_IPHONE + if (inScope == kAudioUnitScope_Group) { + return GetGroupParameter (inID, inElement, outValue); + } +#endif + + AUElement *elem = SafeGetElement(inScope, inElement); + outValue = elem->GetParameter(inID); + return noErr; +} + + +//_____________________________________________________________________________ +// +OSStatus AUBase::SetParameter( AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + AudioUnitParameterValue inValue, + UInt32 inBufferOffsetInFrames) +{ +#if !TARGET_OS_IPHONE + if (inScope == kAudioUnitScope_Group) { + return SetGroupParameter (inID, inElement, inValue, inBufferOffsetInFrames); + } +#endif + + AUElement *elem = SafeGetElement(inScope, inElement); + elem->SetParameter(inID, inValue); + return noErr; +} + +#if !TARGET_OS_IPHONE +//_____________________________________________________________________________ +// +OSStatus AUBase::SetGroupParameter( AudioUnitParameterID inID, + AudioUnitElement inElement, + AudioUnitParameterValue inValue, + UInt32 inBufferOffsetInFrames) +{ + return kAudioUnitErr_InvalidScope; +} + +//_____________________________________________________________________________ +// +OSStatus AUBase::GetGroupParameter( AudioUnitParameterID inID, + AudioUnitElement inElement, + AudioUnitParameterValue & outValue) +{ + return kAudioUnitErr_InvalidScope; +} +#endif + +//_____________________________________________________________________________ +// +OSStatus AUBase::ScheduleParameter ( const AudioUnitParameterEvent *inParameterEvent, + UInt32 inNumEvents) +{ + 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); + } + 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; + + CATRACE(kCATrace_AUBaseRenderStart, (int)this, inBusNumber, inFramesToProcess, 0); + DISABLE_DENORMALS + + try { + ca_require(IsInitialized(), Uninitialized); + ca_require(mAudioUnitAPIVersion >= 2, ParamErr); + ca_require(inFramesToProcess <= mMaxFramesPerSlice, TooManyFrames); + + 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; paramErr", + __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. paramErr. + DebugMessageN7("%s:%d %u frames, %u bytes/frame, expected %u-byte buffer; ioData.mBuffers[%u].mDataByteSize=%u; paramErr", + __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; + CATRACE(kCATrace_AUBaseRenderCallbackStart, (int)this, (int)rc.mRenderNotify, 1, 0); + (*(AURenderCallback)rc.mRenderNotify)(rc.mRenderNotifyRefCon, + &flags, + &inTimeStamp, inBusNumber, inFramesToProcess, &ioData); + CATRACE(kCATrace_AUBaseRenderCallbackEnd, (int)this, (int)rc.mRenderNotify, 1, 0); + } + } + + theError = DoRenderBus(ioActionFlags, inTimeStamp, inBusNumber, output, inFramesToProcess, ioData); + + flags = ioActionFlags | kAudioUnitRenderAction_PostRender; + + if (SetRenderError (theError)) { + flags |= kAudioUnitRenderAction_PostRenderError; + } + + if (mRenderCallbacksTouched) { + for (rcit = mRenderCallbacks.begin(); rcit != mRenderCallbacks.end(); ++rcit) { + RenderCallback &rc = *rcit; + CATRACE(kCATrace_AUBaseRenderCallbackStart, (int)this, (int)rc.mRenderNotify, 2, 0); + (*(AURenderCallback)rc.mRenderNotify)(rc.mRenderNotifyRefCon, + &flags, + &inTimeStamp, inBusNumber, inFramesToProcess, &ioData); + CATRACE(kCATrace_AUBaseRenderCallbackEnd, (int)this, (int)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 + CATRACE(kCATrace_AUBaseRenderEnd, (int)this, theError, 0, 0); + + return theError; + +Uninitialized: theError = kAudioUnitErr_Uninitialized; goto errexit; +ParamErr: theError = paramErr; goto errexit; +TooManyFrames: theError = kAudioUnitErr_TooManyFramesToProcess; goto errexit; +errexit: + DebugMessageN2 (" from %s, render 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); + AudioUnitElement nElems = scope.GetNumberOfElements(); + for (AudioUnitElement ielem = 0; ielem < nElems; ++ielem) { + AUElement *element = scope.GetElement(ielem); + UInt32 nparams = element->GetNumberOfParameters(); + if (nparams > 0) { + struct { + UInt32 scope; + UInt32 element; + } hdr; + + hdr.scope = CFSwapInt32HostToBig(iscope); + hdr.element = CFSwapInt32HostToBig(ielem); + CFDataAppendBytes(data, (UInt8 *)&hdr, sizeof(hdr)); + + element->SaveState(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); + } + +#if !TARGET_OS_IPHONE +// Does the unit support the CPULoad Quality property - if so, save it... + Float32 cpuLoad; + result = DispatchGetProperty (kAudioUnitProperty_CPULoad, + kAudioUnitScope_Global, + 0, + &cpuLoad); + + if (result == noErr) { + CFNumberRef num = CFNumberCreate (NULL, kCFNumberFloatType, &cpuLoad); + CFDictionarySetValue (dict, kCPULoadString, num); + CFRelease (num); + } +#endif + +// 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) { + struct { + UInt32 scope; + UInt32 element; + } hdr; + + hdr.scope = CFSwapInt32BigToHost(*(UInt32 *)p); p += sizeof(UInt32); + hdr.element = CFSwapInt32BigToHost(*(UInt32 *)p); p += sizeof(UInt32); + + AUScope &scope = GetScope(hdr.scope); + AUElement *element = scope.GetElement(hdr.element); + // $$$ order of operations issue: what if the element does not yet exist? + // then we just break out of the loop + if (!element) + break; + p = element->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 !TARGET_OS_IPHONE +#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)); + } + +#if !TARGET_OS_IPHONE +// 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 (kAudioUnitProperty_CPULoad, + kAudioUnitScope_Global, + 0, + &floatValue, + sizeof(floatValue)); + } +#endif + +// 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) + { + sprintf (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; +} + + // 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; +} + +int AUBase::GetNumCustomUIComponents () +{ + return 0; +} + +#if !TARGET_OS_IPHONE +void AUBase::GetUIComponentDescs (ComponentDescription* inDescArray) {} +#endif + +bool AUBase::HasIcon () +{ + CFURLRef url = CopyIconLocation(); + if (url) { + CFRelease (url); + return true; + } + 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::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 AUGlobalElement(this); + case kAudioUnitScope_Input: + return new AUInputElement(this); + case kAudioUnitScope_Output: + return new AUOutputElement(this); +#if !TARGET_OS_IPHONE + case kAudioUnitScope_Group: + return new AUGroupElement(this); + case kAudioUnitScope_Part: + return new AUPartElement(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.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_cast(this)->mLogString = new char[256]; + char str[24]; + char str1[24]; + char str2[24]; + sprintf (const_cast(this)->mLogString, "AU (%p): %s %s %s", + GetComponentInstance(), + CAStringForOSType(desc.componentType, str), + CAStringForOSType(desc.componentSubType, str1), + CAStringForOSType(desc.componentManufacturer, str2)); + + return mLogString; +} + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.h new file mode 100755 index 00000000..18e0981e --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.h @@ -0,0 +1,893 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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 "ComponentBase.h" +#include "AUScopeElement.h" +#include "AUInputElement.h" +#include "AUOutputElement.h" +#include "AUBuffer.h" +#include "CAMath.h" +#include "CAThreadSafeList.h" +#include "CAVectorUnit.h" + +#if 0 && DEBUG + #include "CATrace.h" +#else + #define CATRACE(code, a, b, c, d) +#endif + +typedef AUElement AUGlobalElement; +#if !TARGET_OS_IPHONE + typedef AUElement AUGroupElement; + typedef AUElement AUPartElement; +#endif + + + +// ________________________________________________________________________ +// 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 AUDebugDispatcher; + +// ________________________________________________________________________ + +/*! @class AUBase */ +class AUBase : public ComponentBase, public AUElementCreator { +public: + + /*! @ctor AUBase */ + AUBase( AudioComponentInstance inInstance, + UInt32 numInputElements, + UInt32 numOutputElements, + UInt32 numGroupElements = 0, + UInt32 numPartElements = 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. + + // ________________________________________________________________________ + // 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); + +#if !TARGET_OS_IPHONE + /*! @method SetGroupParameter */ + virtual OSStatus SetGroupParameter( AudioUnitParameterID inID, + AudioUnitElement inElement, + AudioUnitParameterValue inValue, + UInt32 inBufferOffsetInFrames); + + /*! @method GetGroupParameter */ + virtual OSStatus GetGroupParameter( AudioUnitParameterID inID, + AudioUnitElement inElement, + AudioUnitParameterValue & outValue); +#endif + + /*! @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); + + + // 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.mSampleTime)) + 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; + } + + + 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); + + /*! @method SaveState */ + virtual OSStatus SaveState( CFPropertyListRef * 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 GetNumCustomUIComponents */ + virtual int GetNumCustomUIComponents (); +#if !TARGET_OS_IPHONE + /*! @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 !TARGET_OS_IPHONE + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch( ComponentParameters * params, + AUBase * This); +#endif + + // ________________________________________________________________________ + // Methods useful for subclasses + + /*! @method GetScope */ + AUScope & GetScope( AudioUnitScope inScope) + { + if (inScope >= kNumScopes) COMPONENT_THROW(kAudioUnitErr_InvalidScope); + return mScopes[inScope]; + } + + /*! @method GlobalScope */ + AUScope & GlobalScope() { return mScopes[kAudioUnitScope_Global]; } + /*! @method Inputs */ + AUScope & Inputs() { return mScopes[kAudioUnitScope_Input]; } + /*! @method Outputs */ + AUScope & Outputs() { return mScopes[kAudioUnitScope_Output]; } + /*! @method Groups */ +#if !TARGET_OS_IPHONE + AUScope & Groups() { return mScopes[kAudioUnitScope_Group]; } + /*! @method Parts */ + AUScope & Parts() { return mScopes[kAudioUnitScope_Part]; } +#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 !TARGET_OS_IPHONE + /*! @method GetGroup */ + AUGroupElement * GetGroup( AudioUnitElement inElement) + { + return static_cast(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 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 */ + void PropertyChanged( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement); + +#if !TARGET_OS_IPHONE + // 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; + +protected: + // ________________________________________________________________________ + // AUElementCreator override, may be further overridden by subclasses + /*! @method CreateElement */ + virtual AUElement * CreateElement( AudioUnitScope scope, + AudioUnitElement element); + + /*! @method ReallocateBuffers */ + virtual void ReallocateBuffers(); + // needs to be called when mMaxFramesPerSlice changes + + /*! @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); + CATRACE(kCATrace_AUBaseDoRenderBus, inNumberFrames, (int)theOutput->GetBufferList().mBuffers[0].mData, 0, *(UInt32 *)ioData.mBuffers[0].mData); + } else { + theOutput->CopyBufferContentsTo(ioData); + CATRACE(kCATrace_AUBaseDoRenderBus, inNumberFrames, (int)theOutput->GetBufferList().mBuffers[0].mData, (int)ioData.mBuffers[0].mData, *(UInt32 *)ioData.mBuffers[0].mData); + theOutput->InvalidateBufferList(); + } + } + return result; + } + + /*! @method HasIcon */ + bool HasIcon (); + +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( Float64 inSampleTime) + { + bool needsToRender = fnotequal(inSampleTime, mLastRenderedSampleTime); + mLastRenderedSampleTime = inSampleTime; + 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... + + // ________________________________________________________________________ + // 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 TARGET_OS_IPHONE + enum { kNumScopes = 3 }; +#else + enum { kNumScopes = 5 }; +#endif + + /*! @var mElementsCreated */ + bool mElementsCreated; +protected: + /*! @var mInitialized */ + bool mInitialized; + /*! @var mHasBegunInitializing */ + bool mHasBegunInitializing; +private: + /*! @var mAudioUnitAPIVersion */ + UInt8 mAudioUnitAPIVersion; + + /*! @var mInitNumInputEls */ + UInt32 mInitNumInputEls; + /*! @var mInitNumOutputEls */ + UInt32 mInitNumOutputEls; +#if !TARGET_OS_IPHONE + /*! @var mInitNumGroupEls */ + UInt32 mInitNumGroupEls; + /*! @var mInitNumPartEls */ + UInt32 mInitNumPartEls; +#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 mLastRenderedSampleTime */ + Float64 mLastRenderedSampleTime; + + /*! @var mMaxFramesPerSlice */ + UInt32 mMaxFramesPerSlice; + + /*! @var mLastRenderError */ + OSStatus mLastRenderError; + /*! @var mCurrentPreset */ + AUPreset mCurrentPreset; + +protected: + 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; + +private: + /*! @var sVectorUnitType */ + static SInt32 sVectorUnitType; + +#if !TARGET_OS_IPHONE +protected: + /*! @var mHostCallbackInfo */ + HostCallbackInfo mHostCallbackInfo; + + /*! @var mContextInfo */ + CFStringRef mContextName; + +public: + AUDebugDispatcher* mDebugDispatcher; +#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 !TARGET_OS_IPHONE + 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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUDispatch.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUDispatch.cpp new file mode 100755 index 00000000..cd3e4b51 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUDispatch.cpp @@ -0,0 +1,477 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "AUBase.h" +#include "CAXException.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 + + +#if AU_DEBUG_DISPATCHER + #include "AUDebugDispatcher.h" + + #define INIT_DEBUG_DISPATCHER(This) \ + UInt64 nowTime = 0; \ + if (This->mDebugDispatcher != NULL) \ + nowTime = CAHostTimeBase::GetTheCurrentTime(); +#endif + +OSStatus AUBase::ComponentEntryDispatch(ComponentParameters *params, AUBase *This) +{ + if (This == NULL) return paramErr; + +#if AU_DEBUG_DISPATCHER + INIT_DEBUG_DISPATCHER(This) +#endif + + OSStatus result = noErr; + + switch (params->what) { + case kComponentCanDoSelect: + switch (params->params[0]) { + // 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: + { + result = This->DoInitialize(); + + #if AU_DEBUG_DISPATCHER + if (This->mDebugDispatcher) + This->mDebugDispatcher->Initialize (nowTime, result); + #endif + } + break; + + case kAudioUnitUninitializeSelect: + { + This->DoCleanup(); + result = noErr; + + #if AU_DEBUG_DISPATCHER + if (This->mDebugDispatcher) + This->mDebugDispatcher->Uninitialize (nowTime, result); + #endif + } + break; + + case kAudioUnitGetPropertyInfoSelect: + { + 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; + + #if AU_DEBUG_DISPATCHER + if (This->mDebugDispatcher) + This->mDebugDispatcher->GetPropertyInfo (nowTime, result, pinID, pinScope, pinElement, + poutDataSize, poutWritable); + #endif + + + } + break; + + case kAudioUnitGetPropertySelect: + { + 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 = paramErr; + goto finishGetProperty; + } + if (poutData == NULL) { + UInt32 dataSize; + Boolean writable; + + 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 = paramErr; + 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) + { + memcpy(poutData, tempBuffer, clientBufferSize); + delete[] tempBuffer; + // pioDataSize remains correct, the number of bytes we wrote + } else + *pioDataSize = actualPropertySize; + } else + *pioDataSize = 0; + + finishGetProperty: + + #if AU_DEBUG_DISPATCHER + if (This->mDebugDispatcher) + This->mDebugDispatcher->GetProperty (nowTime, result, pinID, pinScope, pinElement, + pioDataSize, poutData); + #else + ; + #endif + + } + break; + + case kAudioUnitSetPropertySelect: + { + 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 = paramErr; + goto finishSetProperty; + } + + if (pinDataSize == 0) { + ca_debug_string("AudioUnitSetProperty: inDataSize == 0"); + result = paramErr; + goto finishSetProperty; + } + } + } + finishSetProperty: + + #if AU_DEBUG_DISPATCHER + if (This->mDebugDispatcher) + This->mDebugDispatcher->SetProperty (nowTime, result, pinID, pinScope, pinElement, + pinData, pinDataSize); + #else + ; + #endif + + } + break; + + case kAudioUnitAddPropertyListenerSelect: + { + 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: + { + PARAM(AudioUnitPropertyID, pinID, 0, 2); + PARAM(AudioUnitPropertyListenerProc, pinProc, 1, 2); + result = This->RemovePropertyListener(pinID, pinProc, NULL, false); + } + break; +#endif + + case kAudioUnitRemovePropertyListenerWithUserDataSelect: + { + 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: + { + PARAM(AURenderCallback, pinProc, 0, 2); + PARAM(void *, pinProcRefCon, 1, 2); + result = This->SetRenderNotification (pinProc, pinProcRefCon); + } + break; + + case kAudioUnitRemoveRenderNotifySelect: + { + PARAM(AURenderCallback, pinProc, 0, 2); + PARAM(void *, pinProcRefCon, 1, 2); + result = This->RemoveRenderNotification (pinProc, pinProcRefCon); + } + break; + + case kAudioUnitGetParameterSelect: + { + PARAM(AudioUnitParameterID, pinID, 0, 4); + PARAM(AudioUnitScope, pinScope, 1, 4); + PARAM(AudioUnitElement, pinElement, 2, 4); + PARAM(AudioUnitParameterValue *, poutValue, 3, 4); + result = (poutValue == NULL ? paramErr : This->GetParameter(pinID, pinScope, pinElement, *poutValue)); + } + break; + + case kAudioUnitSetParameterSelect: + { + 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: + { + 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: + { + { + 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 = paramErr; + else { + if (pinActionFlags == NULL) { + tempFlags = 0; + pinActionFlags = &tempFlags; + } + result = This->DoRender(*pinActionFlags, *pinTimeStamp, pinOutputBusNumber, pinNumberFrames, *pioData); + } + + #if AU_DEBUG_DISPATCHER + if (This->mDebugDispatcher) + This->mDebugDispatcher->Render (nowTime, result, pinActionFlags, pinTimeStamp, + pinOutputBusNumber, pinNumberFrames, pioData); + #endif + } + } + break; + + case kAudioUnitResetSelect: + { + PARAM(AudioUnitScope, pinScope, 0, 2); + PARAM(AudioUnitElement, pinElement, 1, 2); + This->mLastRenderedSampleTime = -1; + 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 AudioUnitBaseGetParameter( AUBase * This, + AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + float *outValue) +{ + OSStatus result = AUBase::noErr; + + try { + if (This == NULL || outValue == NULL) return AUBase::paramErr; + result = This->GetParameter(inID, inScope, inElement, *outValue); + } + COMPONENT_CATCH + + return result; +} + +OSStatus AudioUnitBaseSetParameter( AUBase * This, + AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + float inValue, + UInt32 inBufferOffset) +{ + OSStatus result = AUBase::noErr; + + try { + if (This == NULL) return AUBase::paramErr; + result = This->SetParameter(inID, inScope, inElement, inValue, inBufferOffset); + } + COMPONENT_CATCH + + return result; +} + +OSStatus AudioUnitBaseRender( AUBase * This, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData) +{ + if (inTimeStamp == NULL || ioData == NULL) return AUBase::paramErr; + +#if AU_DEBUG_DISPATCHER + INIT_DEBUG_DISPATCHER(This) +#endif + + OSStatus result = AUBase::noErr; + AudioUnitRenderActionFlags tempFlags; + + try { + if (ioActionFlags == NULL) { + tempFlags = 0; + ioActionFlags = &tempFlags; + } + result = This->DoRender(*ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, *ioData); + } + COMPONENT_CATCH + + #if AU_DEBUG_DISPATCHER + if (This->mDebugDispatcher) + This->mDebugDispatcher->Render (nowTime, result, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); + #endif + + return result; +} diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUDispatch.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUDispatch.h new file mode 100755 index 00000000..ac0329d9 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUDispatch.h @@ -0,0 +1,71 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __AUDispatch_h__ +#define __AUDispatch_h__ + +// Fast dispatch function prototypes + +#include + +/*! @function AudioUnitBaseGetParameter */ +OSStatus AudioUnitBaseGetParameter( AUBase * This, + AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + float * outValue); + +/*! @function AudioUnitBaseSetParameter */ +OSStatus AudioUnitBaseSetParameter( AUBase * This, + AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + float inValue, + UInt32 inBufferOffset); + +/*! @function AudioUnitBaseRender */ +OSStatus AudioUnitBaseRender( AUBase * This, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData); + +#endif // __AUDispatch_h__ diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUInputElement.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUInputElement.cpp new file mode 100755 index 00000000..82085534 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUInputElement.cpp @@ -0,0 +1,146 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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; + mConnRenderProc = NULL; + AllocateBuffer(); + +#if !CA_AU_IS_ONLY_PLUGIN + UInt32 size = sizeof(AudioUnitRenderProc); + OSStatus result = AudioUnitGetProperty( conn.sourceAudioUnit, + kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, + kAudioUnitRenderSelect, + &mConnRenderProc, + &size); + if (result == noErr) + mConnInstanceStorage = GetComponentInstanceStorage (conn.sourceAudioUnit); + else + mConnRenderProc = NULL; +#else // !TARGET_OS_IPHONE + mConnInstanceStorage = NULL; + 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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUInputElement.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUInputElement.h new file mode 100755 index 00000000..59556b3f --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUInputElement.h @@ -0,0 +1,111 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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; + /*! @var mConnRenderProc */ + AudioUnitRenderProc mConnRenderProc; + /*! @var mConnInstanceStorage */ + void * mConnInstanceStorage; // for the input component +}; + + +#endif // __AUInput_h__ diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUOutputElement.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUOutputElement.cpp new file mode 100755 index 00000000..5074c1cb --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUOutputElement.cpp @@ -0,0 +1,56 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUOutputElement.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUOutputElement.h new file mode 100755 index 00000000..367064f2 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUOutputElement.h @@ -0,0 +1,60 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUResources.r b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUResources.r new file mode 100755 index 00000000..acef631a --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUResources.r @@ -0,0 +1,134 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// 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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUScopeElement.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUScopeElement.cpp new file mode 100755 index 00000000..fe02061f --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUScopeElement.cpp @@ -0,0 +1,506 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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; +} + +//_____________________________________________________________________________ +// +// 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 = 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 = 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(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 = GetCreator()->CreateElement(GetScope(), 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 and if not create them + bool didAddElements = false; + unsigned int maxElNum = 0; + + int dictSize = 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; + CFStringGetCString (keys[i], string, 32, kCFStringEncodingASCII); + sscanf (string, "%u", &intKey); + if (UInt32(intKey) > maxElNum) + maxElNum = intKey; + } + + if (maxElNum >= GetNumberOfElements()) { + SetNumberOfElements (maxElNum+1); + didAddElements = true; + } + + // OK, now we have the number of elements that we need - lets restate their names + for (int i = 0; i < dictSize; i++) + { + CFStringRef elName = reinterpret_cast(CFDictionaryGetValue (inNameDict, keys[i])); + int intKey; + CFStringGetCString (keys[i], string, 32, kCFStringEncodingASCII); + sscanf (string, "%d", &intKey); + GetElement (intKey)->SetName (elName); + } + free (keys); + + return didAddElements; +} + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUScopeElement.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUScopeElement.h new file mode 100755 index 00000000..bb55f763 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUScopeElement.h @@ -0,0 +1,535 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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.0), mValue2(0.0), 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 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 */ + UInt32 GetNumberOfParameters() + { + if(mUseIndexedParameters) return mIndexedParameters.size(); else return mParameters.size(); + } +/*! @method GetParameterList */ + void GetParameterList(AudioUnitParameterID *outList); + +/*! @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); + +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 DeallocateBuffer */ + void SetWillAllocateBuffer(bool inFlag) { + mWillAllocate = inFlag; + } +/*! @method DeallocateBuffer */ + 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); + } + 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 (); + +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; +}; + +// ____________________________________________________________________________ +// +/*! @class AUElementCreator */ +class AUElementCreator { +public: +/*! @method CreateElement */ + virtual AUElement * CreateElement(AudioUnitScope scope, AudioUnitElement element) = 0; + virtual ~AUElementCreator() { } +}; + +// ____________________________________________________________________________ +// +// 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 */ + virtual void Initialize( AUElementCreator *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; + + AUElementCreator * GetCreator() const { return mCreator; } + AudioUnitScope GetScope() const { return mScope; } + + +private: +/*! @var mCreator */ + AUElementCreator * 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(AUElementCreator *creator, + AudioUnitScope scope, + UInt32 numElements) + { + if (mDelegate) + return mDelegate->Initialize(creator, scope, numElements); + + mCreator = creator; + mScope = scope; + SetNumberOfElements(numElements); + } + +/*! @method SetNumberOfElements */ + void SetNumberOfElements(UInt32 numElements); + +/*! @method GetNumberOfElements */ + UInt32 GetNumberOfElements() const + { + if (mDelegate) + return mDelegate->GetNumberOfElements(); + + return 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; + #if !CA_NO_RTTI + if (element == NULL || (ioel = dynamic_cast(element)) == NULL) + COMPONENT_THROW (kAudioUnitErr_InvalidElement); + #else + if (element == NULL || (ioel = static_cast(element)) == NULL) + COMPONENT_THROW (kAudioUnitErr_InvalidElement); + #endif + return ioel; + } + +/*! @method HasElementWithName */ + bool HasElementWithName () const; + +/*! @method AddElementNamesToDict */ + void AddElementNamesToDict (CFMutableDictionaryRef & inNameDict); + + bool RestoreElementNames (CFDictionaryRef& inNameDict); + + AUElementCreator * GetCreator() const { return mCreator; } + AudioUnitScope GetScope() const { return mScope; } + + void SetDelegate(AUScopeDelegate* inDelegate) { mDelegate = inDelegate; } + +private: + typedef std::vector ElementVector; +/*! @var mCreator */ + AUElementCreator * mCreator; +/*! @var mScope */ + AudioUnitScope mScope; +/*! @var mElements */ + ElementVector mElements; +/*! @var mDelegate */ + AUScopeDelegate * mDelegate; +}; + + + +#endif // __AUScopeElement_h__ diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/ComponentBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/ComponentBase.cpp new file mode 100755 index 00000000..38e2f064 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/ComponentBase.cpp @@ -0,0 +1,189 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "ComponentBase.h" +#include "CAXException.h" + +#if TARGET_OS_MAC +pthread_mutex_t ComponentInitLocker::sComponentOpenMutex = PTHREAD_MUTEX_INITIALIZER; +#elif TARGET_OS_WIN32 +CAGuard ComponentInitLocker::sComponentOpenGuard("sComponentOpenGuard"); +#endif + +#if CA_DO_NOT_USE_AUDIO_COMPONENT + #include +#endif + +ComponentBase::~ComponentBase() +{ +} + +void ComponentBase::PostConstructor() +{ +} + +void ComponentBase::PreDestructor() +{ +} + +#if !TARGET_OS_IPHONE +OSStatus ComponentBase::Version() +{ + return 0x00000001; +} + +OSStatus ComponentBase::ComponentEntryDispatch(ComponentParameters *p, ComponentBase *This) +{ + if (This == NULL) return paramErr; + + OSStatus result = noErr; + + switch (p->what) { + case kComponentCloseSelect: + This->PreDestructor(); + delete This; + break; + + case kComponentVersionSelect: + result = This->Version(); + break; + + case kComponentCanDoSelect: + switch (p->params[0]) { + case kComponentOpenSelect: + case kComponentCloseSelect: + case kComponentVersionSelect: + case kComponentCanDoSelect: + return 1; + default: + return 0; + } + + default: + result = badComponentSelector; + break; + } + return result; +} +#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; + +#if CA_DO_NOT_USE_AUDIO_COMPONENT + ca_require_noerr (result = ComponentBase_GetComponentDescription (mComponentInstance, desc), home); +#else + AudioComponent comp = AudioComponentInstanceGetComponent(mComponentInstance); + XAssert (comp); + if (comp) { + ca_require_noerr(result = AudioComponentGetDescription(comp, &desc), home); + } else + ca_require_noerr(result = -1, home); +#endif + +home: + if (result) + memset (&desc, 0, sizeof(AudioComponentDescription)); + return desc; +} + + +#if CA_DO_NOT_USE_AUDIO_COMPONENT +OSStatus ComponentBase_GetComponentDescription (const AudioComponentInstance & inInstance, AudioComponentDescription & outDesc) +{ + // we prefer to use the new API. If it is not available however, we have to go back to using the ComponentMgr one. + typedef AudioComponent (*AudioComponentInstanceGetComponentProc) (AudioComponentInstance); + static AudioComponentInstanceGetComponentProc aciGCProc = NULL; + + typedef OSStatus (*AudioComponentGetDescriptionProc)(AudioComponent, AudioComponentDescription *); + static AudioComponentGetDescriptionProc acGDProc = NULL; + + typedef OSErr (*GetComponentInfoProc)(Component, ComponentDescription *, void*, void*, void*); + static GetComponentInfoProc gciProc = NULL; + + static int doneInit = 0; + if (doneInit == 0) { + doneInit = 1; + bool loadCMgr = true; + + void* theImage = dlopen("/System/Library/Frameworks/AudioUnit.framework/AudioUnit", RTLD_LAZY); + if (theImage != NULL) + { + // we assume that all routine names passed here have a leading underscore which gets shaved + // off when passed to dlsym + aciGCProc = (AudioComponentInstanceGetComponentProc)dlsym (theImage, "AudioComponentInstanceGetComponent"); + if (aciGCProc) { + acGDProc = (AudioComponentGetDescriptionProc)dlsym (theImage, "AudioComponentGetDescription"); + if (acGDProc) + loadCMgr = false; + } + } + if (loadCMgr) { + theImage = dlopen("/System/Library/Frameworks/CoreServices.framework/CoreServices", RTLD_LAZY); + if (theImage != NULL) + { + gciProc = (GetComponentInfoProc)dlsym (theImage, "GetComponentInfo"); + } + } + } + + OSStatus result = noErr; + if (acGDProc && aciGCProc) { + AudioComponent comp = (*aciGCProc)(inInstance); + XAssert (comp); + if (comp) { + ca_require_noerr(result = (*acGDProc)(comp, &outDesc), home); + } else + ca_require_noerr(result = -1, home); + + } else if (gciProc) { + // in this case we know that inInstance is directly castable to a Component + ca_require_noerr(result = (*gciProc)((Component)inInstance, (ComponentDescription*)&outDesc, NULL, NULL, NULL), home); + } +home: + return result; +} +#endif //CA_DO_NOT_USE_AUDIO_COMPONENT diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/ComponentBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/ComponentBase.h new file mode 100755 index 00000000..f60bd3f6 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/ComponentBase.h @@ -0,0 +1,226 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __ComponentBase_h__ +#define __ComponentBase_h__ + +#include +#include "CADebugMacros.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include + + #if !TARGET_OS_IPHONE + #include + + #if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) + #define AudioComponentInstance ComponentInstance + #define AudioComponentDescription ComponentDescription + #define AudioComponent Component + #define CA_DO_NOT_USE_AUDIO_COMPONENT 1 + #endif + #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 + + #include +#else + #include "CoreAudioTypes.h" + #include "Components.h" + #include "AudioUnit.h" + #include "CAGuard.h" +#endif + +#ifndef COMPONENT_THROW + #if VERBOSE_COMPONENT_THROW + #define COMPONENT_THROW(err) \ + do { DebugMessage(#err); throw static_cast(err); } while (0) + #else + #define COMPONENT_THROW(err) \ + throw static_cast(err) + #endif +#endif + +#define COMPONENT_CATCH \ + catch (std::bad_alloc &) { result = -108/*memFullErr*/; } \ + catch (OSStatus err) { result = err; } \ + catch (OSErr err) { result = err; } \ + catch (...) { result = -1; } + +class ComponentInitLocker +{ +#if TARGET_OS_MAC +public: + ComponentInitLocker() { pthread_mutex_lock(&sComponentOpenMutex); } + ~ComponentInitLocker() { pthread_mutex_unlock(&sComponentOpenMutex); } +private: + static pthread_mutex_t sComponentOpenMutex; +#elif TARGET_OS_WIN32 +public: + bool sNeedsUnlocking; + ComponentInitLocker() { sNeedsUnlocking = sComponentOpenGuard.Lock(); } + ~ComponentInitLocker() { if(sNeedsUnlocking) { sComponentOpenGuard.Unlock(); } } +private: + static CAGuard sComponentOpenGuard; +#endif +}; + +#if !TARGET_OS_IPHONE + /*! @class ComponentEntryPoint */ +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; + + 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 + + #if !CA_AU_IS_ONLY_PLUGIN + SetComponentInstanceStorage(ci, (Handle)This); + #endif + } 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; + } +}; + +#if TARGET_OS_MAC && TARGET_CPU_PPC && !TARGET_RT_MAC_MACHO + // for OS 9, a PPC native component's entry point must be a routine descriptor + #define 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); \ + } \ + \ + struct RoutineDescriptor Class##EntryRD = \ + BUILD_ROUTINE_DESCRIPTOR((kPascalStackBased | RESULT_SIZE (kFourByteCode) | \ + STACK_ROUTINE_PARAMETER (1, kFourByteCode) | \ + STACK_ROUTINE_PARAMETER (2, kFourByteCode)), Class##Entry); +#else + #define 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); \ + } +#endif + + /*! @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) +#endif // !TARGET_OS_IPHONE + + + /*! @class ComponentBase */ +class ComponentBase { +public: + // classic MacErrors + enum { noErr = 0, paramErr = -50, memFullErr = -108 }; + + /*! @ctor ComponentBase */ + ComponentBase(AudioComponentInstance inInstance) : mComponentInstance(inInstance) { } + /*! @dtor ~ComponentBase */ + virtual ~ComponentBase(); + + /*! @method PostConstructor */ + virtual void PostConstructor(); + + /*! @method PreDestructor */ + virtual void PreDestructor(); + +#if !TARGET_OS_IPHONE + /*! @method Version */ + virtual OSStatus Version(); + + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch(ComponentParameters *p, ComponentBase *This); +#endif + + /*! @method GetComponentInstance */ + AudioComponentInstance GetComponentInstance() const { return mComponentInstance; } + + /*! @method GetComponentDescription */ + AudioComponentDescription GetComponentDescription() const; + +protected: + /*! @var mComponentInstance */ + AudioComponentInstance mComponentInstance; +}; + +#endif // __ComponentBase_h__ diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.cpp new file mode 100755 index 00000000..55ccf833 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.cpp @@ -0,0 +1,386 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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 (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); +} + +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) +{ + 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; +} + +OSStatus AUCarbonViewBase::CreateUI(Float32 inXOffset, Float32 inYOffset) +{ + return noErr; +} + +OSStatus AUCarbonViewBase::EmbedControl(ControlRef ctl) +{ + 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); +} + +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) +{ + 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 = { mBottomRight.h, 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; + } + + 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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.h new file mode 100755 index 00000000..e97ef61b --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.h @@ -0,0 +1,182 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.cpp new file mode 100755 index 00000000..12e4534b --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.cpp @@ -0,0 +1,667 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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)); +#else + SetControlReference(control, SInt32(this)); +#endif +} + +AUCarbonViewControl::~AUCarbonViewControl() +{ + AUListenerRemoveParameter(mListener, this, &mParam); +} + +AUCarbonViewControl* AUCarbonViewControl::mLastControl = NULL; + +void AUCarbonViewControl::Bind() +{ + 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 +} + +void AUCarbonViewControl::ParameterToControl(Float32 paramValue) +{ + ++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; +} + +void AUCarbonViewControl::ControlToParameter() +{ + 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; + } +} + +void AUCarbonViewControl::SetValueFract(double value) +{ + 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); +} + +double AUCarbonViewControl::GetValueFract() +{ + 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; +} + +void AUCarbonViewControl::SetTextValue(CFStringRef cfstr) +{ + verify_noerr(SetControlData(mControl, 0, kControlEditTextCFStringTag, sizeof(CFStringRef), &cfstr)); +} + +CFStringRef AUCarbonViewControl::GetTextValue() +{ + CFStringRef cfstr; + verify_noerr(GetControlData(mControl, 0, kControlEditTextCFStringTag, sizeof(CFStringRef), &cfstr, NULL)); + return cfstr; +} + +void AUCarbonViewControl::SetValue(long value) +{ + SetControl32BitValue(mControl, value); +} + +long AUCarbonViewControl::GetValue() +{ + return GetControl32BitValue(mControl); +} + +/* 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) +{ + 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(); + } + return kControlKeyFilterBlockKey; +} + +pascal ControlKeyFilterResult AUCarbonViewControl::NumericKeyFilterCallback(ControlRef theControl, + SInt16 *keyCode, SInt16 *charCode, + EventModifiers *modifiers) +{ + 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(); + } + return kControlKeyFilterBlockKey; +} + +Boolean AUCarbonViewControl::SizeControlToFit(ControlRef inControl, SInt16 *outWidth, SInt16 *outHeight) +{ + 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; + + 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 () +{ + EventTypeSpec events[] = { + { kEventClassControl, kEventControlValueFieldChanged } // N.B. OS X only + }; + + WantEventTypes(GetControlEventTarget(mControl), GetEventTypeCount(events), events); +} + +void AUPropertyControl::EmbedControl (ControlRef theControl) +{ + mView->EmbedControl (theControl); +} + +WindowRef AUPropertyControl::GetCarbonWindow() +{ + return mView->GetCarbonWindow(); +} + +#pragma mark ___AUVPreset +static CFStringRef kStringFactoryPreset = kAUViewLocalizedStringKey_FactoryPreset; +static bool sAUVPresetLocalized = false; + +AUVPresets::AUVPresets (AUCarbonViewBase* inParentView, + CFArrayRef& inPresets, + Point inLocation, + int nameWidth, + int controlWidth, + ControlFontStyleRec & inFontStyle) + : AUPropertyControl (inParentView), + mPresets (inPresets), + mView (inParentView) +{ + 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; + +#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 + + EmbedControl (mControl); + + HandlePropertyChange(defaultPreset); + + RegisterEvents(); +} + +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 () +{ + 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) ); + } +} + +void AUVPresets::HandlePropertyChange(AUPreset &preset) +{ + // 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); +} + +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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.h new file mode 100755 index 00000000..4a7d5d8f --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.h @@ -0,0 +1,224 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewDispatch.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewDispatch.cpp new file mode 100755 index 00000000..ccba4c93 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewDispatch.cpp @@ -0,0 +1,119 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUControlGroup.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUControlGroup.cpp new file mode 100755 index 00000000..79da1416 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUControlGroup.cpp @@ -0,0 +1,343 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include +#include "AUCarbonViewBase.h" +#include "AUCarbonViewControl.h" +#include "AUControlGroup.h" +#include "AUViewLocalizedStringKeys.h" + +#define kSliderThinDimension 10 +#define kLabelAndSliderSpacing 4 + +static CFStringRef kStringManufacturer = kAUViewLocalizedStringKey_Manufacturer; +static bool sLocalized = false; + +void AUControlGroup::CreateLabelledSlider( + AUCarbonViewBase * auView, + const CAAUParameter & auvp, + const Rect & area, + Point labelSize, + const ControlFontStyleRec & inFontStyle) +{ + ControlFontStyleRec fontStyle = inFontStyle; + Rect minValRect, maxValRect, sliderRect; + ControlRef newControl; + int width = area.right - area.left, height = area.bottom - area.top; + CFStringRef cfstr; + int sliderValueMax, sliderValueMin, sliderValueDefault; + AUCarbonViewControl::ControlType sliderType; + + bool horizontal = (width > height); + + if (horizontal) { + maxValRect.top = minValRect.top = area.top + (height - labelSize.v) / 2; + minValRect.left = area.left; + maxValRect.left = area.right - labelSize.h; + + minValRect.bottom = minValRect.top + labelSize.v; + minValRect.right = minValRect.left + labelSize.h; + maxValRect.bottom = maxValRect.top + labelSize.v; + maxValRect.right = maxValRect.left + labelSize.h; + + sliderRect.left = minValRect.right + kLabelAndSliderSpacing; + sliderRect.right = maxValRect.left - kLabelAndSliderSpacing; + sliderRect.top = area.top + (height - kSliderThinDimension) / 2; + sliderRect.bottom = sliderRect.top + kSliderThinDimension + 4; + + if (auvp.IsIndexedParam ()) { + sliderValueMin = sliderValueDefault = int(auvp.ParamInfo().minValue); + sliderValueMax = int(auvp.ParamInfo().maxValue); + sliderType = AUCarbonViewControl::kTypeDiscrete; + } else { + sliderValueMin = sliderValueDefault = 0; + sliderValueMax = sliderRect.right - sliderRect.left; + sliderType = AUCarbonViewControl::kTypeContinuous; + } + } else { + maxValRect.left = minValRect.left = area.left + (width - labelSize.h) / 2; + maxValRect.top = area.top; + minValRect.top = area.bottom - labelSize.v; + + minValRect.bottom = minValRect.top + labelSize.v; + minValRect.right = minValRect.left + labelSize.h; + maxValRect.bottom = maxValRect.top + labelSize.v; + maxValRect.right = maxValRect.left + labelSize.h; + + sliderRect.left = area.left + (width - kSliderThinDimension) / 2; + sliderRect.right = sliderRect.left + kSliderThinDimension + 4; + sliderRect.top = maxValRect.bottom + kLabelAndSliderSpacing; + sliderRect.bottom = minValRect.top - kLabelAndSliderSpacing; + + if (auvp.IsIndexedParam ()) { + sliderValueMin = sliderValueDefault = int(auvp.ParamInfo().minValue); + sliderValueMax = int(auvp.ParamInfo().maxValue); + sliderType = AUCarbonViewControl::kTypeDiscrete; + } else { + sliderValueMin = sliderValueDefault = 0; + sliderValueMax = sliderRect.bottom - sliderRect.top; + sliderType = AUCarbonViewControl::kTypeContinuous; + } + } + + // minimum value label + if (labelSize.v > 0 && labelSize.h > 0) { + // check to see if the minimum value has a label + cfstr = auvp.GetStringFromValueCopy(&auvp.ParamInfo().minValue); + fontStyle.just = horizontal ? teFlushRight : teCenter; + verify_noerr(CreateStaticTextControl(auView->GetCarbonWindow(), &minValRect, cfstr, &fontStyle, &newControl)); + CFRelease(cfstr); + verify_noerr(auView->EmbedControl(newControl)); + + // maximum value label + cfstr = auvp.GetStringFromValueCopy(&auvp.ParamInfo().maxValue); + fontStyle.just = horizontal ? teFlushLeft : teCenter; + verify_noerr(CreateStaticTextControl(auView->GetCarbonWindow(), &maxValRect, cfstr, &fontStyle, &newControl)); + CFRelease(cfstr); + verify_noerr(auView->EmbedControl(newControl)); + } + + // slider + verify_noerr(CreateSliderControl(auView->GetCarbonWindow(), &sliderRect, sliderValueDefault, sliderValueMin, sliderValueMax, kControlSliderDoesNotPoint, 0, true, AUCarbonViewControl::SliderTrackProc, &newControl)); + + + ControlSize small = kControlSizeSmall; + SetControlData(newControl, kControlEntireControl, kControlSizeTag, sizeof(ControlSize), &small); + auView->AddCarbonControl(sliderType, auvp, newControl); +} + +void AUControlGroup::CreateLabelledSliderAndEditText( + AUCarbonViewBase * auView, + const CAAUParameter & auvp, + const Rect & area, + Point labelSize, + Point editTextSize, + const ControlFontStyleRec & inFontStyle) +{ + ControlFontStyleRec fontStyle = inFontStyle; + Rect sliderArea, textArea; + ControlRef newControl; + int width = area.right - area.left, height = area.bottom - area.top; + + bool horizontal = (width > height); + + sliderArea = area; + textArea = area; + if (horizontal) { + textArea.left = area.right - editTextSize.h; + // provide a large text box if param is generic and its values have strings... + if (auvp.ValuesHaveStrings() && (auvp.ParamInfo().unit == kAudioUnitParameterUnit_Generic)) + { + textArea.right += 30; + } + sliderArea.right = textArea.left - kLabelAndSliderSpacing; + textArea.top = area.top + (height - editTextSize.v) / 2; + textArea.bottom = textArea.top + editTextSize.v; + } else { + textArea.top = area.bottom - editTextSize.v; + sliderArea.bottom = textArea.top - kLabelAndSliderSpacing; + textArea.left = area.left + (width - editTextSize.h) / 2; + textArea.right = textArea.left + editTextSize.h; + } + CreateLabelledSlider(auView, auvp, sliderArea, labelSize, fontStyle); + + verify_noerr(CreateEditUnicodeTextControl(auView->GetCarbonWindow(), &textArea, CFSTR(""), false, + &fontStyle, &newControl)); + auView->AddCarbonControl(AUCarbonViewControl::kTypeText, auvp, newControl); +} + +void AUControlGroup::CreatePopupMenu (AUCarbonViewBase * auView, + const CAAUParameter & auvp, + const Rect & area, + const ControlFontStyleRec & inFontStyle, + const bool inSizeToFit) +{ + ControlRef thePopUp; + + verify_noerr(CreatePopupButtonControl (auView->GetCarbonWindow(), &area, NULL, + -12345, // DON'T GET MENU FROM RESOURCE mMenuID + FALSE, // variableWidth, + 0, // titleWidth, + 0, // titleJustification, + 0, // titleStyle, + &thePopUp)); + + ControlSize small = kControlSizeSmall; + SetControlData(thePopUp, kControlEntireControl, kControlSizeTag, sizeof(ControlSize), &small); + + MenuRef menuRef; + verify_noerr(CreateNewMenu( 1, 0, &menuRef)); + + for (int i = 0; i < auvp.GetNumIndexedParams(); ++i) { + verify_noerr(AppendMenuItemTextWithCFString (menuRef, auvp.GetParamName(i), kMenuItemAttrIgnoreMeta, 0, 0)); + } + + verify_noerr(SetControlData(thePopUp, 0, kControlPopupButtonMenuRefTag, sizeof(menuRef), &menuRef)); + SetControl32BitMaximum(thePopUp, auvp.GetNumIndexedParams()); + + verify_noerr (SetControlFontStyle (thePopUp, &inFontStyle)); + + if (inSizeToFit) { + AUCarbonViewControl::SizeControlToFit(thePopUp); + } + + auView->AddCarbonControl(AUCarbonViewControl::kTypeDiscrete, auvp, thePopUp); +} + +void AUControlGroup::AddAUInfo ( AUCarbonViewBase * auView, + const Point & inLocation, + const SInt16 inRightOffset, + const SInt16 inTotalWidth) +{ + // get component info + ComponentDescription desc; + Handle h1 = NewHandleClear(4); + OSStatus err = GetComponentInfo ((Component)auView->GetEditAudioUnit(), &desc, h1, 0, 0); + + if (err == noErr) { + // Get the manufacturer's name... look for the ':' character convention + HLock(h1); + char* ptr1 = *h1; + int len = *ptr1++; + char* displayStr = 0; + + for (int i = 0; i < len; ++i) { + if (ptr1[i] == ':') { // found the name + ptr1[i++] = 0; + displayStr = ptr1; + break; + } + } + + // localize as necessary: + if (!sLocalized) { + CFBundleRef mainBundle = CFBundleGetBundleWithIdentifier(kLocalizedStringBundle_AUView); + if (mainBundle) { + kStringManufacturer = CFCopyLocalizedStringFromTableInBundle( + kAUViewLocalizedStringKey_Manufacturer, kLocalizedStringTable_AUView, + mainBundle, CFSTR("Manufacturer title string")); + sLocalized = true; + } + } + + // display strings + ControlRef newControl; + Rect r; + r.top = SInt16(inLocation.v); r.bottom = SInt16(inLocation.v) + 16; + ControlFontStyleRec fontStyle; + fontStyle.flags = kControlUseFontMask | kControlUseJustMask; + fontStyle.font = kControlFontSmallBoldSystemFont; + + // display manufacturer string + if (displayStr) { + CFMutableStringRef mfrstring = CFStringCreateMutable(NULL, 0); + CFStringAppend(mfrstring, kStringManufacturer); // "Manufacturer" + CFStringAppend(mfrstring, kAUViewUnlocalizedString_TitleSeparator); + // "Manufacturer: " + CFStringRef mfrname = CFStringCreateWithCString(NULL, displayStr, kCFStringEncodingUTF8); + if (mfrname) { + CFStringAppend(mfrstring, mfrname); // "Manufacturer: MFRName" + CFRelease (mfrname); + } + + r.left = inLocation.h + inRightOffset; + r.right = inLocation.h + inTotalWidth - 28; + fontStyle.just = teFlushRight; + + verify_noerr(CreateStaticTextControl(auView->GetCarbonWindow(), &r, mfrstring, &fontStyle, &newControl)); + verify_noerr(auView->EmbedControl(newControl)); + CFRelease (mfrstring); + + //move displayStr ptr past the manu, to the name + // we move the characters down an index, because the handle doesn't have any room + // at the end for the \0 + int i = strlen(displayStr), j = 0; + while (displayStr[++i] == ' ' && i < len) + ; + while (i < len) + displayStr[j++] = displayStr[i++]; + displayStr[j] = 0; + } else { + displayStr = ptr1; + int i = 0, j = 0; + do { + displayStr[j] = displayStr[i]; + ++j; ++i; + } while (i < len); + + displayStr[j] = 0; + } + + // display AudioUnit string + r.left = inLocation.h; r.right = r.left + inRightOffset; + fontStyle.just = 0; + + CFMutableStringRef cfstr = CFStringCreateMutable(NULL, 0); + CFStringAppend(cfstr, kAUViewLocalizedStringKey_AudioUnit); // "Audio Unit" + CFStringAppend(cfstr, kAUViewUnlocalizedString_TitleSeparator); + // "Audio Unit: " + + CFStringRef auname = CFStringCreateWithCString(NULL, displayStr, kCFStringEncodingUTF8); + CFStringAppend(cfstr, auname); // "Audio Unit: AUName" + CFRelease (auname); + + verify_noerr(CreateStaticTextControl(auView->GetCarbonWindow(), &r, cfstr, &fontStyle, &newControl)); + + // size text control correctly + Boolean bValue = false; + SetControlData(newControl, kControlEntireControl, 'stim' /* kControlStaticTextIsMultilineTag */, sizeof(Boolean), &bValue); + SInt16 baseLineOffset; + Rect bestRect; + err = GetBestControlRect(newControl, &bestRect, &baseLineOffset); + if (err == noErr) + { + int width = (bestRect.right - bestRect.left) + 1; + int height = (bestRect.bottom - bestRect.top) + 1; + SizeControl (newControl, width, height); + } + + verify_noerr(auView->EmbedControl(newControl)); + CFRelease (cfstr); + } + + DisposeHandle (h1); +} + + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUControlGroup.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUControlGroup.h new file mode 100755 index 00000000..9f7ae173 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/AUControlGroup.h @@ -0,0 +1,84 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __AUControlGroup_h__ +#define __AUControlGroup_h__ + +#include + +class AUCarbonViewBase; +class CAAUParameter; + +// Utility class to create clusters of controls related to a single parameter + /*! @class AUControlGroup */ +class AUControlGroup { +public: + /*! @method CreateLabelledSlider */ + static void CreateLabelledSlider( AUCarbonViewBase * auView, + const CAAUParameter & auvp, + const Rect & area, + Point labelSize, + const ControlFontStyleRec & fontStyle); + + /*! @method CreateLabelledSliderAndEditText */ + static void CreateLabelledSliderAndEditText( + AUCarbonViewBase * auView, + const CAAUParameter & auvp, + const Rect & area, + Point labelSize, + Point editTextSize, + const ControlFontStyleRec & fontStyle); + + /*! @method CreatePopupMenu */ + static void CreatePopupMenu ( AUCarbonViewBase * auView, + const CAAUParameter & auvp, + const Rect & area, + const ControlFontStyleRec & inFontStyle, + const bool inSizeToFit = false); + + /*! @method AddAUInfo */ + static void AddAUInfo ( AUCarbonViewBase * auView, + const Point & inLocation, + const SInt16 inRightOffset, + const SInt16 inTotalWidth); +}; + + +#endif // __AUControlGroup_h__ diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.cpp new file mode 100755 index 00000000..15d382aa --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.cpp @@ -0,0 +1,84 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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 = 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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.h new file mode 100755 index 00000000..2253ddeb --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.h @@ -0,0 +1,65 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp new file mode 100755 index 00000000..f8bfe39e --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.cpp @@ -0,0 +1,760 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "AUInstrumentBase.h" + +#if DEBUG + #define DEBUG_PRINT 0 + #define DEBUG_PRINT_RENDER 0 +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const UInt32 kEventQueueSize = 1024; + +AUInstrumentBase::AUInstrumentBase( + ComponentInstance inInstance, + UInt32 numInputs, + UInt32 numOutputs, + UInt32 numGroups, + UInt32 numParts) + : MusicDeviceBase(inInstance, numInputs, numOutputs, numGroups, numParts), + mAbsoluteSampleFrame(0), + mEventQueue(kEventQueueSize), + mNumNotes(0), + mNumActiveNotes(0), + mMaxActiveNotes(0), + mNotes(0), + mNoteSize(0) +{ +#if DEBUG_PRINT + printf("new AUInstrumentBase\n"); +#endif + mFreeNotes.mState = kNoteState_Free; +} + + +AUInstrumentBase::~AUInstrumentBase() +{ +#if DEBUG_PRINT + printf("delete AUInstrumentBase\n"); +#endif +} + +AUElement* AUInstrumentBase::CreateElement( AudioUnitScope scope, + AudioUnitElement element) +{ +#if DEBUG_PRINT + printf("AUInstrumentBase::CreateElement %d %d\n", scope, element); +#endif + switch (scope) + { + case kAudioUnitScope_Group : + return new SynthGroupElement(this, element); + case kAudioUnitScope_Part : + return new SynthPartElement(this, element); + default : + return AUBase::CreateElement(scope, element); + } +} + + +void AUInstrumentBase::SetNotes(UInt32 inNumNotes, UInt32 inMaxActiveNotes, SynthNote* inNotes, UInt32 inNoteDataSize) +{ +#if DEBUG_PRINT + printf("AUInstrumentBase::SetNotes %d %d %08X %d\n", inNumNotes, inMaxActiveNotes, inNotes, inNoteDataSize); +#endif + mNumNotes = inNumNotes; + mMaxActiveNotes = inMaxActiveNotes; + mNoteSize = inNoteDataSize; + mNotes = inNotes; + + for (UInt32 i=0; iReset(); + mFreeNotes.AddNote(note); + } +} + +UInt32 AUInstrumentBase::CountActiveNotes() +{ + // debugging tool. + UInt32 sum = 0; + for (UInt32 i=0; imState <= kNoteState_Released) + sum++; + } + return sum; +} + +void AUInstrumentBase::AddFreeNote(SynthNote* inNote) +{ + if (inNote->mState != kNoteState_FastReleased) + DecNumActiveNotes(); +#if DEBUG_PRINT + printf("AUInstrumentBase::AddFreeNote mNumActiveNotes %lu\n", mNumActiveNotes); +#endif + mFreeNotes.AddNote(inNote); +} + +OSStatus AUInstrumentBase::Initialize() +{ +/* +TO DO: + Currently ValidFormat will check and validate that the num channels is not being + changed if the AU doesn't support the SupportedNumChannels property - which is correct + + What needs to happen here is that IFF the AU does support this property, (ie, the AU + can be configured to have different num channels than its original configuration) then + the state of the AU at Initialization needs to be validated. + + This is work still to be done - see AUEffectBase for the kind of logic that needs to be applied here +*/ + + // override to call SetNotes + + mNoteIDCounter = 128; // reset this every time we initialise + mAbsoluteSampleFrame = 0; + return noErr; +} + +void AUInstrumentBase::Cleanup() +{ +} + + +OSStatus AUInstrumentBase::Reset( AudioUnitScope inScope, + AudioUnitElement inElement) +{ +#if DEBUG_PRINT + printf("AUInstrumentBase::Reset\n"); +#endif + if (inScope == kAudioUnitScope_Global) + { + // kill all notes.. + mFreeNotes.Empty(); + for (UInt32 i=0; iIsSounding()) + note->Kill(0); + note->ListRemove(); + mFreeNotes.AddNote(note); + } + mNumActiveNotes = 0; + mAbsoluteSampleFrame = 0; + + // empty lists. + UInt32 numGroups = Groups().GetNumberOfElements(); + for (UInt32 j = 0; j < numGroups; ++j) + { + SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j); + group->Reset(); + } + } + return MusicDeviceBase::Reset(inScope, inElement); +} + +void AUInstrumentBase::PerformEvents(const AudioTimeStamp& inTimeStamp) +{ +#if DEBUG_PRINT_RENDER + printf("AUInstrumentBase::PerformEvents\n"); +#endif + SynthEvent *event; + SynthGroupElement *group; + + while ((event = mEventQueue.ReadItem()) != NULL) + { +#if DEBUG_PRINT_RENDER + printf("event %08X %d\n", event, event->GetEventType()); +#endif + switch(event->GetEventType()) + { + case SynthEvent::kEventType_NoteOn : + RealTimeStartNote(GetElForGroupID (event->GetGroupID()), event->GetNoteID(), + event->GetOffsetSampleFrame(), *event->GetParams()); + break; + case SynthEvent::kEventType_NoteOff : + RealTimeStopNote(event->GetGroupID(), event->GetNoteID(), + event->GetOffsetSampleFrame()); + break; + case SynthEvent::kEventType_SustainOn : + group = GetElForGroupID (event->GetGroupID()); + group->SustainOn(event->GetOffsetSampleFrame()); + break; + case SynthEvent::kEventType_SustainOff : + group = GetElForGroupID (event->GetGroupID()); + group->SustainOff(event->GetOffsetSampleFrame()); + break; + case SynthEvent::kEventType_SostenutoOn : + group = GetElForGroupID (event->GetGroupID()); + group->SostenutoOn(event->GetOffsetSampleFrame()); + break; + case SynthEvent::kEventType_SostenutoOff : + group = GetElForGroupID (event->GetGroupID()); + group->SostenutoOff(event->GetOffsetSampleFrame()); + break; + case SynthEvent::kEventType_AllNotesOff : + group = GetElForGroupID (event->GetGroupID()); + group->AllNotesOff(event->GetOffsetSampleFrame()); + break; + case SynthEvent::kEventType_AllSoundOff : + group = GetElForGroupID (event->GetGroupID()); + group->AllSoundOff(event->GetOffsetSampleFrame()); + break; + case SynthEvent::kEventType_ResetAllControllers : + group = GetElForGroupID (event->GetGroupID()); + group->ResetAllControllers(event->GetOffsetSampleFrame()); + break; + } + + mEventQueue.AdvanceReadPtr(); + } +} + + +OSStatus AUInstrumentBase::Render( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inNumberFrames) +{ + PerformEvents(inTimeStamp); + + UInt32 numOutputs = Outputs().GetNumberOfElements(); + for (UInt32 j = 0; j < numOutputs; ++j) + { + AudioBufferList& bufferList = GetOutput(j)->GetBufferList(); + for (UInt32 k = 0; k < bufferList.mNumberBuffers; ++k) + { + memset(bufferList.mBuffers[k].mData, 0, bufferList.mBuffers[k].mDataByteSize); + } + } + + UInt32 numGroups = Groups().GetNumberOfElements(); + for (UInt32 j = 0; j < numGroups; ++j) + { + SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j); + OSStatus err = group->Render(inNumberFrames); + if (err) return err; + } + mAbsoluteSampleFrame += inNumberFrames; + return noErr; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// AUInstrumentBase::ValidFormat +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bool AUInstrumentBase::ValidFormat( AudioUnitScope inScope, + AudioUnitElement inElement, + const CAStreamBasicDescription & inNewFormat) +{ + // if the AU supports this, then we should just let this go through to the Init call + if (SupportedNumChannels (NULL)) + return MusicDeviceBase::ValidFormat(inScope, inElement, inNewFormat); + + bool isGood = MusicDeviceBase::ValidFormat (inScope, inElement, inNewFormat); + if (!isGood) return false; + + // if we get to here, then the basic criteria is that the + // num channels cannot change on an existing bus + AUIOElement *el = GetIOElement (inScope, inElement); + return (el->GetStreamFormat().NumberChannels() == inNewFormat.NumberChannels()); +} + + +bool AUInstrumentBase::StreamFormatWritable( AudioUnitScope scope, + AudioUnitElement element) +{ + return IsInitialized() ? false : true; +} + +OSStatus AUInstrumentBase::RealTimeStartNote( SynthGroupElement *inGroup, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams &inParams) +{ + return noErr; +} + +SynthGroupElement * AUInstrumentBase::GetElForGroupID (MusicDeviceGroupID inGroupID) +{ + AUScope & groups = Groups(); + unsigned int numEls = groups.GetNumberOfElements(); + SynthGroupElement* unassignedEl = NULL; + + for (unsigned int i = 0; i < numEls; ++i) { + SynthGroupElement* el = reinterpret_cast(groups.GetElement(i)); + if (el->GroupID() == inGroupID) + return el; + if (el->GroupID() == SynthGroupElement::kUnassignedGroup) { + unassignedEl = el; + break; // we fill this up from the start of the group scope vector + } + } + if (unassignedEl) { + unassignedEl->SetGroupID(inGroupID); + return unassignedEl; + } + throw static_cast(kAudioUnitErr_InvalidElement); +} + +OSStatus AUInstrumentBase::RealTimeStopNote( + MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) +{ +#if DEBUG_PRINT + printf("AUInstrumentBase::RealTimeStopNote %d %d\n", inGroupID, inNoteInstanceID); +#endif + + SynthGroupElement *gp = (inGroupID == kMusicNoteEvent_Unused + ? GetElForNoteID (inNoteInstanceID) + : GetElForGroupID(inGroupID)); + + gp->NoteOff (inNoteInstanceID, inOffsetSampleFrame); + + return noErr; +} + +SynthGroupElement * AUInstrumentBase::GetElForNoteID (NoteInstanceID inNoteID) +{ +#if DEBUG_PRINT + printf("GetElForNoteID id %d\n", (int)inNoteID); +#endif + if (!mNotes) throw std::runtime_error("no notes"); + + for (unsigned int i = 0; i < mNumNotes; ++i) { + if (inNoteID == mNotes[i].GetNoteID()) { + return mNotes[i].GetGroup(); + } + } + throw static_cast(kAudioUnitErr_InvalidElement); +} + +OSStatus AUInstrumentBase::StartNote( MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams &inParams) +{ +#if DEBUG_PRINT + printf("AUInstrumentBase::StartNote %d\n", inGroupID); +#endif + OSStatus err = noErr; + + NoteInstanceID noteID; + if (outNoteInstanceID) { + noteID = NextNoteID(); + *outNoteInstanceID = noteID; + } else + noteID = (UInt32)inParams.mPitch; + + if (InRenderThread ()) + { + err = RealTimeStartNote( + GetElForGroupID(inGroupID), + noteID, + inOffsetSampleFrame, + inParams); + } + else + { + SynthEvent *event = mEventQueue.WriteItem(); + if (!event) return -1; // queue full + + event->Set( + SynthEvent::kEventType_NoteOn, + inGroupID, + noteID, + inOffsetSampleFrame, + &inParams + ); + + mEventQueue.AdvanceWritePtr(); + } + return err; +} + +OSStatus AUInstrumentBase::StopNote( MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) +{ +#if DEBUG_PRINT + printf("AUInstrumentBase::StopNote %d %d\n", inGroupID, inNoteInstanceID); +#endif + OSStatus err = noErr; + + if (InRenderThread ()) + { + err = RealTimeStopNote( + inGroupID, + inNoteInstanceID, + inOffsetSampleFrame); + } + else + { + SynthEvent *event = mEventQueue.WriteItem(); + if (!event) return -1; // queue full + + event->Set( + SynthEvent::kEventType_NoteOff, + inGroupID, + inNoteInstanceID, + inOffsetSampleFrame, + NULL + ); + + mEventQueue.AdvanceWritePtr(); + } + return err; +} + +OSStatus AUInstrumentBase::SendPedalEvent(MusicDeviceGroupID inGroupID, UInt32 inEventType, UInt32 inOffsetSampleFrame) +{ + + if (InRenderThread ()) + { + SynthGroupElement *group = GetElForGroupID(inGroupID); + switch (inEventType) + { + case SynthEvent::kEventType_SustainOn : + group->SustainOn(inOffsetSampleFrame); + break; + case SynthEvent::kEventType_SustainOff : + group->SustainOff(inOffsetSampleFrame); + break; + case SynthEvent::kEventType_SostenutoOn : + group->SostenutoOn(inOffsetSampleFrame); + break; + case SynthEvent::kEventType_SostenutoOff : + group->SostenutoOff(inOffsetSampleFrame); + break; + case SynthEvent::kEventType_AllNotesOff : + group->AllNotesOff(inOffsetSampleFrame); + mNumActiveNotes = CountActiveNotes(); + break; + case SynthEvent::kEventType_AllSoundOff : + group->AllSoundOff(inOffsetSampleFrame); + mNumActiveNotes = CountActiveNotes(); + break; + case SynthEvent::kEventType_ResetAllControllers : + group->ResetAllControllers(inOffsetSampleFrame); + break; + } + } + else + { + SynthEvent *event = mEventQueue.WriteItem(); + if (!event) return -1; // queue full + + event->Set(inEventType, inGroupID, 0, 0, NULL); + + mEventQueue.AdvanceWritePtr(); + } + return noErr; +} + +OSStatus AUInstrumentBase::HandleControlChange( UInt8 inChannel, + UInt8 inController, + UInt8 inValue, + UInt32 inStartFrame) +{ + GetControls(inChannel)->mControls[inController] = inValue; + switch (inController) + { + case kMidiController_Sustain : + if (inValue >= 64) + SendPedalEvent(inChannel, SynthEvent::kEventType_SustainOn, inStartFrame); + else + SendPedalEvent(inChannel, SynthEvent::kEventType_SustainOff, inStartFrame); + break; + case kMidiController_Sostenuto : + if (inValue >= 64) + SendPedalEvent(inChannel, SynthEvent::kEventType_SostenutoOn, inStartFrame); + else + SendPedalEvent(inChannel, SynthEvent::kEventType_SostenutoOff, inStartFrame); + break; + } + return noErr; +} + +OSStatus AUInstrumentBase::HandlePitchWheel( UInt8 inChannel, + UInt8 inPitch1, + UInt8 inPitch2, + UInt32 inStartFrame) +{ + MidiControls* controls = GetControls(inChannel); + controls->mPitchBend = (inPitch2 << 7) | inPitch1; + controls->mFPitchBend = (float)((SInt16)controls->mPitchBend - 8192) / 8192.; + return noErr; +} + + +OSStatus AUInstrumentBase::HandleChannelPressure(UInt8 inChannel, + UInt8 inValue, + UInt32 inStartFrame) +{ + GetControls(inChannel)->mMonoPressure = inValue; + return noErr; +} + + +OSStatus AUInstrumentBase::HandleProgramChange( UInt8 inChannel, + UInt8 inValue) +{ + GetControls(inChannel)->mMonoPressure = inValue; + return noErr; +} + + +OSStatus AUInstrumentBase::HandlePolyPressure( UInt8 inChannel, + UInt8 inKey, + UInt8 inValue, + UInt32 inStartFrame) +{ + GetControls(inChannel)->mPolyPressure[inKey] = inValue; + return noErr; +} + + +OSStatus AUInstrumentBase::HandleResetAllControllers( UInt8 inChannel) +{ + SendPedalEvent (inChannel, SynthEvent::kEventType_ResetAllControllers, 0); + return noErr; +} + + +OSStatus AUInstrumentBase::HandleAllNotesOff( UInt8 inChannel) +{ + SendPedalEvent (inChannel, SynthEvent::kEventType_AllNotesOff, 0); + return noErr; +} + + +OSStatus AUInstrumentBase::HandleAllSoundOff( UInt8 inChannel) +{ + SendPedalEvent (inChannel, SynthEvent::kEventType_AllSoundOff, 0); + return noErr; +} + +SynthNote* AUInstrumentBase::GetAFreeNote(UInt32 inFrame) +{ +#if DEBUG_PRINT + printf("GetAFreeNote size %d\n", mFreeNotes.Length()); +#endif + SynthNote *note = mFreeNotes.mHead; + if (note) + { + mFreeNotes.RemoveNote(note); + return note; + } + + return VoiceStealing(inFrame, true); +} + +SynthNote* AUInstrumentBase::VoiceStealing(UInt32 inFrame, bool inKillIt) +{ + +#if DEBUG_PRINT + printf("enter voice stealing\n"); +#endif + // free list was empty so we need to kill a note. + UInt32 startState = inKillIt ? kNoteState_FastReleased : kNoteState_Released; + for (UInt32 i = startState; i <= startState; --i) + { +#if DEBUG_PRINT + printf(" steal state %d\n", i); +#endif + UInt32 numGroups = Groups().GetNumberOfElements(); + for (UInt32 j = 0; j < numGroups; ++j) + { + SynthGroupElement *group = (SynthGroupElement*)Groups().GetElement(j); +#if DEBUG_PRINT + printf(" steal group %d size %d\n", j, group->mNoteList[i].Length()); +#endif + if (group->mNoteList[i].NotEmpty()) { +#if DEBUG_PRINT + printf("not empty %d %d\n", i, j); +#endif + SynthNote *note = group->mNoteList[i].FindMostQuietNote(); + if (inKillIt) { +#if DEBUG_PRINT + printf("--=== KILL ===---\n"); +#endif + note->mRelativeKillFrame = inFrame; + note->Kill(inFrame); + group->mNoteList[i].RemoveNote(note); + if (i != kNoteState_FastReleased) + DecNumActiveNotes(); + return note; + } else { +#if DEBUG_PRINT + printf("--=== FAST RELEASE ===---\n"); +#endif + group->mNoteList[i].RemoveNote(note); + note->FastRelease(inFrame); + group->mNoteList[kNoteState_FastReleased].AddNote(note); + DecNumActiveNotes(); // kNoteState_FastReleased counts as inactive for voice stealing purposes. + return NULL; + } + } + } + } +#if DEBUG_PRINT + printf("no notes to steal????\n"); +#endif + return NULL; // It should be impossible to get here. It means there were no notes to kill in any state. +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +AUMonotimbralInstrumentBase::AUMonotimbralInstrumentBase( + ComponentInstance inInstance, + UInt32 numInputs, + UInt32 numOutputs, + UInt32 numGroups, + UInt32 numParts) + : AUInstrumentBase(inInstance, numInputs, numOutputs, numGroups, numParts) +{ +} + +OSStatus AUMonotimbralInstrumentBase::RealTimeStartNote( + SynthGroupElement *inGroup, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams &inParams) +{ +#if DEBUG_PRINT_RENDER + printf("AUMonotimbralInstrumentBase::RealTimeStartNote %d\n", inNoteInstanceID); +#endif + + if (NumActiveNotes() + 1 > MaxActiveNotes()) + { + VoiceStealing(inOffsetSampleFrame, false); + } + SynthNote *note = GetAFreeNote(inOffsetSampleFrame); + if (!note) return -1; + + IncNumActiveNotes(); + note->AttackNote(NULL, inGroup, inNoteInstanceID, + mAbsoluteSampleFrame + inOffsetSampleFrame, inOffsetSampleFrame, inParams); + + inGroup->mNoteList[kNoteState_Attacked].AddNote(note); + return noErr; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +OSStatus AUMultitimbralInstrumentBase::GetPropertyInfo(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable) +{ + OSStatus result = noErr; + + switch (inID) + { + case kMusicDeviceProperty_PartGroup: + if (inScope != kAudioUnitScope_Part) return kAudioUnitErr_InvalidScope; + outDataSize = sizeof(UInt32); + outWritable = true; + break; + + default: + result = AUInstrumentBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); + } + return result; +} + +OSStatus AUMultitimbralInstrumentBase::GetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData) +{ + OSStatus result = noErr; + + switch (inID) + { + case kMusicDeviceProperty_PartGroup: + if (inScope != kAudioUnitScope_Group) return kAudioUnitErr_InvalidScope; + // ?? + return -1; //unimpl + break; + + default: + result = AUInstrumentBase::GetProperty (inID, inScope, inElement, outData); + } + + return result; +} + + + +OSStatus AUMultitimbralInstrumentBase::SetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize) +{ + OSStatus result = noErr; + + switch (inID) + { + case kMusicDeviceProperty_PartGroup: + if (inScope != kAudioUnitScope_Group) return kAudioUnitErr_InvalidScope; + // ?? + return -1; //unimpl + break; + + default: + result = MusicDeviceBase::SetProperty (inID, inScope, inElement, inData, inDataSize); + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h new file mode 100755 index 00000000..8f779cbf --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/AUInstrumentBase.h @@ -0,0 +1,246 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __AUInstrumentBase__ +#define __AUInstrumentBase__ + +#include +#include +#include +#include +#include "MusicDeviceBase.h" +#include "LockFreeFIFO.h" +#include "SynthEvent.h" +#include "SynthNote.h" +#include "SynthElement.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef LockFreeFIFOWithFree SynthEventQueue; + +class AUInstrumentBase : public MusicDeviceBase +{ +public: + AUInstrumentBase( + ComponentInstance inInstance, + UInt32 numInputs, + UInt32 numOutputs, + UInt32 numGroups = 32, + UInt32 numParts = 0); + virtual ~AUInstrumentBase(); + + virtual OSStatus Initialize(); + + virtual void Cleanup(); + + virtual AUElement* CreateElement( AudioUnitScope scope, + AudioUnitElement element); + + virtual OSStatus Reset( AudioUnitScope inScope, + AudioUnitElement inElement); + + virtual bool ValidFormat( AudioUnitScope inScope, + AudioUnitElement inElement, + const CAStreamBasicDescription & inNewFormat); + + virtual bool StreamFormatWritable( AudioUnitScope scope, + AudioUnitElement element); + + virtual OSStatus Render( AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inNumberFrames); + + virtual OSStatus StartNote( MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams &inParams); + + virtual OSStatus StopNote( MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame); + + virtual OSStatus RealTimeStartNote( SynthGroupElement *inGroup, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams &inParams); + + virtual OSStatus RealTimeStopNote( MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame); + + virtual OSStatus HandleControlChange( UInt8 inChannel, + UInt8 inController, + UInt8 inValue, + UInt32 inStartFrame); + + virtual OSStatus HandlePitchWheel( UInt8 inChannel, + UInt8 inPitch1, + UInt8 inPitch2, + UInt32 inStartFrame); + + virtual OSStatus HandleChannelPressure( UInt8 inChannel, + UInt8 inValue, + UInt32 inStartFrame); + + virtual OSStatus HandleProgramChange( UInt8 inChannel, + UInt8 inValue); + + virtual OSStatus HandlePolyPressure( UInt8 inChannel, + UInt8 inKey, + UInt8 inValue, + UInt32 inStartFrame); + + virtual OSStatus HandleResetAllControllers( UInt8 inChannel); + + virtual OSStatus HandleAllNotesOff( UInt8 inChannel); + + virtual OSStatus HandleAllSoundOff( UInt8 inChannel); + + SynthNote* GetNote(UInt32 inIndex) + { + if (!mNotes) throw std::runtime_error("no notes"); + return (SynthNote*)((char*)mNotes + inIndex * mNoteSize); + } + + SynthNote* GetAFreeNote(UInt32 inFrame); + void AddFreeNote(SynthNote* inNote); + + MidiControls* GetControls( MusicDeviceGroupID inChannel) + { + SynthGroupElement *group = GetElForGroupID(inChannel); + return &(group->mMidiControls); + } + + +protected: + + UInt32 NextNoteID() { return IncrementAtomic(&mNoteIDCounter); } + + + // call SetNotes in your Initialize() method to give the base class your note structures and to set the maximum + // number of active notes. inNoteData should be an array of size inMaxActiveNotes. + void SetNotes(UInt32 inNumNotes, UInt32 inMaxActiveNotes, SynthNote* inNotes, UInt32 inNoteSize); + + void PerformEvents( const AudioTimeStamp & inTimeStamp); + OSStatus SendPedalEvent(MusicDeviceGroupID inGroupID, UInt32 inEventType, UInt32 inOffsetSampleFrame); + virtual SynthNote* VoiceStealing(UInt32 inFrame, bool inKillIt); + UInt32 MaxActiveNotes() const { return mMaxActiveNotes; } + UInt32 NumActiveNotes() const { return mNumActiveNotes; } + void IncNumActiveNotes() { mNumActiveNotes ++; } + void DecNumActiveNotes() { mNumActiveNotes --; } + UInt32 CountActiveNotes(); + // this call throws if there's no assigned element for the group ID + SynthGroupElement * GetElForGroupID (MusicDeviceGroupID inGroupID); + SynthGroupElement * GetElForNoteID (NoteInstanceID inNoteID); + + SInt64 mAbsoluteSampleFrame; + + +private: + + SInt32 mNoteIDCounter; + + SynthEventQueue mEventQueue; + + UInt32 mNumNotes; + UInt32 mNumActiveNotes; + UInt32 mMaxActiveNotes; + SynthNote* mNotes; + SynthNoteList mFreeNotes; + UInt32 mNoteSize; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class AUMonotimbralInstrumentBase : public AUInstrumentBase +{ +public: + AUMonotimbralInstrumentBase( + ComponentInstance inInstance, + UInt32 numInputs, + UInt32 numOutputs, + UInt32 numGroups = 32, + UInt32 numParts = 0); + + virtual OSStatus RealTimeStartNote( SynthGroupElement *inGroup, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams &inParams); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// this is a work in progress! The mono-timbral one is finished though! +class AUMultitimbralInstrumentBase : public AUInstrumentBase +{ +public: + AUMultitimbralInstrumentBase( + ComponentInstance inInstance, + UInt32 numInputs, + UInt32 numOutputs, + UInt32 numGroups, + UInt32 numParts); + + virtual OSStatus GetPropertyInfo( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable); + + virtual OSStatus GetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData); + + virtual OSStatus SetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize); + +private: + +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h new file mode 100755 index 00000000..50f97771 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/LockFreeFIFO.h @@ -0,0 +1,167 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include + + +template +class LockFreeFIFOWithFree +{ + LockFreeFIFOWithFree(); // private, unimplemented. +public: + LockFreeFIFOWithFree(UInt32 inMaxSize) + : mReadIndex(0), mWriteIndex(0), mFreeIndex(0) + { + //assert(IsPowerOfTwo(inMaxSize)); + mItems = new ITEM[inMaxSize]; + mMask = inMaxSize - 1; + } + + ~LockFreeFIFOWithFree() + { + delete [] mItems; + } + + + void Reset() + { + FreeItems(); + mReadIndex = 0; + mWriteIndex = 0; + mFreeIndex = 0; + } + + ITEM* WriteItem() + { + //printf("WriteItem %d %d\n", mReadIndex, mWriteIndex); + FreeItems(); // free items on the write thread. + UInt32 nextWriteIndex = (mWriteIndex + 1) & mMask; + if (nextWriteIndex == mFreeIndex) return NULL; + return &mItems[mWriteIndex]; + } + + ITEM* ReadItem() + { + //printf("ReadItem %d %d\n", mReadIndex, mWriteIndex); + if (mReadIndex == mWriteIndex) return NULL; + return &mItems[mReadIndex]; + } + + // the CompareAndSwap will always succeed. We use CompareAndSwap because it calls the PowerPC sync instruction, + // plus any processor bug workarounds for various CPUs. + void AdvanceWritePtr() { CompareAndSwap(mWriteIndex, (mWriteIndex + 1) & mMask, (UInt32*)&mWriteIndex); } + void AdvanceReadPtr() { CompareAndSwap(mReadIndex, (mReadIndex + 1) & mMask, (UInt32*)&mReadIndex); } + +private: + ITEM* FreeItem() + { + if (mFreeIndex == mReadIndex) return NULL; + return &mItems[mFreeIndex]; + } + void AdvanceFreePtr() { CompareAndSwap(mFreeIndex, (mFreeIndex + 1) & mMask, (UInt32*)&mFreeIndex); } + + void FreeItems() + { + ITEM* item; + while ((item = FreeItem()) != NULL) + { + item->Free(); + AdvanceFreePtr(); + } + } + + volatile UInt32 mReadIndex, mWriteIndex, mFreeIndex; + UInt32 mMask; + ITEM *mItems; +}; + + + +// Same as above but no free. + +template +class LockFreeFIFO +{ + LockFreeFIFO(); // private, unimplemented. +public: + LockFreeFIFO(UInt32 inMaxSize) + : mReadIndex(0), mWriteIndex(0) + { + //assert(IsPowerOfTwo(inMaxSize)); + mItems = new ITEM[inMaxSize]; + mMask = inMaxSize - 1; + } + + ~LockFreeFIFO() + { + delete [] mItems; + } + + void Reset() + { + mReadIndex = 0; + mWriteIndex = 0; + } + + ITEM* WriteItem() + { + UInt32 nextWriteIndex = (mWriteIndex + 1) & mMask; + if (nextWriteIndex == mReadIndex) return NULL; + return &mItems[mWriteIndex]; + } + + ITEM* ReadItem() + { + if (mReadIndex == mWriteIndex) return NULL; + return &mItems[mReadIndex]; + } + + // the CompareAndSwap will always succeed. We use CompareAndSwap because it calls the PowerPC sync instruction, + // plus any processor bug workarounds for various CPUs. + void AdvanceWritePtr() { CompareAndSwap(mWriteIndex, (mWriteIndex + 1) & mMask, (UInt32*)&mWriteIndex); } + void AdvanceReadPtr() { CompareAndSwap(mReadIndex, (mReadIndex + 1) & mMask, (UInt32*)&mReadIndex); } + +private: + + volatile UInt32 mReadIndex, mWriteIndex; + UInt32 mMask; + ITEM *mItems; +}; + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp new file mode 100755 index 00000000..d16f8e87 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.cpp @@ -0,0 +1,266 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "SynthElement.h" +#include "AUInstrumentBase.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +MidiControls::MidiControls() +{ + Reset(); +} + +void MidiControls::Reset() +{ + memset(this, 0, sizeof(MidiControls)); + mControls[kMidiController_Pan] = 64; + mControls[kMidiController_Expression] = 127; + mPitchBendDepth = 2 << 7; + mFPitchBendDepth = 2.; +} + + +SynthElement::SynthElement(AUInstrumentBase *audioUnit, UInt32 inElement) + : AUElement(audioUnit), mName(0), mIndex(inElement) +{ +} + +SynthElement::~SynthElement() +{ + if (mName) CFRelease(mName); +} + +SynthGroupElement::SynthGroupElement(AUInstrumentBase *audioUnit, UInt32 inElement) + : SynthElement(audioUnit, inElement), mSustainIsOn(false), mSostenutoIsOn(false), mOutputBus(0), mGroupID(kUnassignedGroup) +{ +#if DEBUG_PRINT + printf("SynthGroupElement::SynthGroupElement %d\n", inElement); +#endif + for (UInt32 i=0; i(kAudioUnitErr_InvalidElement); + mGroupID = inGroup; +} + +void SynthGroupElement::Reset() +{ +#if DEBUG_PRINT + printf("SynthGroupElement::Reset\n"); +#endif + mMidiControls.Reset(); + for (UInt32 i=0; imNoteID != inNoteID) + { +#if DEBUG_PRINT + printf(" ? %08X %d\n", note, note->mNoteID); +#endif + note = note->mNext; + } + +#if DEBUG_PRINT + printf(" found %08X\n", note); +#endif + if (note) + { +#if DEBUG_PRINT + printf(" old state %d\n", note->mState); +#endif + mNoteList[kNoteState_Attacked].RemoveNote(note); + note->Release(inFrame); + if (mSustainIsOn) { + mNoteList[kNoteState_ReleasedButSustained].AddNote(note); + } else { + mNoteList[kNoteState_Released].AddNote(note); + } +#if DEBUG_PRINT + printf(" new state %d\n", note->mState); +#endif + } + else if (mSostenutoIsOn) + { + // see if this note is sostenutoed. + note = mNoteList[kNoteState_Sostenutoed].mHead; + while (note && note->mNoteID != inNoteID) + note = note->mNext; + if (note) + { + mNoteList[kNoteState_Sostenutoed].RemoveNote(note); + mNoteList[kNoteState_ReleasedButSostenutoed].AddNote(note); + } + } +} + +void SynthGroupElement::NoteEnded(SynthNote *inNote, UInt32 inFrame) +{ +#if DEBUG_PRINT + printf("SynthGroupElement::NoteEnded %d %d\n", inNote->mNoteID, inNote->mState); +#endif + SynthNoteList *list = mNoteList + inNote->mState; + list->RemoveNote(inNote); + + GetAUInstrument()->AddFreeNote(inNote); +} + +void SynthGroupElement::SostenutoOn(UInt32 inFrame) +{ +#if DEBUG_PRINT + printf("SynthGroupElement::SostenutoOn\n"); +#endif + mSostenutoIsOn = true; + mNoteList[kNoteState_Sostenutoed].TransferAllFrom(&mNoteList[kNoteState_Attacked], inFrame); +} + +void SynthGroupElement::SostenutoOff(UInt32 inFrame) +{ +#if DEBUG_PRINT + printf("SynthGroupElement::SostenutoOff\n"); +#endif + mSostenutoIsOn = false; + mNoteList[kNoteState_Attacked].TransferAllFrom(&mNoteList[kNoteState_Sostenutoed], inFrame); + if (mSustainIsOn) + mNoteList[kNoteState_ReleasedButSustained].TransferAllFrom(&mNoteList[kNoteState_ReleasedButSostenutoed], inFrame); + else + mNoteList[kNoteState_Released].TransferAllFrom(&mNoteList[kNoteState_ReleasedButSostenutoed], inFrame); +} + + +void SynthGroupElement::SustainOn(UInt32 inFrame) +{ +#if DEBUG_PRINT + printf("SynthGroupElement::SustainOn\n"); +#endif + mSustainIsOn = true; +} + +void SynthGroupElement::SustainOff(UInt32 inFrame) +{ +#if DEBUG_PRINT + printf("SynthGroupElement::SustainOff\n"); +#endif + mSustainIsOn = false; + + mNoteList[kNoteState_Released].TransferAllFrom(&mNoteList[kNoteState_ReleasedButSustained], inFrame); +} + +void SynthGroupElement::AllNotesOff(UInt32 inFrame) +{ +#if DEBUG_PRINT + printf("SynthGroupElement::AllNotesOff\n"); +#endif + SynthNote *note; + + for (UInt32 i=0 ; imNext; + + mNoteList[i].RemoveNote(note); + note->FastRelease(inFrame); + mNoteList[kNoteState_FastReleased].AddNote(note); + + note = nextNote; + } + } +} + +void SynthGroupElement::AllSoundOff(UInt32 inFrame) +{ +#if DEBUG_PRINT + printf("SynthGroupElement::AllSoundOff\n"); +#endif + AllNotesOff(inFrame); +} + +void SynthGroupElement::ResetAllControllers(UInt32 inFrame) +{ +#if DEBUG_PRINT + printf("SynthGroupElement::ResetAllControllers\n"); +#endif + mMidiControls.Reset(); +} + +OSStatus SynthGroupElement::Render(UInt32 inNumberFrames) +{ + SynthNote *note; + AudioBufferList& bufferList = GetAudioUnit()->GetOutput(mOutputBus)->GetBufferList(); + + for (UInt32 i=0 ; imNext; + + OSStatus err = note->Render(inNumberFrames, bufferList); + if (err) return err; + + note = nextNote; + } + } + + return noErr; +} + + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h new file mode 100755 index 00000000..a1170730 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthElement.h @@ -0,0 +1,262 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __SynthElement__ +#define __SynthElement__ + +#include +#include +#include "MusicDeviceBase.h" +#include "SynthNoteList.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +class AUInstrumentBase; + +class SynthElement : public AUElement +{ +public: + SynthElement(AUInstrumentBase *audioUnit, UInt32 inElement); + virtual ~SynthElement(); + + UInt32 GetIndex() const { return mIndex; } + + AUInstrumentBase* GetAUInstrument() { return (AUInstrumentBase*)GetAudioUnit(); } + + CFStringRef GetName() const { return mName; } + void SetName(CFStringRef inName) + { + CFStringRef oldName = mName; + mName = inName; + CFRetain(mName); + if (oldName) CFRelease(oldName); + } +private: + CFStringRef mName; + UInt32 mIndex; +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +enum { + kMidiController_BankSelect = 0, + kMidiController_ModWheel = 1, + kMidiController_Breath = 2, + kMidiController_Foot = 4, + kMidiController_PortamentoTime = 5, + kMidiController_DataEntry = 6, + kMidiController_Volume = 7, + kMidiController_Balance = 8, + kMidiController_Pan = 10, + kMidiController_Expression = 11, + + // these controls have a (0-63) == off, (64-127) == on + kMidiController_Sustain = 64, //hold1 + kMidiController_Portamento = 65, + kMidiController_Sostenuto = 66, + kMidiController_Soft = 67, + kMidiController_LegatoPedal = 68, + kMidiController_Hold2Pedal = 69, + kMidiController_FilterResonance = 71, + kMidiController_ReleaseTime = 72, + kMidiController_AttackTime = 73, + kMidiController_Brightness = 74, + kMidiController_DecayTime = 75, + kMidiController_VibratoRate = 76, + kMidiController_VibratoDepth = 77, + kMidiController_VibratoDelay = 78, + + // these controls have a 0-127 range and in MIDI they have no LSB (so fractional values are lost in MIDI) + kMidiController_ReverbLevel = 91, + kMidiController_ChorusLevel = 93, + + kMidiController_AllSoundOff = 120, + kMidiController_ResetAllControllers = 121, + kMidiController_AllNotesOff = 123 +}; + +struct MidiControls +{ + MidiControls(); + void Reset(); + + UInt8 mControls[128]; + UInt8 mPolyPressure[128]; + UInt8 mMonoPressure; + UInt8 mProgramChange; + UInt16 mPitchBend; + UInt16 mActiveRPN; + UInt16 mActiveNRPN; + UInt16 mActiveRPValue; + UInt16 mActiveNRPValue; + + UInt16 mPitchBendDepth; + float mFPitchBendDepth; + float mFPitchBend; + + SInt16 GetHiResControl(UInt32 inIndex) const + { + return ((mControls[inIndex] & 127) << 7) | (mControls[inIndex + 32] & 127); + } + + void SetHiResControl(UInt32 inIndex, UInt8 inMSB, UInt8 inLSB) + { + mControls[inIndex] = inMSB; + mControls[inIndex + 32] = inLSB; + } + + float GetControl(UInt32 inIndex) const + { + if (inIndex < 32) { + return (float)mControls[inIndex] + (float)mControls[inIndex + 32] / 127.; + } else { + return (float)mControls[inIndex]; + } + } + + float PitchBend() const { return mFPitchBend * mFPitchBendDepth; } + +}; + + +class SynthGroupElement : public SynthElement +{ +public: + enum { + kUnassignedGroup = 0xFFFFFFFF + }; + + SynthGroupElement(AUInstrumentBase *audioUnit, UInt32 inElement); + + void NoteOff(NoteInstanceID inNoteID, UInt32 inFrame); + void SustainOn(UInt32 inFrame); + void SustainOff(UInt32 inFrame); + void SostenutoOn(UInt32 inFrame); + void SostenutoOff(UInt32 inFrame); + + void NoteEnded(SynthNote *inNote, UInt32 inFrame); + + void AllNotesOff(UInt32 inFrame); + void AllSoundOff(UInt32 inFrame); + void ResetAllControllers(UInt32 inFrame); + + UInt32 GetOutputBus() const { return mOutputBus; } + void SetOutputBus(UInt32 inBus) { mOutputBus = inBus; } + + void Reset(); + + virtual OSStatus Render(UInt32 inNumberFrames); + + float GetControl(UInt32 inIndex) const { return mMidiControls.GetControl(inIndex); } + float PitchBend() const { return mMidiControls.PitchBend(); } + + MusicDeviceGroupID GroupID () const { return mGroupID; } + void SetGroupID (MusicDeviceGroupID inGroup); + +private: + friend class AUInstrumentBase; + friend class AUMonotimbralInstrumentBase; + friend class AUMultitimbralInstrumentBase; + + MidiControls mMidiControls; + + bool mSustainIsOn; + bool mSostenutoIsOn; + UInt32 mOutputBus; + MusicDeviceGroupID mGroupID; + + + SynthNoteList mNoteList[kNumberOfSoundingNoteStates]; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct SynthKeyZone +{ + UInt8 mLoNote; + UInt8 mHiNote; + UInt8 mLoVelocity; + UInt8 mHiVelocity; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const UInt32 kUnlimitedPolyphony = 0xFFFFFFFF; + +class SynthPartElement : public SynthElement +{ +public: + SynthPartElement(AUInstrumentBase *audioUnit, UInt32 inElement); + + UInt32 GetGroupIndex() const { return mGroupIndex; } + bool InRange(Float32 inNote, Float32 inVelocity); + + UInt32 GetMaxPolyphony() const { return mMaxPolyphony; } + void SetMaxPolyphony(UInt32 inMaxPolyphony) { mMaxPolyphony = inMaxPolyphony; } + +private: + UInt32 mGroupIndex; + UInt32 mPatchIndex; + UInt32 mMaxPolyphony; + SynthKeyZone mKeyZone; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline AUInstrumentBase* SynthNote::GetAudioUnit() const + { + return (AUInstrumentBase*)mGroup->GetAudioUnit(); + } + +inline Float32 SynthNote::GetGlobalParameter(AudioUnitParameterID inParamID) const + { + return mGroup->GetAudioUnit()->Globals()->GetParameter(inParamID); + } + +inline void SynthNote::NoteEnded(UInt32 inFrame) + { + mGroup->NoteEnded(this, inFrame); + mNoteID = 0xFFFFFFFF; + } + +inline float SynthNote::PitchBend() const + { + return mGroup->PitchBend(); + } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +#endif diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h new file mode 100755 index 00000000..86a439ad --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthEvent.h @@ -0,0 +1,140 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +/* You can either fill in code here or remove this and create or add new files. */ + +#ifndef __SynthEvent__ +#define __SynthEvent__ + +#include +#include +#include +#include "MusicDeviceBase.h" +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +class SynthEvent +{ +public: + enum { + kEventType_NoteOn = 1, + kEventType_NoteOff = 2, + kEventType_SustainOn = 3, + kEventType_SustainOff = 4, + kEventType_SostenutoOn = 5, + kEventType_SostenutoOff = 6, + kEventType_AllNotesOff = 7, + kEventType_AllSoundOff = 8, + kEventType_ResetAllControllers = 9 + }; + + + SynthEvent() {} + ~SynthEvent() {} + + void Set( + UInt32 inEventType, + MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams* inNoteParams + ) + { + mEventType = inEventType; + mGroupID = inGroupID; + mNoteID = inNoteID; + mOffsetSampleFrame = inOffsetSampleFrame; + + if (inNoteParams) + { + UInt32 paramSize = offsetof(MusicDeviceNoteParams, mControls) + (inNoteParams->argCount-2)*sizeof(NoteParamsControlValue); + mNoteParams = inNoteParams->argCount > 3 + ? (MusicDeviceNoteParams*)malloc(paramSize) + : &mSmallNoteParams; + memcpy(mNoteParams, inNoteParams, paramSize); + } + else + mNoteParams = NULL; + } + + + void Free() + { + if (mNoteParams) + { + if (mNoteParams->argCount > 3) + free(mNoteParams); + mNoteParams = NULL; + } + } + + UInt32 GetEventType() const { return mEventType; } + MusicDeviceGroupID GetGroupID() const { return mGroupID; } + NoteInstanceID GetNoteID() const { return mNoteID; } + UInt32 GetOffsetSampleFrame() const { return mOffsetSampleFrame; } + + MusicDeviceNoteParams* GetParams() const { return mNoteParams; } + + UInt32 GetArgCount() const { return mNoteParams->argCount; } + UInt32 NumberParameters() const { return mNoteParams->argCount - 2; } + + Float32 GetNote() const { return mNoteParams->mPitch; } + Float32 GetVelocity() const { return mNoteParams->mVelocity; } + + NoteParamsControlValue GetParameter(UInt32 inIndex) const + { + if (inIndex >= NumberParameters()) + throw std::runtime_error("index out of range"); + return mNoteParams->mControls[inIndex]; + } + +private: + UInt32 mEventType; + MusicDeviceGroupID mGroupID; + NoteInstanceID mNoteID; + UInt32 mOffsetSampleFrame; + MusicDeviceNoteParams* mNoteParams; + MusicDeviceNoteParams mSmallNoteParams; // inline a small one to eliminate malloc for the simple case. +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +#endif diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp new file mode 100755 index 00000000..a3c838ca --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.cpp @@ -0,0 +1,113 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "SynthNote.h" +#include "SynthElement.h" +#include "AUInstrumentBase.h" + +void SynthNote::AttackNote( + SynthPartElement * inPart, + SynthGroupElement * inGroup, + NoteInstanceID inNoteID, + SInt64 inAbsoluteSampleFrame, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams &inParams) +{ +#if DEBUG_PRINT + printf("SynthNote::AttackNote %d %d %d\n", inPart, inGroup->GroupID(), inNoteID); +#endif + mPart = inPart; + mGroup = inGroup; + mNoteID = inNoteID; + + mAbsoluteStartFrame = inAbsoluteSampleFrame; + mRelativeStartFrame = inOffsetSampleFrame; + mRelativeReleaseFrame = -1; + mRelativeKillFrame = -1; + + mPitch = inParams.mPitch; + mVelocity = inParams.mVelocity; + + + Attack(inParams); +} + + +void SynthNote::Reset() +{ + mPart = 0; + mGroup = 0; + mAbsoluteStartFrame = 0; + mRelativeStartFrame = 0; + mRelativeReleaseFrame = 0; + mRelativeKillFrame = 0; +} + +void SynthNote::Kill(UInt32 inFrame) +{ + mRelativeKillFrame = inFrame; +} + +void SynthNote::Release(UInt32 inFrame) +{ + mRelativeReleaseFrame = inFrame; +} + +void SynthNote::FastRelease(UInt32 inFrame) +{ + mRelativeReleaseFrame = inFrame; +} + +double SynthNote::TuningA() const +{ + return 440.0; +} + +double SynthNote::Frequency() +{ + return TuningA() * pow(2., (mPitch - 69. + PitchBend()) / 12.); +} + +double SynthNote::SampleRate() +{ + return GetAudioUnit()->GetOutput(0)->GetStreamFormat().mSampleRate; +} + + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h new file mode 100755 index 00000000..afb1730d --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNote.h @@ -0,0 +1,170 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __SynthNote__ +#define __SynthNote__ + +#include +#include +#include +#include "MusicDeviceBase.h" + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +enum { + kNoteState_Attacked = 0, + kNoteState_Sostenutoed = 1, + kNoteState_ReleasedButSostenutoed = 2, + kNoteState_ReleasedButSustained = 3, + kNoteState_Released = 4, + kNoteState_FastReleased = 5, + kNoteState_Free = 6, + kNumberOfActiveNoteStates = 5, + kNumberOfSoundingNoteStates = 6, + kNumberOfNoteStates = 7 +}; + +/* + This table describes the state transitions for SynthNotes + + EVENT CURRENT STATE NEW STATE + note on free attacked + note off attacked (and sustain on) released but sustained + note off attacked released + note off sostenutoed released but sostenutoed + sustain on -- no changes -- + sustain off released but sustained released + sostenuto on attacked sostenutoed + sostenuto off sostenutoed attacked + sostenuto off released but sostenutoed (and sustain on) released but sustained + sostenuto off released but sostenutoed released + end of note any state free + soft voice stealing any state fast released + hard voice stealing any state free + + soft voice stealing happens when there is a note on event and NumActiveNotes > MaxActiveNotes + hard voice stealing happens when there is a note on event and NumActiveNotes == NumNotes (no free notes) + voice stealing removes the quietest note in the highest numbered state that has sounding notes. +*/ + +class SynthGroupElement; +class SynthPartElement; +class AUInstrumentBase; + +struct SynthNote +{ + SynthNote() : + mPrev(0), mNext(0), mState(kNoteState_Free), + mRelativeStartFrame(0), + mRelativeReleaseFrame(-1), + mRelativeKillFrame(-1) + { + } + + virtual ~SynthNote() {} + + virtual void Reset(); + virtual void AttackNote( + SynthPartElement * inPart, + SynthGroupElement * inGroup, + NoteInstanceID inNoteID, + SInt64 inAbsoluteSampleFrame, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams &inParams + ); + + virtual OSStatus Render(UInt32 inNumFrames, AudioBufferList& inBufferList)=0; + virtual void Attack(const MusicDeviceNoteParams &inParams) = 0; + virtual void Kill(UInt32 inFrame); // voice is being stolen. + virtual void Release(UInt32 inFrame); + virtual void FastRelease(UInt32 inFrame); + virtual Float32 Amplitude() = 0; // used for finding quietest note for voice stealing. + + virtual void NoteEnded(UInt32 inFrame); + + SynthGroupElement* GetGroup() const { return mGroup; } + SynthPartElement* GetPart() const { return mPart; } + + AUInstrumentBase* GetAudioUnit() const; + + Float32 GetGlobalParameter(AudioUnitParameterID inParamID) const; + + NoteInstanceID GetNoteID() const { return mNoteID; } + UInt32 GetState() const { return mState; } + Boolean IsSounding() const { return mState < kNumberOfSoundingNoteStates; } + Boolean IsActive() const { return mState < kNumberOfActiveNoteStates; } + SInt64 GetAbsoluteStartFrame() const { return mAbsoluteStartFrame; } + SInt32 GetRelativeStartFrame() const { return mRelativeStartFrame; } + SInt32 GetRelativeReleaseFrame() const { return mRelativeReleaseFrame; } + SInt32 GetRelativeKillFrame() const { return mRelativeKillFrame; } + + void ListRemove() { mPrev = mNext = 0; } // only use when lists will be reset. + + float PitchBend() const; + double TuningA() const; + + virtual double Frequency(); // returns the frequency of note + pitch bend. + double SampleRate(); + +//private: +// friend class NoteList; + + // linked list pointers + SynthNote *mPrev; + SynthNote *mNext; + + SynthPartElement* mPart; + SynthGroupElement* mGroup; + + NoteInstanceID mNoteID; + UInt32 mState; + SInt64 mAbsoluteStartFrame; + SInt32 mRelativeStartFrame; + SInt32 mRelativeReleaseFrame; + SInt32 mRelativeKillFrame; + + Float32 mPitch; + Float32 mVelocity; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp new file mode 100755 index 00000000..a5ee505b --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.cpp @@ -0,0 +1,87 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "SynthNoteList.h" +#include + +void SynthNoteList::SanityCheck() const +{ + if (mState >= kNumberOfNoteStates) { + throw std::runtime_error("mState is bad"); + } + + if (mHead == NULL) { + if (mTail != NULL) + throw std::runtime_error("mHead is NULL but not mTail"); + return; + } + if (mTail == NULL) { + throw std::runtime_error("mTail is NULL but not mHead"); + } + + if (mHead->mPrev) { + throw std::runtime_error("mHead has a mPrev"); + } + if (mTail->mNext) { + throw std::runtime_error("mTail has a mNext"); + } + + SynthNote *note = mHead; + while (note) + { + if (note->mState != mState) + throw std::runtime_error("note in wrong state"); + if (note->mNext) { + if (note->mNext->mPrev != note) + throw std::runtime_error("bad link 1"); + } else { + if (mTail != note) + throw std::runtime_error("note->mNext is nil, but mTail != note"); + } + if (note->mPrev) { + if (note->mPrev->mNext != note) + throw std::runtime_error("bad link 2"); + } else { + if (mHead != note) + throw std::runtime_error("note->mPrev is nil, but mHead != note"); + } + note = note->mNext; + } +} diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h new file mode 100755 index 00000000..5ab7ffa0 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUInstrumentBase/SynthNoteList.h @@ -0,0 +1,226 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __SynthNoteList__ +#define __SynthNoteList__ + +#include "SynthNote.h" + +#if DEBUG +#ifndef DEBUG_PRINT + #define DEBUG_PRINT 0 +#endif + #define SANITY_CHECK 0 +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +struct SynthNoteList +{ + SynthNoteList() : mState(0xFFFFFFFF), mHead(0), mTail(0) {} + + bool NotEmpty() const { return mHead != NULL; } + bool IsEmpty() const { return mHead == NULL; } + void Empty() { +#if SANITY_CHECK + SanityCheck(); +#endif + mHead = mTail = NULL; + } + + UInt32 Length() const { +#if SANITY_CHECK + SanityCheck(); +#endif + UInt32 length = 0; + for (SynthNote* note = mHead; note; note = note->mNext) + length++; + return length; + }; + + void AddNote(SynthNote *inNote) + { +#if DEBUG_PRINT + printf("AddNote %d %08X\n", mState, inNote); +#endif +#if SANITY_CHECK + SanityCheck(); +#endif + inNote->mState = mState; + inNote->mNext = mHead; + inNote->mPrev = NULL; + + if (mHead) { mHead->mPrev = inNote; mHead = inNote; } + else mHead = mTail = inNote; +#if SANITY_CHECK + SanityCheck(); +#endif + } + + void RemoveNote(SynthNote *inNote) + { +#if DEBUG_PRINT + printf("RemoveNote\n"); +#endif +#if SANITY_CHECK + SanityCheck(); +#endif + if (inNote->mPrev) inNote->mPrev->mNext = inNote->mNext; + else mHead = inNote->mNext; + + if (inNote->mNext) inNote->mNext->mPrev = inNote->mPrev; + else mTail = inNote->mPrev; + + inNote->mPrev = 0; + inNote->mNext = 0; +#if SANITY_CHECK + SanityCheck(); +#endif + } + + void TransferAllFrom(SynthNoteList *inNoteList, UInt32 inFrame) + { +#if DEBUG_PRINT + printf("TransferAllFrom\n"); +#endif +#if SANITY_CHECK + SanityCheck(); + inNoteList->SanityCheck(); +#endif + if (!inNoteList->mTail) return; + + if (mState == kNoteState_Released) + { + for (SynthNote* note = inNoteList->mHead; note; note = note->mNext) + { +#if DEBUG_PRINT + printf("TransferAllFrom release %08X\n", note); +#endif + note->mState = mState; + note->Release(inFrame); + } + } + else + { + for (SynthNote* note = inNoteList->mHead; note; note = note->mNext) + { + note->mState = mState; + } + } + + inNoteList->mTail->mNext = mHead; + + if (mHead) mHead->mPrev = inNoteList->mTail; + else mTail = inNoteList->mTail; + + mHead = inNoteList->mHead; + + inNoteList->mHead = NULL; + inNoteList->mTail = NULL; +#if SANITY_CHECK + SanityCheck(); + inNoteList->SanityCheck(); +#endif + } + + SynthNote* FindOldestNote() + { +#if DEBUG_PRINT + printf("FindOldestNote\n"); +#endif +#if SANITY_CHECK + SanityCheck(); +#endif + SInt64 minStartFrame = -1; + SynthNote* oldestNote = NULL; + for (SynthNote* note = mHead; note; note = note->mNext) + { + if (note->mAbsoluteStartFrame < minStartFrame) + { + oldestNote = note; + minStartFrame = note->mAbsoluteStartFrame; + } + } + return oldestNote; + } + + SynthNote* FindMostQuietNote() + { +#if DEBUG_PRINT + printf("FindMostQuietNote\n"); +#endif + Float32 minAmplitude = 1e9; + SInt64 minStartFrame = -1; + SynthNote* mostQuietNote = NULL; + for (SynthNote* note = mHead; note; note = note->mNext) + { + Float32 amp = note->Amplitude(); +#if DEBUG_PRINT + printf(" amp %g minAmplitude %g\n", amp, minAmplitude); +#endif + if (amp < minAmplitude) + { + mostQuietNote = note; + minAmplitude = amp; + minStartFrame = note->mAbsoluteStartFrame; + } + else if (amp == minAmplitude && note->mAbsoluteStartFrame < minStartFrame) + { + // use earliest start time as a tie breaker + mostQuietNote = note; + minStartFrame = note->mAbsoluteStartFrame; + } + } +#if SANITY_CHECK + SanityCheck(); +#endif + return mostQuietNote; + } + + void SanityCheck() const; + + UInt32 mState; + SynthNote *mHead; + SynthNote *mTail; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUViewBase/AUViewLocalizedStringKeys.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUViewBase/AUViewLocalizedStringKeys.h new file mode 100755 index 00000000..7f1a8106 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUViewBase/AUViewLocalizedStringKeys.h @@ -0,0 +1,82 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.cpp new file mode 100755 index 00000000..1931dd72 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.cpp @@ -0,0 +1,483 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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) +{ +} + +//_____________________________________________________________________________ +// +AUEffectBase::~AUEffectBase() +{ + Cleanup(); +} + +//_____________________________________________________________________________ +// +void AUEffectBase::Cleanup() +{ + for (KernelList::iterator it = mKernelList.begin(); it != mKernelList.end(); ++it) + delete *it; + + mKernelList.clear(); +} + + +//_____________________________________________________________________________ +// +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(); + + + + 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() +{ + UInt32 nChannels = GetNumberOfChannels(); + + if (mKernelList.size() < nChannels) { + mKernelList.reserve(nChannels); + for (UInt32 i = mKernelList.size(); i < nChannels; ++i) + mKernelList.push_back(NewKernel()); + } else + while (mKernelList.size() > nChannels) { + AUKernelBase *kernel = mKernelList.back(); + delete kernel; + mKernelList.pop_back(); + } + + for(unsigned int i = 0; i < nChannels; 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; + + // 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 * inSliceFramesToProcess * sizeof(AudioUnitSampleType)); + } + + for(unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++ ) { + outputBufferList.mBuffers[i].mDataByteSize = + (outputBufferList.mBuffers[i].mNumberChannels * inSliceFramesToProcess * sizeof(AudioUnitSampleType)); + } + // 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 = + (AudioUnitSampleType *)inputBufferList.mBuffers[i].mData + inputBufferList.mBuffers[i].mNumberChannels * inSliceFramesToProcess; + } + + for(unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++ ) { + outputBufferList.mBuffers[i].mData = + (AudioUnitSampleType *)outputBufferList.mBuffers[i].mData + outputBufferList.mBuffers[i].mNumberChannels * inSliceFramesToProcess; + } + + return result; +} + +// ____________________________________________________________________________ +// + +OSStatus AUEffectBase::Render( AudioUnitRenderActionFlags &ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 nFrames) +{ + if (!HasInput(0)) + return kAudioUnitErr_NoConnection; + + OSStatus result = noErr; + AUOutputElement *theOutput = GetOutput(0); // throws if error + + AUInputElement *theInput = GetInput(0); + result = theInput->PullInput(ioActionFlags, inTimeStamp, 0 /* element */, nFrames); + + if (result == noErr) + { + if(ProcessesInPlace() && theOutput->WillAllocateBuffer()) + { + theOutput->SetBufferList(theInput->GetBufferList() ); + } + + if (ShouldBypassEffect()) + { + // leave silence bit alone + + if(!ProcessesInPlace() ) + { + theInput->CopyBufferContentsTo (theOutput->GetBufferList()); + } + } + else + { + if(mParamList.size() == 0 ) + { + // this will read/write silence bit + result = ProcessBufferLists(ioActionFlags, theInput->GetBufferList(), theOutput->GetBufferList(), nFrames); + } + else + { + // deal with scheduled parameters... + + AudioBufferList &inputBufferList = theInput->GetBufferList(); + AudioBufferList &outputBufferList = theOutput->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 + for(unsigned int i = 0; i < inputBufferList.mNumberBuffers; i++ ) { + inputBufferList.mBuffers[i].mData = + (AudioUnitSampleType *)inputBufferList.mBuffers[i].mData - inputBufferList.mBuffers[i].mNumberChannels * nFrames; + inputBufferList.mBuffers[i].mDataByteSize = + (inputBufferList.mBuffers[i].mNumberChannels * nFrames * sizeof(AudioUnitSampleType)); + } + + for(unsigned int i = 0; i < outputBufferList.mNumberBuffers; i++ ) { + outputBufferList.mBuffers[i].mData = + (AudioUnitSampleType *)outputBufferList.mBuffers[i].mData - outputBufferList.mBuffers[i].mNumberChannels * nFrames; + outputBufferList.mBuffers[i].mDataByteSize = + (outputBufferList.mBuffers[i].mNumberChannels * nFrames * sizeof(AudioUnitSampleType)); + } + } + } + + if ( (ioActionFlags & kAudioUnitRenderAction_OutputIsSilence) && !ProcessesInPlace() ) + { + AUBufferList::ZeroBuffer(theOutput->GetBufferList() ); + } + } + + return result; +} + +OSStatus AUEffectBase::ProcessBufferLists( + 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) { + // interleaved (or mono) + int channel = 0; + + for (KernelList::iterator it = mKernelList.begin(); it != mKernelList.end(); ++it, ++channel) { + AUKernelBase *kernel = *it; + + if (kernel != NULL) { + ioSilence = silentInput; + + // process each interleaved channel individually + kernel->Process( + (const AudioUnitSampleType *)inBuffer.mBuffers[0].mData + channel, + (AudioUnitSampleType *)outBuffer.mBuffers[0].mData + channel, + inFramesToProcess, + inBuffer.mBuffers[0].mNumberChannels, + ioSilence); + + if (!ioSilence) + ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence; + } + } + } else { + // deinterleaved + const AudioBuffer *srcBuffer = inBuffer.mBuffers; + AudioBuffer *destBuffer = outBuffer.mBuffers; + + for (KernelList::iterator it = mKernelList.begin(); it != mKernelList.end(); + ++it, ++srcBuffer, ++destBuffer) { + AUKernelBase *kernel = *it; + + if (kernel != NULL) { + ioSilence = silentInput; + + kernel->Process( + (const AudioUnitSampleType *)srcBuffer->mData, + (AudioUnitSampleType *)destBuffer->mData, + inFramesToProcess, + 1, + ioSilence); + + if (!ioSilence) + ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence; + } + } + } + + return noErr; +} + +Float64 AUEffectBase::GetSampleRate() +{ + return GetOutput(0)->GetStreamFormat().mSampleRate; +} + +UInt32 AUEffectBase::GetNumberOfChannels() +{ + return GetOutput(0)->GetStreamFormat().mChannelsPerFrame; +} + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.h new file mode 100755 index 00000000..886963d7 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUEffectBase.h @@ -0,0 +1,269 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __AUEffectBase_h__ +#define __AUEffectBase_h__ + +#include "AUBase.h" +#include "AUSilentTimeout.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 */ + void SetParameter( AudioUnitParameterID paramID, + AudioUnitParameterValue value) + { + Globals()->SetParameter(paramID, value); + } + + /*! @method GetParameter */ + AudioUnitParameterValue GetParameter( AudioUnitParameterID paramID ) + { + return Globals()->GetParameter(paramID ); + } + + /*! @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; + } + +private: + /*! @var mBypassEffect */ + bool mBypassEffect; + /*! @var mParamSRDep */ + bool mParamSRDep; + + /*! @var mProcessesInplace */ + bool mProcessesInPlace; + + /*! @var mSilentTimeout */ + AUSilentTimeout mSilentTimeout; + + +}; + + +// 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 AudioUnitSampleType * inSourceP, + AudioUnitSampleType * inDestP, + UInt32 inFramesToProcess, + UInt32 inNumChannels, + bool & ioSilence) = 0; + + /*! @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; + +}; + + + +#endif // __AUEffectBase_h__ diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIBase.cpp new file mode 100755 index 00000000..21c0c18c --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIBase.cpp @@ -0,0 +1,481 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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) { + 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; + +#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; +InvalidScope: + return kAudioUnitErr_InvalidScope; +InvalidElement: + return kAudioUnitErr_InvalidElement; +} + +OSStatus AUMIDIBase::DelegateGetProperty( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData) +{ + OSStatus result; + + switch (inID) { + case kMusicDeviceProperty_MIDIXMLNames: + ca_require(inScope == kAudioUnitScope_Global, InvalidScope); + ca_require(inElement == 0, InvalidElement); + result = GetXMLNames((CFURLRef *)outData); + break; + +#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; +InvalidScope: + return kAudioUnitErr_InvalidScope; +InvalidElement: + return kAudioUnitErr_InvalidElement; +} + +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], 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 + + +OSStatus AUMIDIBase::ComponentEntryDispatch( ComponentParameters * params, + AUMIDIBase * This) +{ + if (This == NULL) return paramErr; + + 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; +} + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIBase.h new file mode 100755 index 00000000..0b6fe2a5 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIBase.h @@ -0,0 +1,207 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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 */ + 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 */ + 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 !TARGET_OS_IPHONE + // component dispatcher + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch( ComponentParameters *params, + AUMIDIBase *This); +#endif +}; + +#endif // __AUMIDIBase_h__ diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.cpp new file mode 100755 index 00000000..a9087099 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.cpp @@ -0,0 +1,158 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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_AU_IS_ONLY_PLUGIN + 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->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame); + } + COMPONENT_CATCH + return result; +} diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.h new file mode 100755 index 00000000..ce28e55d --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUMIDIEffectBase.h @@ -0,0 +1,83 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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 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/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUOutputBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUOutputBase.cpp new file mode 100755 index 00000000..8203a235 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUOutputBase.cpp @@ -0,0 +1,105 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "AUOutputBase.h" + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=mac68k +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(push, 2) +#elif PRAGMA_STRUCT_PACK + #pragma pack(2) +#endif + +#if TARGET_API_MAC_OS8 || TARGET_API_MAC_OSX +struct AudioOutputUnitStartStopGluePB { + unsigned char componentFlags; + unsigned char componentParamSize; + short componentWhat; + AudioUnit ci; +}; +#elif TARGET_OS_WIN32 +struct AudioOutputUnitStartStopGluePB { + unsigned char componentFlags; + unsigned char componentParamSize; + short componentWhat; +}; +#else + #error Platform not supported +#endif + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=reset +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(pop) +#elif PRAGMA_STRUCT_PACK + #pragma pack() +#endif + +#if !TARGET_OS_IPHONE +OSStatus AUOutputBase::ComponentEntryDispatch(ComponentParameters *params, AUOutputBase *This) +{ + if (This == NULL) return paramErr; + + OSStatus result; + + switch (params->what) { + case kAudioOutputUnitStartSelect: + { + //AudioOutputUnitStartStopGluePB *p = (AudioOutputUnitStartStopGluePB *)params; + result = This->Start(); + } + break; + + case kAudioOutputUnitStopSelect: + { + //AudioOutputUnitStartStopGluePB *p = (AudioOutputUnitStartStopGluePB *)params; + result = This->Stop(); + } + break; + + default: + result = badComponentSelector; + break; + } + + return result; +} +#endif diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUOutputBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUOutputBase.h new file mode 100755 index 00000000..ea516c84 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUOutputBase.h @@ -0,0 +1,76 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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 !TARGET_OS_IPHONE + // component dispatcher + /*! @method ComponentEntryDispatch */ + static OSStatus ComponentEntryDispatch( ComponentParameters * params, + AUOutputBase * This); +#endif + +private: + /*! @var mAUBaseInstance */ + AUBase & mAUBaseInstance; +}; + +#endif // __AUOutputBase_h__ diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUPannerBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUPannerBase.cpp new file mode 100755 index 00000000..5c0b4858 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUPannerBase.cpp @@ -0,0 +1,700 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "AUPannerBase.h" +#include "CABundleLocker.h" +#include +#include + +static bool sLocalized = false; + +static CFStringRef kPanner_Azimuth_Name = CFSTR("azimuth"); +static CFStringRef kPanner_Elevation_Name = CFSTR("elevation"); +static CFStringRef kPanner_Distance_Name = CFSTR("distance"); + +static CFStringRef kPanner_CoordScale_Name = CFSTR("coordinate scale"); +static CFStringRef kPanner_RefDistance_Name = CFSTR("reference distance"); +static CFStringRef kPanner_Gain_Name = CFSTR("gain"); + +static Float32 kPannerParamDefault_Azimuth = 0.; +static Float32 kPannerParamDefault_Elevation = 0.; +static Float32 kPannerParamDefault_Distance = 1.; + +static Float32 kPannerParamDefault_CoordScale = 10.; +static Float32 kPannerParamDefault_RefDistance = 1.; +static Float32 kPannerParamDefault_Gain = 1.; + +//_____________________________________________________________________________ +// +AUPannerBase::AUPannerBase(AudioComponentInstance inAudioUnit) + : AUBase(inAudioUnit, 1, 1), mBypassEffect(false) +{ + { + CABundleLocker lock; + if (!sLocalized) + { + CFBundleRef bundle = CFBundleGetBundleWithIdentifier( CFSTR("com.apple.audio.units.Components") ); + if (bundle != NULL) + { + kPanner_Azimuth_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Azimuth_Name, CFSTR("AudioUnits"), bundle, CFSTR("")); + kPanner_Elevation_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Elevation_Name, CFSTR("AudioUnits"), bundle, CFSTR("")); + kPanner_Distance_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Distance_Name, CFSTR("AudioUnits"), bundle, CFSTR("")); + + kPanner_CoordScale_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_CoordScale_Name, CFSTR("AudioUnits"), bundle, CFSTR("")); + kPanner_RefDistance_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_RefDistance_Name, CFSTR("AudioUnits"), bundle, CFSTR("")); + kPanner_Gain_Name = CFCopyLocalizedStringFromTableInBundle(kPanner_Gain_Name, CFSTR("AudioUnits"), bundle, CFSTR("")); + + } + + sLocalized = true; + } + } + + CreateElements(); + + SetParameter(kPannerParam_Azimuth, kPannerParamDefault_Azimuth); + SetParameter(kPannerParam_Elevation, kPannerParamDefault_Elevation); + SetParameter(kPannerParam_Distance, kPannerParamDefault_Distance); + + SetParameter(kPannerParam_CoordScale, kPannerParamDefault_CoordScale); + SetParameter(kPannerParam_RefDistance, kPannerParamDefault_RefDistance); + SetParameter(kPannerParam_Gain, kPannerParamDefault_Gain); +} + +//_____________________________________________________________________________ +// +AUPannerBase::~AUPannerBase() +{ + Cleanup(); +} + +//_____________________________________________________________________________ +// +/*! @method Initialize */ +OSStatus AUPannerBase::Initialize() +{ + OSStatus err = noErr; + AllocBypassMatrix(); + err = UpdateBypassMatrix(); + return err; +} + +//_____________________________________________________________________________ +// +/*! @method AllocBypassMatrix */ +void AUPannerBase::AllocBypassMatrix() +{ + UInt32 inChannels = GetNumberOfInputChannels(); + UInt32 outChannels = GetNumberOfOutputChannels(); + mBypassMatrix.alloc(inChannels * outChannels, true); +} + +static AudioChannelLayoutTag DefaultTagForNumberOfChannels(UInt32 inNumberChannels) +{ + switch (inNumberChannels) { + case 1: return kAudioChannelLayoutTag_Mono; + case 2: return kAudioChannelLayoutTag_Stereo; + case 4: return kAudioChannelLayoutTag_Quadraphonic; + case 5: return kAudioChannelLayoutTag_AudioUnit_5_0; + case 6: return kAudioChannelLayoutTag_AudioUnit_6_0; + case 7: return kAudioChannelLayoutTag_AudioUnit_7_0; + case 8: return kAudioChannelLayoutTag_AudioUnit_8; + + default: return 0xFFFF0000 | inNumberChannels; + } +} + +//_____________________________________________________________________________ +// +/*! @method UpdateBypassMatrix */ +OSStatus AUPannerBase::SetDefaultChannelLayoutsIfNone() +{ + OSStatus err = noErr; + + // if layout has not been set, then guess layout from number of channels + UInt32 inChannels = GetNumberOfInputChannels(); + AudioChannelLayout inputLayoutSubstitute; + const AudioChannelLayout* inputLayout = &GetInputLayout(); + if (inputLayout == NULL || inputLayout->mChannelLayoutTag == 0) { + inputLayout = &inputLayoutSubstitute; + inputLayoutSubstitute.mNumberChannelDescriptions = 0; + inputLayoutSubstitute.mChannelBitmap = 0; + inputLayoutSubstitute.mChannelLayoutTag = DefaultTagForNumberOfChannels(inChannels); + + mInputLayout = &inputLayoutSubstitute; + err = SetAudioChannelLayout(kAudioUnitScope_Input, 0, &GetInputLayout()); + if (err) return err; + } + + // if layout has not been set, then guess layout from number of channels + UInt32 outChannels = GetNumberOfOutputChannels(); + AudioChannelLayout outputLayoutSubstitute; + const AudioChannelLayout* outputLayout = &GetOutputLayout(); + if (outputLayout == NULL || outputLayout->mChannelLayoutTag == 0) { + outputLayout = &outputLayoutSubstitute; + outputLayoutSubstitute.mNumberChannelDescriptions = 0; + outputLayoutSubstitute.mChannelBitmap = 0; + outputLayoutSubstitute.mChannelLayoutTag = DefaultTagForNumberOfChannels(outChannels); + + mOutputLayout = &outputLayoutSubstitute; + err = SetAudioChannelLayout(kAudioUnitScope_Output, 0, &GetOutputLayout()); + if (err) return err; + } + + return err; +} + + + +OSStatus AUPannerBase::UpdateBypassMatrix() +{ + OSStatus err = SetDefaultChannelLayoutsIfNone(); + if (err) return err; + + UInt32 inChannels = GetNumberOfInputChannels(); + UInt32 outChannels = GetNumberOfOutputChannels(); + + const AudioChannelLayout* inoutACL[2]; + + inoutACL[0] = &GetInputLayout(); + inoutACL[1] = &GetOutputLayout(); + + mBypassMatrix.alloc(inChannels * outChannels, true); + + UInt32 propSize = inChannels * outChannels * sizeof(Float32); + + err = AudioFormatGetProperty(kAudioFormatProperty_MatrixMixMap, sizeof(inoutACL), inoutACL, &propSize, mBypassMatrix()); + if (err) { + // if there is an error, use a diagonal matrix. + Float32* bypass = mBypassMatrix(); + for (UInt32 chan = 0; chan < std::min(inChannels, outChannels); ++chan) + { + float *amp = bypass + (chan * outChannels + chan); + *amp = 1.; + } + } + + return noErr; +} + +//_____________________________________________________________________________ +// +/*! @method Cleanup */ +void AUPannerBase::Cleanup() +{ + +} + + +//_____________________________________________________________________________ +// +/*! @method Reset */ +OSStatus AUPannerBase::Reset( AudioUnitScope inScope, + AudioUnitElement inElement) +{ + return AUBase::Reset(inScope, inElement); +} + +//_____________________________________________________________________________ +// +/*! @method GetParameterInfo */ +OSStatus AUPannerBase::GetParameterInfo( AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + AudioUnitParameterInfo &outParameterInfo ) +{ + OSStatus result = noErr; + + outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable + + kAudioUnitParameterFlag_IsReadable; + + if (inScope == kAudioUnitScope_Global) { + + switch(inParameterID) + { + case kPannerParam_Azimuth: + AUBase::FillInParameterName (outParameterInfo, kPanner_Azimuth_Name, false); + outParameterInfo.unit = kAudioUnitParameterUnit_Degrees; + outParameterInfo.minValue = -180.; + outParameterInfo.maxValue = 180; + outParameterInfo.defaultValue = kPannerParamDefault_Azimuth; + break; + + case kPannerParam_Elevation: + AUBase::FillInParameterName (outParameterInfo, kPanner_Elevation_Name, false); + outParameterInfo.unit = kAudioUnitParameterUnit_Degrees; + outParameterInfo.minValue = -90.; + outParameterInfo.maxValue = 90; + outParameterInfo.defaultValue = kPannerParamDefault_Elevation; + break; + + case kPannerParam_Distance: + AUBase::FillInParameterName (outParameterInfo, kPanner_Distance_Name, false); + outParameterInfo.unit = kAudioUnitParameterUnit_Generic; + outParameterInfo.minValue = 0.0; + outParameterInfo.maxValue = 1.; + outParameterInfo.defaultValue = kPannerParamDefault_Distance; + outParameterInfo.flags += kAudioUnitParameterFlag_IsHighResolution; + //outParameterInfo.flags += kAudioUnitParameterFlag_DisplayLogarithmic; + break; + + case kPannerParam_CoordScale: + AUBase::FillInParameterName (outParameterInfo, kPanner_CoordScale_Name, false); + outParameterInfo.unit = kAudioUnitParameterUnit_Meters; + outParameterInfo.minValue = 0.01; + outParameterInfo.maxValue = 1000.; + outParameterInfo.defaultValue = kPannerParamDefault_CoordScale; + outParameterInfo.flags += kAudioUnitParameterFlag_DisplayLogarithmic; + break; + + case kPannerParam_RefDistance: + AUBase::FillInParameterName (outParameterInfo, kPanner_RefDistance_Name, false); + outParameterInfo.unit = kAudioUnitParameterUnit_Meters; + outParameterInfo.minValue = 0.01; + outParameterInfo.maxValue = 1000.; + outParameterInfo.defaultValue = kPannerParamDefault_RefDistance; + outParameterInfo.flags += kAudioUnitParameterFlag_DisplayLogarithmic; + break; + + case kPannerParam_Gain: + AUBase::FillInParameterName (outParameterInfo, kPanner_Gain_Name, false); + outParameterInfo.unit = kAudioUnitParameterUnit_Generic; + outParameterInfo.minValue = 0.; + outParameterInfo.maxValue = 1.; + outParameterInfo.defaultValue = kPannerParamDefault_Gain; + break; + + default: + result = kAudioUnitErr_InvalidParameter; + break; + } + } else { + result = kAudioUnitErr_InvalidParameter; + } + + return result; +} + +//_____________________________________________________________________________ +// +OSStatus AUPannerBase::GetParameter( AudioUnitParameterID inParamID, + AudioUnitScope inScope, + AudioUnitElement inElement, + Float32 & outValue) +{ + if (inScope != kAudioUnitScope_Global) + return kAudioUnitErr_InvalidScope; + + outValue = Globals()->GetParameter(inParamID); + + return noErr; +} + + +//_____________________________________________________________________________ +// +OSStatus AUPannerBase::SetParameter( AudioUnitParameterID inParamID, + AudioUnitScope inScope, + AudioUnitElement inElement, + Float32 inValue, + UInt32 inBufferOffsetInFrames) +{ + if (inScope != kAudioUnitScope_Global) + return kAudioUnitErr_InvalidScope; + + Globals()->SetParameter(inParamID, inValue); + + return noErr; +} + + + +//_____________________________________________________________________________ +// +/*! @method GetPropertyInfo */ +OSStatus AUPannerBase::GetPropertyInfo (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable) +{ + OSStatus err = noErr; + switch (inID) { + case kAudioUnitProperty_BypassEffect: + if (inScope != kAudioUnitScope_Global) + return kAudioUnitErr_InvalidScope; + + outWritable = true; + outDataSize = sizeof (UInt32); + break; + default: + err = AUBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable); + } + return err; +} + +//_____________________________________________________________________________ +// +/*! @method GetProperty */ +OSStatus AUPannerBase::GetProperty (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void * outData) +{ + OSStatus err = noErr; + switch (inID) + { + case kAudioUnitProperty_BypassEffect: + if (inScope != kAudioUnitScope_Global) + return kAudioUnitErr_InvalidScope; + + *((UInt32*)outData) = (IsBypassEffect() ? 1 : 0); + break; + default: + err = AUBase::GetProperty(inID, inScope, inElement, outData); + } + return err; +} + +//_____________________________________________________________________________ +// +/*! @method SetProperty */ +OSStatus AUPannerBase::SetProperty(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize) +{ + 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; + } + return AUBase::SetProperty(inID, inScope, inElement, inData, inDataSize); +} + + +//_____________________________________________________________________________ +// +/*! @method StreamFormatWritable */ +bool AUPannerBase::StreamFormatWritable (AudioUnitScope scope, + AudioUnitElement element) +{ + return true; +} + +//_____________________________________________________________________________ +// +/*! @method ChangeStreamFormat */ +OSStatus AUPannerBase::ChangeStreamFormat ( + AudioUnitScope inScope, + AudioUnitElement inElement, + const CAStreamBasicDescription & inPrevFormat, + const CAStreamBasicDescription & inNewFormat) +{ + if (inScope == kAudioUnitScope_Input && !InputChannelConfigIsSupported(inNewFormat.NumberChannels())) + return kAudioUnitErr_FormatNotSupported; + + if (inScope == kAudioUnitScope_Output && !OutputChannelConfigIsSupported(inNewFormat.NumberChannels())) + return kAudioUnitErr_FormatNotSupported; + + if (inNewFormat.NumberChannels() != inPrevFormat.NumberChannels()) + RemoveAudioChannelLayout(inScope, inElement); + + return AUBase::ChangeStreamFormat(inScope, inElement, inPrevFormat, inNewFormat); +} + +//_____________________________________________________________________________ +// +/*! @method Render */ +OSStatus AUPannerBase::Render(AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inNumberFrames) +{ + if (IsBypassEffect()) + return BypassRender(ioActionFlags, inTimeStamp, inNumberFrames); + else + return PannerRender(ioActionFlags, inTimeStamp, inNumberFrames); +} + +//_____________________________________________________________________________ +// +/*! @method Render */ +OSStatus AUPannerBase::BypassRender(AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inNumberFrames) +{ + AudioUnitRenderActionFlags xflags = 0; + OSStatus result = PullInput(0, xflags, inTimeStamp, inNumberFrames); + if (result) return false; + bool isSilent = xflags & kAudioUnitRenderAction_OutputIsSilence; + + AudioBufferList& outputBufferList = GetOutput(0)->GetBufferList(); + AUBufferList::ZeroBuffer(outputBufferList); + + if (!isSilent) + { + UInt32 inChannels = GetNumberOfInputChannels(); + UInt32 outChannels = GetNumberOfOutputChannels(); + Float32* bypass = mBypassMatrix(); + for (UInt32 outChan = 0; outChan < outChannels; ++outChan) + { + float* outData = GetOutput(0)->GetChannelData(outChan); + + for (UInt32 inChan = 0; inChan < inChannels; ++inChan) + { + float* inData = GetInput(0)->GetChannelData(inChan); + float *amp = bypass + (inChan * outChannels + outChan); + vDSP_vsma(inData, 1, amp, outData, 1, outData, 1, inNumberFrames); + } + } + } + return noErr; +} + +//_____________________________________________________________________________ +// +UInt32 AUPannerBase::GetAudioChannelLayout( AudioUnitScope inScope, + AudioUnitElement inElement, + AudioChannelLayout * outLayoutPtr, + Boolean & outWritable) +{ + SetDefaultChannelLayoutsIfNone(); + + outWritable = true; + + CAAudioChannelLayout* caacl = NULL; + switch (inScope) + { + case kAudioUnitScope_Input: + caacl = &mInputLayout; + break; + case kAudioUnitScope_Output: + caacl = &mOutputLayout; + break; + default: + COMPONENT_THROW(kAudioUnitErr_InvalidScope); + } + + if (inElement != 0) + COMPONENT_THROW(kAudioUnitErr_InvalidElement); + + UInt32 size = caacl->IsValid() ? caacl->Size() : 0; + if (size > 0 && outLayoutPtr) + memcpy(outLayoutPtr, &caacl->Layout(), size); + + return size; +} + +//_____________________________________________________________________________ +// +OSStatus AUPannerBase::RemoveAudioChannelLayout( AudioUnitScope inScope, + AudioUnitElement inElement) +{ + CAAudioChannelLayout* caacl = NULL; + switch (inScope) + { + case kAudioUnitScope_Input: + caacl = &mInputLayout; + break; + case kAudioUnitScope_Output: + caacl = &mOutputLayout; + break; + default: + return kAudioUnitErr_InvalidScope; + } + + if (inElement != 0) + return kAudioUnitErr_InvalidElement; + + *caacl = NULL; + return noErr; +} + +//_____________________________________________________________________________ +// +OSStatus AUPannerBase::SetAudioChannelLayout( AudioUnitScope inScope, + AudioUnitElement inElement, + const AudioChannelLayout * inLayout) +{ + if (!inLayout) + return RemoveAudioChannelLayout(inScope, inElement); + + if (!ChannelLayoutTagIsSupported(inScope, inElement, inLayout->mChannelLayoutTag)) + return kAudioUnitErr_FormatNotSupported; + + CAAudioChannelLayout* caacl = NULL; + UInt32 currentChannels; + switch (inScope) + { + case kAudioUnitScope_Input: + caacl = &mInputLayout; + currentChannels = GetNumberOfInputChannels(); + break; + case kAudioUnitScope_Output: + caacl = &mOutputLayout; + currentChannels = GetNumberOfOutputChannels(); + break; + default: + return kAudioUnitErr_InvalidScope; + } + + if (inElement != 0) + return kAudioUnitErr_InvalidElement; + + UInt32 numChannelsInLayout = CAAudioChannelLayout::NumberChannels(*inLayout); + if (currentChannels != numChannelsInLayout) + return kAudioUnitErr_InvalidPropertyValue; + + *caacl = inLayout; + if (IsInitialized()) + UpdateBypassMatrix(); + + return noErr; +} + +//_____________________________________________________________________________ +// +UInt32 AUPannerBase::GetChannelLayoutTags( AudioUnitScope inScope, + AudioUnitElement inElement, + AudioChannelLayoutTag* outTags) +{ + switch (inScope) + { + case kAudioUnitScope_Input: + if (outTags) { + outTags[0] = kAudioChannelLayoutTag_Mono; + outTags[1] = kAudioChannelLayoutTag_Stereo; + outTags[2] = kAudioChannelLayoutTag_Ambisonic_B_Format; + } + return 3; + case kAudioUnitScope_Output: + if (outTags) { + outTags[0] = kAudioChannelLayoutTag_Stereo; + outTags[1] = kAudioChannelLayoutTag_Quadraphonic; + outTags[2] = kAudioChannelLayoutTag_AudioUnit_5_0; + outTags[3] = kAudioChannelLayoutTag_AudioUnit_6_0; + outTags[4] = kAudioChannelLayoutTag_AudioUnit_7_0; + outTags[5] = kAudioChannelLayoutTag_AudioUnit_7_0_Front; + outTags[6] = kAudioChannelLayoutTag_AudioUnit_8; + } + return 7; + default: { + OSStatus err = kAudioUnitErr_InvalidScope; + throw err; + } + } +} + + + +//_____________________________________________________________________________ +// +bool AUPannerBase::ChannelConfigIsSupported() +{ + UInt32 inChannels = GetNumberOfInputChannels(); + UInt32 outChannels = GetNumberOfOutputChannels(); + const AUChannelInfo* cinfo = NULL; + UInt32 numConfigs = SupportedNumChannels(&cinfo); + for (UInt32 i = 0; i < numConfigs; ++i) + { + if (cinfo[i].inChannels == (SInt16)inChannels && cinfo[i].outChannels == (SInt16)outChannels) + return true; + } + return false; +} + + +//_____________________________________________________________________________ +// +bool AUPannerBase::InputChannelConfigIsSupported(UInt32 inNumberChannels) +{ + const AUChannelInfo* cinfo = NULL; + UInt32 numConfigs = SupportedNumChannels(&cinfo); + for (UInt32 i = 0; i < numConfigs; ++i) + { + if (cinfo[i].inChannels == (SInt16)inNumberChannels) + return true; + } + return false; +} + +//_____________________________________________________________________________ +// +bool AUPannerBase::OutputChannelConfigIsSupported(UInt32 inNumberChannels) +{ + const AUChannelInfo* cinfo = NULL; + UInt32 numConfigs = SupportedNumChannels(&cinfo); + for (UInt32 i = 0; i < numConfigs; ++i) + { + if (cinfo[i].outChannels == (SInt16)inNumberChannels) + return true; + } + return false; +} + +//_____________________________________________________________________________ +// +bool AUPannerBase::ChannelLayoutTagIsSupported( AudioUnitScope inScope, + AudioUnitElement inElement, + AudioChannelLayoutTag inTag) +{ + UInt32 numTags = GetChannelLayoutTags(inScope, inElement, NULL); + CAAutoFree tags(numTags); + GetChannelLayoutTags(inScope, inElement, tags()); + + for (UInt32 i = 0; i < numTags; ++i) + { + if (tags[i] == inTag) + return true; + } + + return false; +} + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUPannerBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUPannerBase.h new file mode 100755 index 00000000..fa2140cc --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/AUPannerBase.h @@ -0,0 +1,263 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __AUPannerBase_h__ +#define __AUPannerBase_h__ + +#include "AUBase.h" +#include +#include "CAAutoDisposer.h" +#include "CAAudioChannelLayout.h" + + +/*! @class AUPannerBase */ +class AUPannerBase : public AUBase +{ +public: +/*! @ctor AUPannerBase */ + AUPannerBase(AudioComponentInstance inAudioUnit); +/*! @dtor ~AUPannerBase */ + virtual ~AUPannerBase(); + + /*! @method Initialize */ + virtual OSStatus Initialize(); + + /*! @method Cleanup */ + virtual void Cleanup(); + + + /*! @method Reset */ + virtual OSStatus Reset( AudioUnitScope inScope, + AudioUnitElement inElement); + + /*! @method GetParameterInfo */ + virtual OSStatus GetParameterInfo( AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + AudioUnitParameterInfo &outParameterInfo ); + + + /*! @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 IsBypassEffect */ + // This is used for the property value - to reflect to the UI if an effect is bypassed + bool IsBypassEffect () { return mBypassEffect; } + + /*! @method SetBypassEffect */ + virtual void SetBypassEffect (bool inFlag) { mBypassEffect = inFlag; } + + + /*! @method Render */ + virtual OSStatus Render(AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inNumberFrames); + + /*! @method Render */ + virtual OSStatus PannerRender(AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inNumberFrames) = 0; + + /*! @method BypassRender */ + virtual OSStatus BypassRender(AudioUnitRenderActionFlags & ioActionFlags, + const AudioTimeStamp & inTimeStamp, + UInt32 inNumberFrames); + + + /*! @method GetAudioChannelLayout */ + virtual UInt32 GetAudioChannelLayout( AudioUnitScope inScope, + AudioUnitElement inElement, + AudioChannelLayout * outLayoutPtr, + Boolean & outWritable); + + /*! @method SetAudioChannelLayout */ + virtual OSStatus SetAudioChannelLayout( AudioUnitScope inScope, + AudioUnitElement inElement, + const AudioChannelLayout * inLayout); + + /*! @method RemoveAudioChannelLayout */ + virtual OSStatus RemoveAudioChannelLayout( AudioUnitScope inScope, + AudioUnitElement inElement); + + /*! @method GetChannelLayoutTags */ + virtual UInt32 GetChannelLayoutTags( AudioUnitScope inScope, + AudioUnitElement inElement, + AudioChannelLayoutTag* outTags); + + /*! @method GetNumberOfInputChannels */ + UInt32 GetNumberOfInputChannels() { return ((AUIOElement*)Inputs().SafeGetElement(0))->NumberChannels(); }; + /*! @method GetNumberOfOutputChannels */ + UInt32 GetNumberOfOutputChannels() { return ((AUIOElement*)Outputs().SafeGetElement(0))->NumberChannels(); } + + /*! @method GetParameter */ + virtual OSStatus GetParameter( AudioUnitParameterID inParamID, + AudioUnitScope inScope, + AudioUnitElement inElement, + Float32 & outValue); + + /*! @method SetParameter */ + virtual OSStatus SetParameter( AudioUnitParameterID inParamID, + AudioUnitScope inScope, + AudioUnitElement inElement, + Float32 inValue, + UInt32 inBufferOffsetInFrames); + + // convenience wrappers for accessing parameters in the global scope + /*! @method SetParameter */ + void SetParameter( UInt32 inParamID, + Float32 inValue) + { + OSStatus err = SetParameter(inParamID, kAudioUnitScope_Global, 0, inValue, 0); + if (err) throw err; + } + + /*! @method GetParameter */ + Float32 GetParameter( UInt32 inParamID ) + { + Float32 outValue = 0.; + OSStatus err = GetParameter(inParamID, kAudioUnitScope_Global, 0, outValue); + if (err) throw err; + return outValue; + } + + /*! @method InputChannelConfigIsSupported */ + bool InputChannelConfigIsSupported(UInt32 inNumberChannels); + /*! @method OutputChannelConfigIsSupported */ + bool OutputChannelConfigIsSupported(UInt32 inNumberChannels); + /*! @method ChannelConfigIsSupported */ + bool ChannelConfigIsSupported(); + + /*! @method SupportsTail */ + virtual bool SupportsTail () { return true; } + /*! @method GetTailTime */ + virtual Float64 GetTailTime() { return 0; } + + + /*! @method GetGain */ + Float32 GetGain() { return GetParameter(kPannerParam_Gain); } + /*! @method GetTailTime */ + Float32 GetAzimuth() { return GetParameter(kPannerParam_Azimuth); } + /*! @method GetElevation */ + Float32 GetElevation() { return GetParameter(kPannerParam_Elevation); } + /*! @method GetDistance */ + Float32 GetDistance() { return GetParameter(kPannerParam_Distance); } + /*! @method GetCoordScale */ + Float32 GetCoordScale() { return GetParameter(kPannerParam_CoordScale); } + /*! @method GetRefDistance */ + Float32 GetRefDistance() { return GetParameter(kPannerParam_RefDistance); } + + /*! @method SetGain */ + void SetGain(Float32 inValue) { SetParameter(kPannerParam_Gain, inValue); } + /*! @method SetAzimuth */ + void SetAzimuth(Float32 inValue) { SetParameter(kPannerParam_Azimuth, inValue); } + /*! @method SetElevation */ + void SetElevation(Float32 inValue) { SetParameter(kPannerParam_Elevation, inValue); } + /*! @method SetDistance */ + void SetDistance(Float32 inValue) { SetParameter(kPannerParam_Distance, inValue); } + /*! @method SetCoordScale */ + void SetCoordScale(Float32 inValue) { SetParameter(kPannerParam_CoordScale, inValue); } + /*! @method SetRefDistance */ + void SetRefDistance(Float32 inValue) { SetParameter(kPannerParam_RefDistance, inValue); } + +protected: + /*! @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(); } + + /*! @method AllocBypassMatrix */ + void AllocBypassMatrix(); + + /*! @method UpdateBypassMatrix */ + OSStatus UpdateBypassMatrix(); + + /*! @method SetDefaultChannelLayoutsIfNone */ + OSStatus SetDefaultChannelLayoutsIfNone(); + + /*! @method ChannelLayoutTagIsSupported */ + bool ChannelLayoutTagIsSupported( AudioUnitScope inScope, + AudioUnitElement inElement, + AudioChannelLayoutTag inTag); + + const AudioChannelLayout& GetInputLayout() const { return mInputLayout.Layout(); } + const AudioChannelLayout& GetOutputLayout() const { return mOutputLayout.Layout(); } + +private: + + /*! @var UpdateBypassMatrix */ + bool mBypassEffect; + /*! @var mBypassMatrix */ + CAAutoFree mBypassMatrix; + /*! @var mInputLayout */ + CAAudioChannelLayout mInputLayout; + /*! @var mOutputLayout */ + CAAudioChannelLayout mOutputLayout; +}; + +#endif /* __AUPannerBase_h__ */ diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.cpp new file mode 100755 index 00000000..986d2ca4 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.cpp @@ -0,0 +1,343 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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); + + +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); + + + +MusicDeviceBase::MusicDeviceBase(AudioComponentInstance inInstance, + UInt32 numInputs, + UInt32 numOutputs, + UInt32 numGroups, + UInt32 numParts) + : AUBase(inInstance, numInputs, numOutputs, numGroups, numParts), + AUMIDIBase(this) +{ +} + +OSStatus MusicDeviceBase::GetPropertyInfo(AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 & outDataSize, + Boolean & outWritable) +{ + OSStatus result; + + switch (inID) + { + case kMusicDeviceProperty_InstrumentCount: + if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope; + outDataSize = sizeof(UInt32); + outWritable = false; + result = noErr; + break; + + 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_AU_IS_ONLY_PLUGIN + case kAudioUnitProperty_FastDispatch: + 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 + + case kMusicDeviceProperty_InstrumentCount: + if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope; + return GetInstrumentCount (*(UInt32*)outData); + + 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 paramErr; + + 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 !TARGET_OS_IPHONE +OSStatus MusicDeviceBase::ComponentEntryDispatch( ComponentParameters * params, + MusicDeviceBase * This) +{ + if (This == NULL) return paramErr; + + 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 + + +// 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 paramErr; + 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 paramErr; + MusicDeviceBase *This = static_cast(inComponentStorage); + if (This == NULL) return paramErr; + 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 paramErr; + result = This->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame); + } + COMPONENT_CATCH + return result; +} + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.h new file mode 100755 index 00000000..2223dfad --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/OtherBases/MusicDeviceBase.h @@ -0,0 +1,123 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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, + UInt32 numParts = 0); + + /*! @method PrepareInstrument */ + virtual OSStatus PrepareInstrument(MusicDeviceInstrumentID inInstrument) { return noErr; } + + /*! @method ReleaseInstrument */ + virtual OSStatus ReleaseInstrument(MusicDeviceInstrumentID inInstrument) { return noErr; } + + /*! @method StartNote */ + virtual OSStatus StartNote( MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams &inParams) = 0; + + /*! @method StopNote */ + virtual OSStatus StopNote( MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) = 0; + + /*! @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 !TARGET_OS_IPHONE + // 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/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBaseHelper.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBaseHelper.cpp new file mode 100755 index 00000000..9f73c36f --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBaseHelper.cpp @@ -0,0 +1,128 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "AUBaseHelper.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +OSStatus GetFileRefPath (CFDictionaryRef parent, CFStringRef frKey, CFStringRef * fPath) +{ + static CFStringRef kFRString = CFSTR (kAUPresetExternalFileRefs); + + const void* frVal = CFDictionaryGetValue(parent, kFRString); + if (!frVal) return kAudioUnitErr_InvalidPropertyValue; + + const void* frString = CFDictionaryGetValue ((CFDictionaryRef)frVal, frKey); + if (!frString) return kAudioUnitErr_InvalidPropertyValue; + + if (fPath) + *fPath = (CFStringRef)frString; + + return noErr; +} + +// write valid samples check, with bool for zapping + +UInt32 FindInvalidSamples(Float32 *inSource, UInt32 inFramesToProcess, bool &outHasNonZero, bool zapInvalidSamples) +{ + float *sourceP = inSource; + + UInt32 badSamplesDetected = 0; + bool hasNonZero = false; + for (UInt32 i=0; i < inFramesToProcess; i++) + { + float input = *(sourceP++); + + if(input > 0) + hasNonZero = true; + + float absx = fabs(input); + + // a bad number! + if (!(absx < 1e15)) + { + if (!(absx == 0)) + { + //printf("\tbad sample: %f\n", input); + badSamplesDetected++; + if (zapInvalidSamples) + input = 0; + } + } + } + + return badSamplesDetected; +} + + +CFMutableDictionaryRef CreateFileRefDict (CFStringRef fKey, CFStringRef fPath, CFMutableDictionaryRef fileRefDict) +{ + if (!fileRefDict) + fileRefDict = CFDictionaryCreateMutable (NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + CFDictionarySetValue (fileRefDict, fKey, fPath); + + return fileRefDict; +} + +#if DEBUG +//_____________________________________________________________________________ +// +void PrintAUParamEvent (AudioUnitParameterEvent& event, FILE* f) +{ + bool isRamp = event.eventType == kParameterEvent_Ramped; + fprintf (f, "\tParamID=%ld,Scope=%ld,Element=%ld\n", (long)event.parameter, (long)event.scope, (long)event.element); + fprintf (f, "\tEvent Type:%s,", (isRamp ? "ramp" : "immediate")); + if (isRamp) + fprintf (f, "start=%ld,dur=%ld,startValue=%f,endValue=%f\n", + (long)event.eventValues.ramp.startBufferOffset, (long)event.eventValues.ramp.durationInFrames, + event.eventValues.ramp.startValue, event.eventValues.ramp.endValue); + else + fprintf (f, "start=%ld,value=%f\n", + (long)event.eventValues.immediate.bufferOffset, + event.eventValues.immediate.value); + fprintf (f, "- - - - - - - - - - - - - - - -\n"); +} +#endif + diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBaseHelper.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBaseHelper.h new file mode 100755 index 00000000..7bb4618e --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBaseHelper.h @@ -0,0 +1,74 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __AUBaseHelper_h__ +#define __AUBaseHelper_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +#include "AUBase.h" + + +UInt32 FindInvalidSamples(Float32 *inSource, UInt32 inFramesToProcess, bool &hasNonZero, bool zapInvalidSamples); + + +// helpers for dealing with the file-references dictionary in an AUPreset + +extern "C" 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 +extern "C" CFMutableDictionaryRef +CreateFileRefDict (CFStringRef fKey, CFStringRef fPath, CFMutableDictionaryRef fileRefDict); + +#if DEBUG + void PrintAUParamEvent (AudioUnitParameterEvent& event, FILE* f); +#endif + + + +#endif // __AUBaseHelper_h__ \ No newline at end of file diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBuffer.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBuffer.cpp new file mode 100755 index 00000000..67259110 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBuffer.cpp @@ -0,0 +1,203 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "AUBuffer.h" +#include + +AUBufferList::~AUBufferList() +{ + Deallocate(); + if (mPtrs) + free(mPtrs); +} + +void AUBufferList::Allocate(const CAStreamBasicDescription &format, UInt32 nFrames) +{ + UInt32 nStreams; + UInt32 channelsPerStream; + if (format.IsInterleaved()) { + nStreams = 1; + channelsPerStream = format.mChannelsPerFrame; + } else { + nStreams = format.mChannelsPerFrame; + channelsPerStream = 1; + } + + // careful -- the I/O thread could be running! + if (nStreams > mAllocatedStreams) { + mPtrs = (AudioBufferList *)CA_realloc(mPtrs, offsetof(AudioBufferList, mBuffers) + nStreams * sizeof(AudioBuffer)); + mAllocatedStreams = nStreams; + } + UInt32 bytesPerStream = (nFrames * format.mBytesPerFrame + 0xF) & ~0xF; + UInt32 nBytes = nStreams * bytesPerStream; + 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/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBuffer.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBuffer.h new file mode 100755 index 00000000..3c5bf082 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUBuffer.h @@ -0,0 +1,261 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUDebugDispatcher.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUDebugDispatcher.cpp new file mode 100755 index 00000000..799ce686 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUDebugDispatcher.cpp @@ -0,0 +1,423 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +/*============================================================================= + * AUDebugDispatcher.h + * CAServices + +=============================================================================*/ + +#if AU_DEBUG_DISPATCHER + +#warning "This should * * NOT * * be seen on a Release Version" + + +#include "AUDebugDispatcher.h" + +static char* AUErrorStr (OSStatus result); + +class AUDD_Locker { +public: + AUDD_Locker (CAMutex &guard) :mGuard (guard) { didLock = mGuard.Lock(); } + ~AUDD_Locker () { if (didLock) mGuard.Unlock(); } + +private: + bool didLock; + CAMutex &mGuard; +}; + +AUDebugDispatcher::AUDebugDispatcher (AUBase *au, FILE* file) + : mAUBase (au), + mFile (file), + mHaveDoneProperty (false), + mPrintMutex ("AU Debug Dispatcher Printer"), + mHostCB1_Result (0), + mHostCB2_Result (0), + mHostCB3_Result (0), + mHostCB_WhenToPrint (0), + mHostCB_WasPlaying (0) +{ + // lets gather some info about this instance... + AudioComponentDescription desc = mAUBase->GetComponentDescription(); + fprintf (mFile, "\nAUBase=0x%X, Type=%4.4s, SubType=%4.4s, Manu=%4.4s\n\n", AU(), + (char*)&desc.componentType, + (char*)&desc.componentSubType, + (char*)&desc.componentManufacturer); + mFirstTime = CAHostTimeBase::GetCurrentTime(); +} + + +AUDebugDispatcher::~AUDebugDispatcher() +{ + PrintHeaderString (CAHostTimeBase::GetCurrentTime(), (unsigned int)pthread_self(), "Close"); + fprintf (mFile, "\n"); +} + +void AUDebugDispatcher::PrintHeaderString (UInt64 inNowTime, unsigned int inThread, const char* inMethod) +{ + double secsSinceStart = SecsSinceStart(inNowTime); + fprintf (mFile, "[AUDisp:AUBase = 0x%X, Time = %.6lf secs, Thread = 0x%X, IsInitialized = '%c'] %s()\n", + AU(), secsSinceStart, inThread, (mAUBase->IsInitialized() ? 'T' : 'F'), inMethod); +} + +unsigned int AUDebugDispatcher::RecordDispatch (UInt64 inStartTime, OSStatus result, const char* inMethod) +{ + UInt64 nowTime = CAHostTimeBase::GetCurrentTime(); + + unsigned int theThread = (unsigned int)pthread_self(); + + PrintHeaderString (nowTime, theThread, inMethod); + + UInt64 nanos = CAHostTimeBase::ConvertToNanos(nowTime - inStartTime); + + fprintf (mFile, "\t[Time To execute = %.6lf secs", (nanos * 1.0e-9)); + + if (result) + fprintf (mFile, ", * * * result = %ld, %s * * * ", result, AUErrorStr(result)); + + fprintf (mFile, "]\n"); + + return theThread; +} + +#pragma mark - +#pragma mark __AU Dispatch +#pragma mark - + +void AUDebugDispatcher::Initialize (UInt64 nowTime, OSStatus result) +{ + AUDD_Locker lock (mPrintMutex); + RecordDispatch (nowTime, result, "Initialize"); +} + +void AUDebugDispatcher::Uninitialize (UInt64 nowTime, OSStatus result) +{ + AUDD_Locker lock (mPrintMutex); + RecordDispatch (nowTime, result, "Uninitialize"); +} + +void AUDebugDispatcher::GetPropertyInfo (UInt64 nowTime, + OSStatus result, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 *outDataSize, + Boolean *outWritable) +{ + AUDD_Locker lock (mPrintMutex); + RecordDispatch (nowTime, result, "GetPropertyInfo"); + PrintProperty (inID, inScope, inElement); +} + +void AUDebugDispatcher::GetProperty (UInt64 nowTime, + OSStatus result, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 *ioDataSize, + void *outData) +{ + //err -> ioDataSize == NULL or 0 + //outData == NULL -> Dispatches to GetPropertyInfo + + // still should log these as calls to GetProperty... + AUDD_Locker lock (mPrintMutex); + const char *dispStr = outData != NULL ? "GetProperty" : "GetProperty - Info"; + RecordDispatch (nowTime, result, dispStr); + PrintProperty (inID, inScope, inElement); +} + +void AUDebugDispatcher::SetProperty (UInt64 nowTime, + OSStatus result, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize) +{ + // inData could be NULL to remove property value... + AUDD_Locker lock (mPrintMutex); + RecordDispatch (nowTime, result, "SetProperty"); + PrintProperty (inID, inScope, inElement); +} + +void AUDebugDispatcher::Render ( UInt64 nowTime, + OSStatus result, + AudioUnitRenderActionFlags * inRenderFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumFrames, + AudioBufferList * inIOData) +{ + if (mHaveDoneProperty) { + AUDD_Locker lock (mPrintMutex); + RecordDispatch (nowTime, result, "Render"); + fprintf (mFile, "\t\t[Sample Time = %.0lf, NumFrames = %ld]\n", inTimeStamp->mSampleTime, inNumFrames); + mHaveDoneProperty = false; + } + RenderActions_HostCallbacks (); +} + +#define kBeginLine " " + +void AUDebugDispatcher::RenderActions_HostCallbacks () +{ + bool doPrint = !(mHostCB_WhenToPrint++ % 5000); + +// (3) Host Transport State callback +// - this is printed below, but we use the transStateChange to see if we have something to print + Boolean isPlaying, transStateChange, isCycling; + Float64 currentSample, cycleStartBeat, cycleEndBeat; + OSStatus result = mAUBase->CallHostTransportState (&isPlaying, &transStateChange, ¤tSample, + &isCycling, &cycleStartBeat, &cycleEndBeat); + bool newCB3Result = false; + if (result != mHostCB3_Result) { + mHostCB3_Result = result; + newCB3Result = true; + } + + if (transStateChange) mHostCB_WhenToPrint = 1; + +// Code to test the Host Callbacks + Float64 currentBeat, currentTempo; + +// (1) Beat and Tempo callback + result = mAUBase->CallHostBeatAndTempo (¤tBeat, ¤tTempo); + + if (result) { + if (result != mHostCB1_Result) { + printf ("_HCback_ Error Calling HostBeatAndTempo:%ld\n", result); + mHostCB1_Result = result; + } + } else { + if (doPrint || currentBeat < 0 || transStateChange) + printf ("_HCback_ Beat and Tempo: Current Beat:%f, Current Tempo:%f\n", currentBeat, currentTempo); + } + +// (2) Musical Time callback + UInt32 deltaSampleOffset, timeSig_Denom; + Float32 timeSig_Num; + Float64 currentMeasureDownBeat; + result = mAUBase->CallHostMusicalTimeLocation (&deltaSampleOffset, &timeSig_Num, &timeSig_Denom, ¤tMeasureDownBeat); + + if (result) { + if (result != mHostCB2_Result) { + printf ("%sError Calling CallHostMusicalTimeLocation:%ld\n", kBeginLine, result); + mHostCB2_Result = result; + } + } else { + if (doPrint || currentMeasureDownBeat < 0 || deltaSampleOffset < 0 || transStateChange) { + printf ("%sMusical Time: Delta Sample Offset:%ld, Time Sig:Num:%.1f, Time Sig:Denom:%ld, DownBeat:%f\n", + kBeginLine, deltaSampleOffset, timeSig_Num, timeSig_Denom, currentMeasureDownBeat); + } + } + + if (mHostCB3_Result) { + if (newCB3Result) { + printf ("%sError Calling CallHostTransportState:%ld\n", kBeginLine, mHostCB3_Result); + } + } else { + if (doPrint || (mHostCB_WasPlaying != isPlaying) || transStateChange || currentSample < 0) + { + printf ("%sTransport State: Was Playing:%d, ", kBeginLine, mHostCB_WasPlaying); + mHostCB_WasPlaying = isPlaying; + printf ("Is Playing:%d, Transport State Changed:%d", isPlaying, transStateChange); + if (isPlaying) { + printf (", Current Sample:%.1f", currentSample); + if (isCycling) + printf (", Is Cycling [Start Beat:%.2f, End Beat:%.2f]", cycleStartBeat, cycleEndBeat); + } + printf ("\n"); + } + } +} + +#pragma mark - +#pragma mark __Utilities +#pragma mark - + +static char* AUScopeStr (AudioUnitScope inScope) +{ + switch (inScope) { + case kAudioUnitScope_Global: return "Global"; + case kAudioUnitScope_Output: return "Output"; + case kAudioUnitScope_Input: return "Input"; + case kAudioUnitScope_Group: return "Group"; + } + return NULL; +} + +static char* AUErrorStr (OSStatus result) +{ + switch (result) { + case kAudioUnitErr_InvalidProperty: return "Invalid Property"; + case kAudioUnitErr_InvalidParameter: return "Invalid Parameter"; + case kAudioUnitErr_InvalidElement: return "Invalid Element"; + case kAudioUnitErr_NoConnection: return "Invalid Connection"; + case kAudioUnitErr_FailedInitialization: return "Failed Initialization"; + case kAudioUnitErr_TooManyFramesToProcess: return "Too Many Frames"; + case kAudioUnitErr_IllegalInstrument: return "Illegal Instrument"; + case kAudioUnitErr_InstrumentTypeNotFound: return "Instrument Type Not Found"; + case kAudioUnitErr_InvalidFile: return "Invalid File"; + case kAudioUnitErr_UnknownFileType: return "Unknown File Type"; + case kAudioUnitErr_FileNotSpecified: return "File Not Specified"; + case kAudioUnitErr_FormatNotSupported: return "Format Not Supported"; + case kAudioUnitErr_Uninitialized: return "Un Initialized"; + case kAudioUnitErr_InvalidScope: return "Invalid Scope"; + case kAudioUnitErr_PropertyNotWritable: return "Property Not Writable"; + case kAudioUnitErr_InvalidPropertyValue: return "Invalid Property Value"; + case kAudioUnitErr_PropertyNotInUse: return "Property Not In Use"; + case kAudioUnitErr_Initialized: return "Initialized"; + + // some common system errors + case badComponentSelector: return "Bad Component Selector"; + case paramErr: return "Parameter Error"; + case badComponentInstance: return "Bad Component Instance"; + } + return "Unknown Error"; +} + +static char* AUPropertyStr (AudioUnitPropertyID inID) +{ + switch (inID) { + case kAudioUnitProperty_ClassInfo: return "Class Info"; + case kAudioUnitProperty_MakeConnection: return "Connection"; + case kAudioUnitProperty_SampleRate: return "Sample Rate"; + case kAudioUnitProperty_ParameterList: return "Parameter List"; + case kAudioUnitProperty_ParameterInfo: return "Parameter Info"; + case kAudioUnitProperty_FastDispatch: return "Fast Dispatch"; + case kAudioUnitProperty_CPULoad: return "CPU Load"; + case kAudioUnitProperty_StreamFormat: return "Format"; + case kAudioUnitProperty_ReverbRoomType: return "Reverb Room Type"; + case kAudioUnitProperty_ElementCount: return "Element Count"; + case kAudioUnitProperty_Latency: return "Latency"; + case kAudioUnitProperty_SupportedNumChannels: return "Supported Num Channels"; + case kAudioUnitProperty_MaximumFramesPerSlice: return "Max Frames Per Slice"; + case kAudioUnitProperty_SetExternalBuffer: return "Set External Buffer"; + case kAudioUnitProperty_ParameterValueStrings: return "Parameter Value Strings"; + case kAudioUnitProperty_GetUIComponentList: return "Carbon UI"; + case kAudioUnitProperty_AudioChannelLayout: return "Audio Channel Layout"; + case kAudioUnitProperty_TailTime: return "Tail Time"; + case kAudioUnitProperty_BypassEffect: return "Bypass Effect"; + case kAudioUnitProperty_LastRenderError: return "Last Render Error"; + case kAudioUnitProperty_SetRenderCallback: return "Render Callback"; + case kAudioUnitProperty_FactoryPresets: return "Factory Preset"; + case kAudioUnitProperty_ContextName: return "Context Name"; + case kAudioUnitProperty_RenderQuality: return "Render Quality"; + case kAudioUnitProperty_HostCallbacks: return "Host Callbacks"; + case kAudioUnitProperty_InPlaceProcessing: return "In Place Processing"; + case kAudioUnitProperty_ElementName: return "Element Name"; + case kAudioUnitProperty_CocoaUI: return "Cocoa UI"; + case kAudioUnitProperty_SupportedChannelLayoutTags: return "Supported Channel Layout Tags"; + case kAudioUnitProperty_ParameterStringFromValue: return "Parameter Value Name"; + case kAudioUnitProperty_UsesInternalReverb: return "Use Internal Reverb"; + case kAudioUnitProperty_ParameterIDName: return "Parameter ID Name"; + case kAudioUnitProperty_ParameterClumpName: return "Clump Name"; + case kAudioUnitProperty_PresentPreset: return "Present Preset"; + + + case kMusicDeviceProperty_InstrumentCount: return "Instrument Count"; + case kMusicDeviceProperty_InstrumentName: return "Instrument Name"; + case kMusicDeviceProperty_SoundBankFSRef: return "Sound Bank - File"; + case kMusicDeviceProperty_InstrumentNumber: return "Instrument Number"; + case kMusicDeviceProperty_MIDIXMLNames: return "MIDI XML Names"; + case kMusicDeviceProperty_BankName: return "Bank Name"; + case kMusicDeviceProperty_SoundBankData: return "Sound Bank - Data"; + + + case kAudioOutputUnitProperty_CurrentDevice: return "Current AudioDevice"; + case kAudioOutputUnitProperty_IsRunning: return "Is Running"; + case kAudioOutputUnitProperty_ChannelMap: return "Channel Map"; + case kAudioOutputUnitProperty_EnableIO: return "Enable I/O"; + case kAudioOutputUnitProperty_StartTime: return "Start Time"; + case kAudioOutputUnitProperty_SetInputCallback: return "I/O Input Callback"; + } + return "Unknown"; +} + + +void AUDebugDispatcher::PrintProperty ( AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement) +{ + char* scopeStr = AUScopeStr(inScope); + char* propStr = AUPropertyStr (inID); + + if (scopeStr != NULL) + fprintf (mFile, "\t\t[ID = %ld, %s, Scope = %s, El = %ld]\n", inID, propStr, scopeStr, inElement); + else + fprintf (mFile, "\t\t[ID = %ld, %s, Scope = %ld, El = %ld]\n", inID, propStr, inScope , inElement); + + bool iscback = false; + bool isInput = false; + switch (inID) + { + case kAudioUnitProperty_SetRenderCallback: + iscback = true; + case kAudioUnitProperty_MakeConnection: + { + AUInputElement *el = mAUBase->GetInput (inElement); + if (el) { + bool hasInput = false; + if (iscback) + hasInput = el->IsCallback(); + else + hasInput = el->HasConnection(); + fprintf (mFile, "\t\tHas Input=%c, ", (hasInput ? 'T' : 'F')); + isInput = true; + } + } + case kAudioUnitProperty_SampleRate: + case kAudioUnitProperty_StreamFormat: + { + CAStreamBasicDescription desc = mAUBase->GetStreamFormat (inScope, inElement); + if (!isInput) + fprintf (mFile, "\t\t"); + desc.Print (mFile); + break; + } + default: + break; + } + + mHaveDoneProperty = true; +} + +#endif //AU_DEBUG_DISPATCHER diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUDebugDispatcher.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUDebugDispatcher.h new file mode 100755 index 00000000..4712e730 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUDebugDispatcher.h @@ -0,0 +1,131 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +/*============================================================================= + * AUDebugDispatcher.h + * CAServices + + =============================================================================*/ + +#ifndef __AUDebugDispatcher_h__ +#define __AUDebugDispatcher_h__ + +#if AU_DEBUG_DISPATCHER + +#include "CAHostTimeBase.h" +#include "CAMutex.h" +#include "AUBase.h" + + +class AUDebugDispatcher { +public: + AUDebugDispatcher (AUBase *au, FILE* file = stdout); + ~AUDebugDispatcher(); + +// these are the AU API calls + void Initialize (UInt64 nowTime, OSStatus result); + + void Uninitialize (UInt64 nowTime, OSStatus result); + + void GetPropertyInfo (UInt64 nowTime, + OSStatus result, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 *outDataSize, + Boolean *outWritable); + + void GetProperty ( UInt64 nowTime, + OSStatus result, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32 *ioDataSize, + void *outData); + + void SetProperty ( UInt64 nowTime, + OSStatus result, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void * inData, + UInt32 inDataSize); + + void Render ( UInt64 nowTime, + OSStatus result, + AudioUnitRenderActionFlags * inRenderFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumFrames, + AudioBufferList * inIOData); + +private: + AUBase* mAUBase; + UInt64 mFirstTime; + FILE* mFile; + bool mHaveDoneProperty; + CAMutex mPrintMutex; + + + OSStatus mHostCB1_Result; + OSStatus mHostCB2_Result; + OSStatus mHostCB3_Result; + int mHostCB_WhenToPrint; + int mHostCB_WasPlaying; + + double SecsSinceStart(UInt64 inNowTime) + { + UInt64 nanos = CAHostTimeBase::ConvertToNanos(inNowTime - mFirstTime); + return nanos * 1.0e-9; + } + + unsigned int RecordDispatch (UInt64 inStartTime, OSStatus result, const char* inMethod); + + void PrintHeaderString (UInt64 inNowTime, unsigned int inThread, const char* inMethod); + + unsigned int AU() const { return (unsigned int)mAUBase->GetComponentInstance(); } + + void PrintProperty (AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement); + + void RenderActions_HostCallbacks (); +}; + +#endif // AU_DEBUG_DISPATCHER +#endif //__AUDebugDispatcher_h__ diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUInputFormatConverter.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUInputFormatConverter.h new file mode 100755 index 00000000..d24801f0 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUInputFormatConverter.h @@ -0,0 +1,149 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUSilentTimeout.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUSilentTimeout.h new file mode 100755 index 00000000..a1334b16 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUSilentTimeout.h @@ -0,0 +1,87 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUTimestampGenerator.cpp b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUTimestampGenerator.cpp new file mode 100755 index 00000000..c3020782 --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUTimestampGenerator.cpp @@ -0,0 +1,185 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "AUTimestampGenerator.h" +#include "CAMath.h" + +#if DEBUG +static double DebugHostTime(const AudioTimeStamp &ts) +{ + static UInt64 baseHostTime = 0; + if (!(ts.mFlags & kAudioTimeStampHostTimeValid)) + return -1.; + if (baseHostTime == 0) + baseHostTime = ts.mHostTime; + return double(SInt64(ts.mHostTime) - SInt64(baseHostTime)) * CAHostTimeBase::GetInverseFrequency(); +} +#endif + +void AUTimestampGenerator::AddOutputTime(const AudioTimeStamp &inTimeStamp, Float64 expectedDeltaFrames, double outputSampleRate, double rateScalarAdj) +{ + mRateScalarAdj = rateScalarAdj; + mLastOutputTime = mCurrentOutputTime; + mCurrentOutputTime = inTimeStamp; + if (mBypassed) + return; + if (mHostTimeDiscontinuityCorrection && !(mCurrentOutputTime.mFlags & kAudioTimeStampHostTimeValid) && (mLastOutputTime.mFlags & kAudioTimeStampHostTimeValid)) { + // no host time here but we had one last time, interpolate one + double rateScalar = (mCurrentOutputTime.mFlags & kAudioTimeStampRateScalarValid) ? mCurrentOutputTime.mRateScalar : 1.0; + Float64 deltaSamples = mCurrentOutputTime.mSampleTime - mLastOutputTime.mSampleTime; + mCurrentOutputTime.mHostTime = mLastOutputTime.mHostTime + + UInt64(CAHostTimeBase::GetFrequency() * deltaSamples * rateScalar / outputSampleRate); + mCurrentOutputTime.mFlags |= kAudioTimeStampHostTimeValid; +#if DEBUG + if (mVerbosity > 1) + printf("synthesized host time: %.3f (%.3f + %.f smp @ %.f Hz, rs %.3f\n", DebugHostTime(mCurrentOutputTime), DebugHostTime(mLastOutputTime), deltaSamples, outputSampleRate, rateScalar); +#endif + } + // copy rate scalar + if (rateScalarAdj != 1.0) { + if (mCurrentOutputTime.mFlags & kAudioTimeStampRateScalarValid) + mCurrentOutputTime.mRateScalar *= rateScalarAdj; + else { + mCurrentOutputTime.mRateScalar = rateScalarAdj; + mCurrentOutputTime.mFlags |= kAudioTimeStampRateScalarValid; + } + } + + if (mFirstTime) { + mFirstTime = false; + mDiscontinuous = false; + mDiscontinuityDeltaSamples = 0.; + if (!mStartInputAtZero) + mNextInputSampleTime = mCurrentOutputTime.mSampleTime; + } else { + mDiscontinuous = fnotequal(mCurrentOutputTime.mSampleTime, mNextOutputSampleTime); + mDiscontinuityDeltaSamples = mCurrentOutputTime.mSampleTime - mNextOutputSampleTime; + // time should never go backwards... + if (mDiscontinuityDeltaSamples < 0.) + mDiscontinuityDeltaSamples = 0.; +#if DEBUG + if (mVerbosity > 1) + if (mDiscontinuous) + printf("%-20.20s: *** DISCONTINUOUS, got "TSGFMT", expected "TSGFMT"\n", mDebugName, (SInt64)mCurrentOutputTime.mSampleTime, (SInt64)mNextOutputSampleTime); +#endif + } + mNextOutputSampleTime = mCurrentOutputTime.mSampleTime + expectedDeltaFrames; +} + +const AudioTimeStamp & AUTimestampGenerator::GenerateInputTime(Float64 framesToAdvance, double inputSampleRate) +{ + if (mBypassed) + return mCurrentOutputTime; + + double inputSampleTime; + + mCurrentInputTime.mFlags = kAudioTimeStampSampleTimeValid; + double rateScalar = 1.0; + + // propagate rate scalar + if (mCurrentOutputTime.mFlags & kAudioTimeStampRateScalarValid) { + mCurrentInputTime.mFlags |= kAudioTimeStampRateScalarValid; + mCurrentInputTime.mRateScalar = rateScalar = mCurrentOutputTime.mRateScalar; + } + + // propagate host time and sample time + if (mCurrentOutputTime.mFlags & kAudioTimeStampHostTimeValid) { + mCurrentInputTime.mFlags |= kAudioTimeStampHostTimeValid; + mCurrentInputTime.mHostTime = mCurrentOutputTime.mHostTime; + if (mHostTimeDiscontinuityCorrection && mDiscontinuous && (mLastOutputTime.mFlags & kAudioTimeStampHostTimeValid)) { + // we had a discontinuous output time, need to resync by interpolating + // a sample time that is appropriate to the host time + UInt64 deltaHostTime = mCurrentOutputTime.mHostTime - mLastOutputTime.mHostTime; + double deltaSeconds = double(deltaHostTime) * CAHostTimeBase::GetInverseFrequency(); + // samples/second * seconds = samples + double deltaSamples = floor(inputSampleRate / rateScalar * deltaSeconds + 0.5); + double lastInputSampleTime = mCurrentInputTime.mSampleTime; + inputSampleTime = lastInputSampleTime + deltaSamples; +#if DEBUG + if (mVerbosity > 1) + printf("%-20.20s: adjusted input time: "TSGFMT" -> "TSGFMT" (SR=%.3f, rs=%.3f)\n", mDebugName, (SInt64)lastInputSampleTime, (SInt64)inputSampleTime, inputSampleRate, rateScalar); +#endif + mDiscontinuous = false; + } else { + inputSampleTime = mNextInputSampleTime; + } + } else { + // we don't know the host time, so we can't do much + inputSampleTime = mNextInputSampleTime; + } + + if (!mHostTimeDiscontinuityCorrection && fnonzero(mDiscontinuityDeltaSamples)) + { + // we had a discontinuous output time, need to resync by propagating the + // detected discontinuity, taking the rate scalar adjustment into account + inputSampleTime += floor(mDiscontinuityDeltaSamples / mRateScalarAdj + 0.5); + +#if DEBUG + if (mVerbosity > 1) + printf("%-20.20s: adjusted input time: %.0f -> %.0f (SR=%.3f, rs=%.3f, delta=%.0f)\n", mDebugName, mNextInputSampleTime, inputSampleTime, inputSampleRate, mRateScalarAdj, mDiscontinuityDeltaSamples); +#endif + + mDiscontinuityDeltaSamples = 0.; + } + + + // propagate word clock + if (mCurrentOutputTime.mFlags & kAudioTimeStampWordClockTimeValid) { + mCurrentInputTime.mFlags |= kAudioTimeStampWordClockTimeValid; + mCurrentInputTime.mWordClockTime = mCurrentOutputTime.mWordClockTime; + } + + // propagate SMPTE time + if (mCurrentOutputTime.mFlags & kAudioTimeStampSMPTETimeValid) { + mCurrentInputTime.mFlags |= kAudioTimeStampSMPTETimeValid; + mCurrentInputTime.mSMPTETime = mCurrentOutputTime.mSMPTETime; + } + + // store the input sample time and expected next input time + mCurrentInputTime.mSampleTime = inputSampleTime; + mNextInputSampleTime = inputSampleTime + framesToAdvance; + +#if DEBUG + if (mVerbosity > 0) { + printf("%-20.20s: out = "TSGFMT" (%10.3fs) in = "TSGFMT" (%10.3fs) delta = "TSGFMT" advance = "TSGFMT"\n", mDebugName, (SInt64)mCurrentOutputTime.mSampleTime, DebugHostTime(mCurrentOutputTime), (SInt64)inputSampleTime, DebugHostTime(mCurrentInputTime), (SInt64)(mCurrentOutputTime.mSampleTime - inputSampleTime), (SInt64)framesToAdvance); + } +#endif + return mCurrentInputTime; +} diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUTimestampGenerator.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUTimestampGenerator.h new file mode 100755 index 00000000..e08bd86a --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/Utility/AUTimestampGenerator.h @@ -0,0 +1,148 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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) : + mStartInputAtZero(true), + mBypassed(false), + mHostTimeDiscontinuityCorrection(hostTimeDiscontinuityCorrection) + { +#if DEBUG + mVerbosity = 0; + sprintf(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) { mStartInputAtZero = b; } + bool GetStartInputAtZero() const { return 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) { mBypassed = b; } + bool GetBypassed() const { return mBypassed; } + + // Call this to reset the timeline. + void Reset() + { + mCurrentInputTime.mSampleTime = 0.; + mNextInputSampleTime = 0.; + mCurrentOutputTime.mSampleTime = 0.; + mNextOutputSampleTime = 0.; + mLastOutputTime.mFlags = 0; + 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); + + // 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)mCurrentInputTime.mSampleTime, (SInt64)framesToAdvance); +#endif + mNextInputSampleTime = mCurrentInputTime.mSampleTime + framesToAdvance; + } + + +private: + AudioTimeStamp mCurrentInputTime; + Float64 mNextInputSampleTime; + Float64 mNextOutputSampleTime; + + AudioTimeStamp mLastOutputTime; + AudioTimeStamp mCurrentOutputTime; + + bool mFirstTime; + 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. + + +#if DEBUG +public: + int mVerbosity; + char mDebugName[64]; +#endif +}; + + +#endif // __AUTimestampGenerator_h__ diff --git a/distrho/src/CoreAudio106/PublicUtility/AUOutputBL.cpp b/distrho/src/CoreAudio106/PublicUtility/AUOutputBL.cpp new file mode 100755 index 00000000..f5ee5a2b --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/AUOutputBL.cpp @@ -0,0 +1,163 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "AUOutputBL.h" +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif +/* +struct AudioBufferList +{ + UInt32 mNumberBuffers; + AudioBuffer mBuffers[1]; +}; +struct AudioBuffer +{ + UInt32 mNumberChannels; // number of interleaved channels in the buffer + UInt32 mDataByteSize; // the size of the buffer pointed to by mData + void* mData; // the pointer to the buffer +}; +*/ + +AUOutputBL::AUOutputBL (const CAStreamBasicDescription &inDesc, UInt32 inDefaultNumFrames) + : mFormat (inDesc), + mBufferMemory(NULL), + mBufferList (NULL), + mNumberBuffers (0), // keep this here, so can ensure integrity of ABL + mBufferSize (0), + mFrames(inDefaultNumFrames) +{ + mNumberBuffers = mFormat.IsInterleaved() ? 1 : mFormat.NumberChannels(); + mBufferList = reinterpret_cast(new Byte[offsetof(AudioBufferList, mBuffers) + (mNumberBuffers * sizeof(AudioBuffer))]); +} + +AUOutputBL::~AUOutputBL() +{ + if (mBufferMemory) + delete[] mBufferMemory; + + if (mBufferList) + delete [] (Byte *)mBufferList; +} + +void AUOutputBL::Prepare (UInt32 inNumFrames, bool inWantNullBufferIfAllocated) +{ + UInt32 channelsPerBuffer = mFormat.IsInterleaved() ? mFormat.NumberChannels() : 1; + + if (mBufferMemory == NULL || inWantNullBufferIfAllocated) + { + mBufferList->mNumberBuffers = mNumberBuffers; + AudioBuffer *buf = &mBufferList->mBuffers[0]; + for (UInt32 i = 0; i < mNumberBuffers; ++i, ++buf) { + buf->mNumberChannels = channelsPerBuffer; + buf->mDataByteSize = mFormat.FramesToBytes (inNumFrames); + buf->mData = NULL; + } + } + else + { + UInt32 nBytes = mFormat.FramesToBytes (inNumFrames); + if ((nBytes * mNumberBuffers) > AllocatedBytes()) + throw OSStatus(kAudioUnitErr_TooManyFramesToProcess); + + mBufferList->mNumberBuffers = mNumberBuffers; + AudioBuffer *buf = &mBufferList->mBuffers[0]; + Byte* p = mBufferMemory; + for (UInt32 i = 0; i < mNumberBuffers; ++i, ++buf) { + buf->mNumberChannels = channelsPerBuffer; + buf->mDataByteSize = nBytes; + buf->mData = p; + p += mBufferSize; + } + } +} + + +void AUOutputBL::Allocate (UInt32 inNumFrames) +{ + if (inNumFrames) + { + UInt32 nBytes = mFormat.FramesToBytes (inNumFrames); + + if (nBytes <= AllocatedBytes()) + return; + + // align successive buffers for Altivec and to take alternating + // cache line hits by spacing them by odd multiples of 16 + if (mNumberBuffers > 1) + nBytes = (nBytes + (0x10 - (nBytes & 0xF))) | 0x10; + + mBufferSize = nBytes; + + UInt32 memorySize = mBufferSize * mNumberBuffers; + Byte *newMemory = new Byte[memorySize]; + memset(newMemory, 0, memorySize); // make buffer "hot" + + Byte *oldMemory = mBufferMemory; + mBufferMemory = newMemory; + delete[] oldMemory; + + mFrames = inNumFrames; + } + else + { + if (mBufferMemory) { + delete [] mBufferMemory; + mBufferMemory = NULL; + } + mBufferSize = 0; + mFrames = 0; + } +} + +#if DEBUG +void AUOutputBL::Print() +{ + printf ("AUOutputBL::Print\n"); + mFormat.Print(); + printf ("Num Buffers:%d, mFrames:%d, allocatedMemory:%c\n", (int)mBufferList->mNumberBuffers, (int)mFrames, (mBufferMemory != NULL ? 'T' : 'F')); + AudioBuffer *buf = &mBufferList->mBuffers[0]; + for (UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i, ++buf) + printf ("\tBuffer:%d, Size:%d, Chans:%d, Buffer:%p\n", (int)i, (int)buf->mDataByteSize, (int)buf->mNumberChannels, buf->mData); +} +#endif + diff --git a/distrho/src/CoreAudio106/PublicUtility/AUOutputBL.h b/distrho/src/CoreAudio106/PublicUtility/AUOutputBL.h new file mode 100755 index 00000000..3e7fe0b9 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/AUOutputBL.h @@ -0,0 +1,112 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __AUOutputBL_h__ +#define __AUOutputBL_h__ + +#include "CAStreamBasicDescription.h" +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) +#else +#endif + +// ____________________________________________________________________________ +// +// AUOutputBL - Simple Buffer List wrapper targetted to use with retrieving AU output +// Works in one of two ways (both adjustable)... Can use it with NULL pointers, or allocate +// memory to receive the data in. + +// Before using this with any call to AudioUnitRender, it needs to be Prepared +// as some calls to AudioUnitRender can reset the ABL + +class AUOutputBL { +public: + + // you CANNOT use one of these - it will crash! +// AUOutputBL (); + + // this is the constructor that you use + // it can't be reset once you've constructed it + AUOutputBL (const CAStreamBasicDescription &inDesc, UInt32 inDefaultNumFrames = 512); + ~AUOutputBL(); + + void Prepare () + { + Prepare (mFrames); + } + + // this version can throw if this is an allocted ABL and inNumFrames is > AllocatedFrames() + // you can set the bool to true if you want a NULL buffer list even if allocated + // inNumFrames must be a valid number (will throw if inNumFrames is 0) + void Prepare (UInt32 inNumFrames, bool inWantNullBufferIfAllocated = false); + + AudioBufferList* ABL() { return mBufferList; } + + // You only need to call this if you want to allocate a buffer list + // if you want an empty buffer list, just call Prepare() + // if you want to dispose previously allocted memory, pass in 0 + // then you either have an empty buffer list, or you can re-allocate + // Memory is kept around if an Allocation request is less than what is currently allocated + void Allocate (UInt32 inNumberFrames); + + UInt32 AllocatedFrames() const { return mFrames; } + + const CAStreamBasicDescription& GetFormat() const { return mFormat; } + +#if DEBUG + void Print(); +#endif + +private: + UInt32 AllocatedBytes () const { return (mBufferSize * mNumberBuffers); } + + CAStreamBasicDescription mFormat; + Byte* mBufferMemory; + AudioBufferList* mBufferList; + UInt32 mNumberBuffers; + UInt32 mBufferSize; + UInt32 mFrames; + +// don't want to copy these.. can if you want, but more code to write! + AUOutputBL () {} + AUOutputBL (const AUOutputBL &c) {} + AUOutputBL& operator= (const AUOutputBL& c) { return *this; } +}; + +#endif // __AUOutputBL_h__ diff --git a/distrho/src/CoreAudio106/PublicUtility/AUParamInfo.cpp b/distrho/src/CoreAudio106/PublicUtility/AUParamInfo.cpp new file mode 100755 index 00000000..4f4466a0 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/AUParamInfo.cpp @@ -0,0 +1,133 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "AUParamInfo.h" +#include "CAXException.h" + +AUParamInfo::AUParamInfo (AudioUnit inAU, + bool inIncludeExpert, + bool inIncludeReadOnly, + AudioUnitScope inScope, + AudioUnitElement inElement) + : mAU (inAU), + mNumParams (0), + mParamListID(NULL), + mScope (inScope), + mElement (inElement) +{ + UInt32 size; + OSStatus result = AudioUnitGetPropertyInfo(mAU, kAudioUnitProperty_ParameterList, inScope, mElement, &size, NULL); + if (size == 0 || result) return; + + int nparams = size / sizeof(AudioUnitPropertyID); + mParamListID = new AudioUnitParameterID[nparams]; + + memset (mParamListID, 0xFF, size); + + AudioUnitParameterID *paramList = new AudioUnitParameterID[nparams]; + + result = AudioUnitGetProperty(mAU, kAudioUnitProperty_ParameterList, mScope, mElement, paramList, &size); + if (result) { + delete [] mParamListID; + delete [] paramList; + mParamListID = NULL; + return; + } + + ParameterMap params; + for (int i = 0; i < nparams; ++i) + { + CAAUParameter auvp (mAU, paramList[i], mScope, mElement); // took out only using global scope in CAAUParameter creation + const AudioUnitParameterInfo ¶mInfo = auvp.ParamInfo(); + + // don't include if parameter can't be read or written + if (!(paramInfo.flags & kAudioUnitParameterFlag_IsWritable) + && !(paramInfo.flags & kAudioUnitParameterFlag_IsReadable)) + continue; + + // only include if expert params wanted + if (!inIncludeExpert && auvp.IsExpert()) + continue; + + // only include if read only params are wanted + if (!(paramInfo.flags & kAudioUnitParameterFlag_IsWritable) + && (paramInfo.flags & kAudioUnitParameterFlag_IsReadable)) + { + if (!inIncludeReadOnly) + continue; + } + + mParamListID[mNumParams] = paramList[i]; + mNumParams++; + + // ok - if we're here, then we have a parameter we are going to display. + UInt32 clump = 0; + auvp.GetClumpID (clump); + mParams[clump].push_back (auvp); + } + + delete [] paramList; +} + +AUParamInfo::~AUParamInfo() +{ + delete [] mParamListID; +} + +UInt32 AUParamInfo::NumParamsForClump (UInt32 inClump) const +{ + ParameterMap::const_iterator it = mParams.find(inClump); + if (it != mParams.end()) + return (*it).second.size(); + return 0; +} + +const CAAUParameter* AUParamInfo::GetParamInfo (AudioUnitParameterID inParamID) const +{ + for (ParameterMap::const_iterator it = mParams.begin(); it != mParams.end(); ++it) { + const ParameterList &list = (*it).second; + for (ParameterList::const_iterator iter = list.begin(); iter != list.end(); ++iter) { + if (inParamID == (*iter).mParameterID) { + return &(*iter); + } + } + } + return NULL; +} diff --git a/distrho/src/CoreAudio106/PublicUtility/AUParamInfo.h b/distrho/src/CoreAudio106/PublicUtility/AUParamInfo.h new file mode 100755 index 00000000..866cae2b --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/AUParamInfo.h @@ -0,0 +1,106 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include +#include +#include +#include "CAAUParameter.h" + +/* + The ParameterMap returned by the Map() method is a map where + - the key is the clumpID + - the value is a ParameterList (vector) + + If you have parameters on multiple scopes (or elements within a scope), then you should create one of these + for each scope-element pair +*/ + +class AUParamInfo { + +public: + typedef std::vector ParameterList; + typedef std::map > ParameterMap; + + + + AUParamInfo (AudioUnit inAU, + bool inIncludeExpert, + bool inIncludeReadOnly, + AudioUnitScope inScope = kAudioUnitScope_Global, + AudioUnitElement inElement = 0); + + ~AUParamInfo(); + + const ParameterMap& Map () const { return mParams; } + + // some convenience methods + UInt32 NumParams () const { return mNumParams; } + + AudioUnitParameterID ParamID (UInt32 inIndex) const + { + if (inIndex < mNumParams) return mParamListID[inIndex]; + return 0xFFFFFFFF; + } + + UInt32 NumClumps () const { return mParams.size(); } + + UInt32 NumParamsForClump (UInt32 inClump) const; + + // returns NULL if there's no info for the parameter + const CAAUParameter* GetParamInfo (AudioUnitParameterID inParamID) const; + + AudioUnitScope GetScope () const { return mScope; } + AudioUnitElement GetElement () const { return mElement; } + +private: + + AudioUnit mAU; + UInt32 mNumParams; + AudioUnitParameterID * mParamListID; + + ParameterMap mParams; + AudioUnitScope mScope; + AudioUnitElement mElement; + + // disallow + AUParamInfo () {} + AUParamInfo (const AUParamInfo &c) {} + AUParamInfo& operator= (const AUParamInfo& c) { return *this; } +}; diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMap.cpp b/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMap.cpp new file mode 100755 index 00000000..b99480e3 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMap.cpp @@ -0,0 +1,194 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CAAUMIDIMap.h" + + +static MIDILinearTransformer linearTrans; +static MIDILogTransformer logTrans; +static MIDIExpTransformer expTrans; +static MIDISqrtTransformer sqrtTrans; +static MIDISquareTransformer squareTrans; +static MIDICubeRtTransformer cubeRtTrans; +static MIDICubeTransformer cubeTrans; + +MIDIValueTransformer * CAAUMIDIMap::GetTransformer (UInt32 inFlags) +{ + if (AudioUnitDisplayTypeIsLogarithmic(inFlags)) + return &logTrans; + else if (AudioUnitDisplayTypeIsExponential(inFlags)) + return &expTrans; + else if (AudioUnitDisplayTypeIsSquareRoot(inFlags)) + return &sqrtTrans; + else if (AudioUnitDisplayTypeIsSquared(inFlags)) + return &squareTrans; + else if (AudioUnitDisplayTypeIsCubed(inFlags)) + return &cubeTrans; + else if (AudioUnitDisplayTypeIsCubeRoot(inFlags)) + return &cubeRtTrans; + else + return &linearTrans; +} + +// The CALLER of this method must ensure that the status byte's MIDI Command matches!!! +bool CAAUMIDIMap::MIDI_Matches (UInt8 inChannel, UInt8 inData1, UInt8 inData2, Float32 &outLinear) const +{ + // see if the channels match first + SInt8 chan = Channel(); + // channel matches (if chan is less than zero, "Any Channel" flag is set) + if (chan >= 0 && chan != inChannel) + return false; + + // match the special cases first + if (IsKeyEvent()) { + // we're using this key event as an on/off type switch + if (IsBipolar()) { + if (IsKeyPressure()){ + if (IsBipolar_OnValue()) { + if (inData2 > 63) { + outLinear = 1; + return true; + } + } else { + if (inData2 < 64) { + outLinear = 0; + return true; + } + } + return false; + } + else { + if (IsBipolar_OnValue()) { + if (inData1 > 63) { + outLinear = 1; + return true; + } + } else { + if (inData1 < 64) { + outLinear = 0; + return true; + } + } + return false; + } + } + if (IsAnyNote()) { +// not quite sure how to interpret this... + if (IsKeyPressure()) + outLinear = inData2 / 127.0; + else + outLinear = inData1 / 127.0; + return true; + } + if (mData1 == inData1) { + if (IsKeyPressure()) + outLinear = inData2 / 127.0; + else + outLinear = 1; + return true; + } + return false; + } + else if (IsControlChange()) { + // controller ID matches + if (mData1 == inData1) { + if (IsBipolar()) { + if (IsBipolar_OnValue()) { + if (inData2 > 63) { + outLinear = 1; + return true; + } + } else { + if (inData2 < 64) { + outLinear = 0; + return true; + } + } + return false; + } + //printf("this in midi matches %X with ", this); + outLinear = inData2 / 127.; + return true; + } + return false; + } + + // this just matches on the patch change value itself... + if (IsPatchChange()) { + if (mData1 == inData1) { + outLinear = 1; + return true; + } + return false; + } + + // finally, for the other two, just check the bi-polar matching conditions + // pitch bend and after touch + if (IsBipolar()) { + if (IsBipolar_OnValue()) { + if (inData1 > 63) { + outLinear = 1; + return true; + } + } else { + if (inData1 < 64) { + outLinear = 0; + return true; + } + } + return false; + } + + if (IsPitchBend()) { + UInt16 value = (inData2 << 7) | inData1; + outLinear = value / 16383.; + } + else if (IsChannelPressure()) { + outLinear = inData1 / 127.0; + } + + return true; +} + + +void CAAUMIDIMap::Print () const +{ + printf ("CAAUMIDIMap:%p, (%u/%u), mParamID %d, IsValid:%c, Status:0x%X, mData1 %d, Flags:0x%X\n", this, (unsigned int)mScope, (unsigned int)mElement, (int)mParameterID, (IsValid() ? 'T' : 'F'), mStatus, mData1, (int)mFlags); +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMap.h b/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMap.h new file mode 100755 index 00000000..d9189ac0 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMap.h @@ -0,0 +1,535 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __CAAUMIDIMap_h_ +#define __CAAUMIDIMap_h_ + +#include +#include + +/* +enum { + kAUParameterMIDIMapping_AnyChannelFlag = (1L << 0), + // If this flag is set and mStatus is a MIDI channel message, then the MIDI channel number + // in the status byte is ignored; the mapping is from the specified MIDI message on ANY channel. + + kAUParameterMIDIMapping_AnyNoteFlag = (1L << 1), + // If this flag is set and mStatus is a Note On, Note Off, or Polyphonic Pressure message, + // the message's note number is ignored; the mapping is from ANY note number. + + kAUParameterMIDIMapping_SubRange = (1L << 2), + // set this flag if the midi control should map only to a sub-range of the parameter's value + // then specify that range in the mSubRangeMin and mSubRangeMax members + + kAUParameterMIDIMapping_Toggle = (1L << 3), + // this is only useful for boolean typed parameters. When set, it means that the parameter's + // value should be toggled (if true, become false and vice versa) when the represented MIDI message + // is received + + kAUParameterMIDIMapping_Bipolar = (1L << 4), + // this can be set to when mapping a MIDI Controller to indicate that the parameter (typically a boolean + // style parameter) will only have its value changed to either the on or off state of a MIDI controller message + // (0 < 64 is off, 64 < 127 is on) such as the sustain pedal. The seeting of the next flag + // (kAUParameterMIDIMapping_Bipolar_On) determine whether the parameter is mapped to the on or off + // state of the controller + kAUParameterMIDIMapping_Bipolar_On = (1L << 5) + // only a valid flag if kAUParameterMIDIMapping_Bipolar is set +}; + +// The reserved fields here are being used to reserve space (as well as align to 64 bit size) for future use +// When/If these fields are used, the names of the fields will be changed to reflect their functionality +// so, apps should NOT refer to these reserved fields directly by name +typedef struct AUParameterMIDIMapping +{ + AudioUnitScope mScope; + AudioUnitElement mElement; + AudioUnitParameterID mParameterID; + UInt32 mFlags; + Float32 mSubRangeMin; + Float32 mSubRangeMax; + UInt8 mStatus; + UInt8 mData1; + UInt8 reserved1; // MUST be set to zero + UInt8 reserved2; // MUST be set to zero + UInt32 reserved3; // MUST be set to zero +} AUParameterMIDIMapping; +*/ + +/* +Parameter To MIDI Mapping Properties +These properties are used to: +Describe a current set of mappings between MIDI messages and Parameter value setting +Create a mapping between a parameter and a MIDI message through either: +- explicitly adding (or removing) the mapping +- telling the AU to hot-map the next MIDI message to a specified Parameter + The same MIDI Message can map to one or more parameters + One Parameter can be mapped from multiple MIDI messages + + In general usage, these properties only apply to AU's that implement the MIDI API + AU Instruments (type=='aumu') and Music Effects (type == 'aumf') + + These properties are used in the Global scope. The scope and element members of the structure describe + the scope and element of the parameter. In all usages, mScope, mElement and mParameterID must be + correctly specified. + + + * The AUParameterMIDIMapping Structure + + Command mStatus mData1 + Note Off 0x8n Note Num + Note On 0x9n Note Num + Key Pressure 0xAn Note Num + Control Change 0xBn ControllerID + Patch Change 0xCn Patch Num + Channel Pressure DxDn 0 (Unused) + Pitch Bend 0xEn 0 (Unused) + + (where n is 0-0xF to correspond to MIDI channels 1-16) + + Details: + + In general MIDI Commands can be mapped to either a specific channel as specified in the mStatus bit. + If the kAUParameterMIDIMapping_AnyChannelFlag bit is set mStatus is a MIDI channel message, then the + MIDI channel number in the status byte is ignored; the mapping is from the specified MIDI message on ANY channel. + + For note commands (note on, note off, key pressure), the MIDI message can trigger either with just a specific + note number, or any note number if the kAUParameterMIDIMapping_AnyNoteFlag bit is set. In these instances, the + note number is used as the trigger value (for instance, a note message could be used to set the + cut off frequency of a filter). + + The Properties: + + kAudioUnitProperty_AllParameterMIDIMappings array of AUParameterMIDIMapping (read/write) + This property is used to both retreive and set the current mapping state between (some/many/all of) its parameters + and MIDI messages. When set, it should replace any previous mapped settings the AU had. + + If this property is implemented by a non-MIDI capable AU (such as an 'aufx' type), then the property is + read only, and recommends a suggested set of mappings for the host to perform. In this case, it is the + host's responsibility to map MIDI message to the AU parameters. As described previously, there are a set + of default mappings (see AudioToolbox/AUMIDIController.h) that the host can recommend to the user + in this circumstance. + + This property's size will be very dynamic, depending on the number of mappings currently in affect, so the + caller should always get the size of the property first before retrieving it. The AU should return an error + if the caller doesn't provide enough space to return all of the current mappings. + + kAudioUnitProperty_AddParameterMIDIMapping array of AUParameterMIDIMapping (write only) + This property is used to Add mappings to the existing set of mappings the AU possesses. It does NOT replace + any existing mappings. + + kAudioUnitProperty_RemoveParameterMIDIMapping array of AUParameterMIDIMapping (write only) + This property is used to remove the specified mappings from the AU. If a mapping is specified that does not + currently exist in the AU, then it should just be ignored. + + kAudioUnitProperty_HotMapParameterMIDIMapping AUParameterMIDIMapping (read/write) + This property is used in two ways, determined by the value supplied by the caller. + (1) If a mapping struct is provided, then that struct provides *all* of the information that the AU should + use to map the parameter, *except* for the MIDI message. The AU should then listen for the next MIDI message + and associate that MIDI message with the supplied AUParameter mapping. When this MIDI message is received and + the mapping made, the AU should also issue a notification on this property + (kAudioUnitProperty_HotMapParameterMIDIMapping) to indicate to the host that the mapping has been made. The host + can then retrieve the mapping that was made by getting the value of this property. + + To avoid possible confusion, it is recommended that once the host has retrieved this mapping (if it is + presenting a UI to describe the mappings for example), that it then clears the mapping state as described next. + + Thus, the only time this property will return a valid value is when the AU has made a mapping. If the AU's mapping + state has been cleared (or it has not been asked to make a mapping), then the AU should return + kAudioUnitErr_InvalidPropertyValue if the host tries to read this value. + + (2) If the value passed in is NULL, then if the AU had a parameter that it was in the process of mapping, it + should disregard that (stop listening to the MIDI messages to create a mapping) and discard the partially + mapped struct. If the value is NULL and the AU is not in the process of mapping, the AU can ignore the request. + + At all times, the _AllMappings property will completely describe the current known state of the AU's mappings + of MIDI messages to parameters. +*/ + + +/* + When mapping, it is recommended that LSB controllers are in general not mapped (ie. the controller range of 32 < 64) + as many host parsers will map 14 bit control values. If you know (or can present an option) that the host deals with + 7 bit controllers only, then these controller ID's can be mapped of course. +*/ + + +struct MIDIValueTransformer { + virtual double tolinear(double) = 0; + virtual double fromlinear(double) = 0; +#if DEBUG + // suppress warning + virtual ~MIDIValueTransformer() { } +#endif +}; + +struct MIDILinearTransformer : public MIDIValueTransformer { + virtual double tolinear(double x) { return x; } + virtual double fromlinear(double x) { return x; } +}; + +struct MIDILogTransformer : public MIDIValueTransformer { + virtual double tolinear(double x) { return log(std::max(x, .00001)); } + virtual double fromlinear(double x) { return exp(x); } +}; + +struct MIDIExpTransformer : public MIDIValueTransformer { + virtual double tolinear(double x) { return exp(x); } + virtual double fromlinear(double x) { return log(std::max(x, .00001)); } +}; + +struct MIDISqrtTransformer : public MIDIValueTransformer { + virtual double tolinear(double x) { return x < 0. ? -(sqrt(-x)) : sqrt(x); } + virtual double fromlinear(double x) { return x < 0. ? -(x * x) : x * x; } +}; + +struct MIDISquareTransformer : public MIDIValueTransformer { + virtual double tolinear(double x) { return x < 0. ? -(x * x) : x * x; } + virtual double fromlinear(double x) { return x < 0. ? -(sqrt(-x)) : sqrt(x); } +}; + +struct MIDICubeRtTransformer : public MIDIValueTransformer { + virtual double tolinear(double x) { return x < 0. ? -(pow(-x, 1./3.)) : pow(x, 1./3.); } + virtual double fromlinear(double x) { return x * x * x; } +}; + +struct MIDICubeTransformer : public MIDIValueTransformer { + virtual double tolinear(double x) { return x * x * x; } + virtual double fromlinear(double x) { return x < 0. ? -(pow(-x, 1./3.)) : pow(x, 1./3.); } +}; + + +class CAAUMIDIMap : public AUParameterMIDIMapping { + +public: +// variables for more efficient parsing of MIDI to Param value + Float32 mMinValue; + Float32 mMaxValue; + MIDIValueTransformer *mTransType; + +// methods + static MIDIValueTransformer *GetTransformer (UInt32 inFlags); + + CAAUMIDIMap() { memset(this, 0, sizeof(CAAUMIDIMap)); } + CAAUMIDIMap (const AUParameterMIDIMapping& inMap) + { + memset(this, 0, sizeof(CAAUMIDIMap)); + memcpy (this, &inMap, sizeof(inMap)); + } + CAAUMIDIMap (AudioUnitScope inScope, AudioUnitElement inElement, AudioUnitParameterID inParam) + { + memset(this, 0, sizeof(CAAUMIDIMap)); + mScope = inScope; + mElement = inElement; + mParameterID = inParam; + } + + + bool IsValid () const { return mStatus != 0; } + + // returns -1 if any channel bit is set + SInt32 Channel () const { return IsAnyChannel() ? -1 : (mStatus & 0xF); } + bool IsAnyChannel () const { + return mFlags & kAUParameterMIDIMapping_AnyChannelFlag; + } + // preserves the existing channel info in the status byte + // preserves any previously set mFlags value + void SetAnyChannel (bool inFlag) + { + if (inFlag) + mFlags |= kAUParameterMIDIMapping_AnyChannelFlag; + else + mFlags &= ~kAUParameterMIDIMapping_AnyChannelFlag; + } + + bool IsAnyNote () const { + return (mFlags & kAUParameterMIDIMapping_AnyNoteFlag) != 0; + } + // preserves the existing key num in the mData1 byte + // preserves any previously set mFlags value + void SetAnyNote (bool inFlag) + { + if (inFlag) + mFlags |= kAUParameterMIDIMapping_AnyNoteFlag; + else + mFlags &= ~kAUParameterMIDIMapping_AnyNoteFlag; + } + + bool IsToggle() const { return (mFlags & kAUParameterMIDIMapping_Toggle) != 0; } + void SetToggle (bool inFlag) + { + if (inFlag) + mFlags |= kAUParameterMIDIMapping_Toggle; + else + mFlags &= ~kAUParameterMIDIMapping_Toggle; + } + + bool IsBipolar() const { return (mFlags & kAUParameterMIDIMapping_Bipolar) != 0; } + // inUseOnValue is valid ONLY if inFlag is true + void SetBipolar (bool inFlag, bool inUseOnValue = false) + { + if (inFlag) { + mFlags |= kAUParameterMIDIMapping_Bipolar; + if (inUseOnValue) + mFlags |= kAUParameterMIDIMapping_Bipolar_On; + else + mFlags &= ~kAUParameterMIDIMapping_Bipolar_On; + } else { + mFlags &= ~kAUParameterMIDIMapping_Bipolar; + mFlags &= ~kAUParameterMIDIMapping_Bipolar_On; + } + } + bool IsBipolar_OnValue () const { return (mFlags & kAUParameterMIDIMapping_Bipolar_On) != 0; } + + bool IsSubRange () const { return (mFlags & kAUParameterMIDIMapping_SubRange) != 0; } + void SetSubRange (Float32 inStartValue, Float32 inStopValue) + { + mFlags |= kAUParameterMIDIMapping_SubRange; + + mSubRangeMin = inStartValue; + mSubRangeMax = inStopValue; + } + + void SetParamRange(Float32 minValue, Float32 maxValue) + { + mMinValue = minValue; + mMaxValue = maxValue; + } + + // this will retain the subrange values previously set. + void SetSubRange (bool inFlag) + { + if (inFlag) + mFlags |= kAUParameterMIDIMapping_SubRange; + else + mFlags &= ~kAUParameterMIDIMapping_SubRange; + } + + bool IsAnyValue() const{return !IsBipolar();} + bool IsOnValue() const{return IsBipolar_OnValue();} + bool IsOffValue() const{return IsBipolar();} + + bool IsNoteOff () const { return ((mStatus & 0xF0) == 0x80); } + bool IsNoteOn () const { return ((mStatus & 0xF0) == 0x90); } + + bool IsKeyPressure () const { return ((mStatus & 0xF0) == 0xA0); } + + bool IsKeyEvent () const { return (mStatus > 0x7F) && (mStatus < 0xB0); } + + bool IsPatchChange () const { return ((mStatus & 0xF0) == 0xC0); } + bool IsChannelPressure () const { return ((mStatus & 0xF0) == 0xD0); } + bool IsPitchBend () const { return ((mStatus & 0xF0) == 0xE0); } + bool IsControlChange () const { return ((mStatus & 0xF0) == 0xB0); } + + + void SetControllerOnValue(){SetBipolar(true,true);} + void SetControllerOffValue(){SetBipolar(true,false);} + void SetControllerAnyValue(){SetBipolar(false,false);} + + // All of these Set calls will reset the mFlags field based on the + // anyChannel param value + void SetNoteOff (UInt8 key, SInt8 channel, bool anyChannel = false) + { + mStatus = 0x80 | (channel & 0xF); + mData1 = key; + mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0); + + } + + void SetNoteOn (UInt8 key, SInt8 channel, bool anyChannel = false) + { + mStatus = 0x90 | (channel & 0xF); + mData1 = key; + mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0); + } + + void SetPolyKey (UInt8 key, SInt8 channel, bool anyChannel = false) + { + mStatus = 0xA0 | (channel & 0xF); + mData1 = key; + mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0); + } + + void SetControlChange (UInt8 controllerID, SInt8 channel, bool anyChannel = false) + { + mStatus = 0xB0 | (channel & 0xF); + mData1 = controllerID; + mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0); + } + + void SetPatchChange (UInt8 patchChange, SInt8 channel, bool anyChannel = false) + { + mStatus = 0xC0 | (channel & 0xF); + mData1 = patchChange; + mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0); + } + + void SetChannelPressure (SInt8 channel, bool anyChannel = false) + { + mStatus = 0xD0 | (channel & 0xF); + mData1 = 0; + mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0); + } + + void SetPitchBend (SInt8 channel, bool anyChannel = false) + { + mStatus = 0xE0 | (channel & 0xF); + mData1 = 0; + mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0); + } + + + Float32 ParamValueFromMIDILinear (Float32 inLinearValue) const + { + Float32 low, high; + if (IsSubRange()){ + low = mSubRangeMin; + high = mSubRangeMax; + } + else { + low = mMinValue; + high = mMaxValue; + } + + + // WE ARE ASSUMING YOU HAVE SET THIS UP PROPERLY!!!!! (or this will crash cause it will be NULL) + return mTransType->fromlinear((inLinearValue * (high - low)) + low); + } + + + // The CALLER of this method must ensure that the status byte's MIDI Command (ignoring the channel) matches!!! + bool MIDI_Matches (UInt8 inChannel, UInt8 inData1, UInt8 inData2, Float32 &outLinear) const; + + void Print () const; + + void Save (CFPropertyListRef &outData) const; + void Restore (CFDictionaryRef inData); + + static void SaveAsMapPList (AudioUnit inUnit, + const AUParameterMIDIMapping * inMappings, + UInt32 inNumMappings, + CFPropertyListRef &outData, + CFStringRef inName = NULL); + + // inNumMappings describes how much memory is allocated in outMappings + static void RestoreFromMapPList (const CFDictionaryRef inData, + AUParameterMIDIMapping * outMappings, + UInt32 inNumMappings); + + static UInt32 NumberOfMaps (const CFDictionaryRef inData); +}; + + + // these sorting operations sort for run-time efficiency based on the MIDI messages +inline bool operator== (const CAAUMIDIMap &a, const CAAUMIDIMap &b) +{ + // ignore channel first + return (((a.mStatus & 0xF0) == (b.mStatus & 0xF0)) + && (a.mData1 == b.mData1) + && ((a.mStatus & 0xF) == (b.mStatus & 0xf)) // now compare the channel + && (a.mParameterID == b.mParameterID) + && (a.mElement == b.mElement) + && (a.mScope == b.mScope)); + + // reserved field comparisons - ignored until/if they are used +} + +inline bool operator< (const CAAUMIDIMap &a, const CAAUMIDIMap &b) +{ + if ((a.mStatus & 0xF0) != (b.mStatus & 0xF0)) + return ((a.mStatus & 0xF0) < (b.mStatus & 0xF0)); + + if (a.mData1 != b.mData1) + return (a.mData1 < b.mData1); + + if ((a.mStatus & 0xF) != (b.mStatus & 0xf)) // now compare the channel + return ((a.mStatus & 0xF) < (b.mStatus & 0xf)); + +// reserved field comparisons - ignored until/if they are used + +// we're sorting this by MIDI, so we don't really care how the rest is sorted + return ((a.mParameterID < b.mParameterID) + && (a.mElement < b.mElement) + && (a.mScope < b.mScope)); +} + + + +class CompareMIDIMap { + int compare (const CAAUMIDIMap &a, const CAAUMIDIMap &b) + { + if ((a.mStatus & 0xF0) < (b.mStatus & 0xF0)) + return -1; + if ((a.mStatus & 0xF0) > (b.mStatus & 0xF0)) + return 1; + + // note event + if (a.mStatus < 0xB0 || a.mStatus >= 0xD0) + return 0; + if (a.mData1 > b.mData1) return 1; + if (a.mData1 < b.mData1) return -1; + return 0; + } + +public: + bool operator() (const CAAUMIDIMap &a, const CAAUMIDIMap &b) { + return compare (a, b) < 0; + } + bool Finish (const CAAUMIDIMap &a, const CAAUMIDIMap &b) { + return compare (a, b) != 0; + } +}; + + +/* + usage: To find potential mapped events for a given status byte, where mMMapEvents is a sorted vec + CompareMIDIMap comparObj; + sortVecIter lower_iter = std::lower_bound(mMMapEvents.begin(), mMMapEvents.end(), inStatusByte, compareObj); + for (;lower_iter < mMMapEvents.end(); ++lower_iter) { + // then, see if we go out of the status byte range, using the Finish method + if (compareObj.Finish(map, tempMap)) // tempMap is a CAAUMIDIMap object with the status/dataByte 1 set + break; + // ... + } + + in the for loop you call the MIDI_Matches call, to see if the MIDI event matches a given AUMIDIParam mapping + special note: you HAVE to transform note on (with vel zero) events to the note off status byte +*/ + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMapManager.cpp b/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMapManager.cpp new file mode 100755 index 00000000..95ce3c43 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMapManager.cpp @@ -0,0 +1,227 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CAAUMIDIMapManager.h" +#include + +CAAUMIDIMapManager::CAAUMIDIMapManager() +{ + hotMapping = false; +} + +static void FillInMap (CAAUMIDIMap &map, AUBase &That) +{ + AudioUnitParameterInfo info; + That.GetParameterInfo (map.mScope, map.mParameterID, info); + + if (map.IsSubRange()) { + map.mMinValue = map.mSubRangeMin; + map.mMaxValue = map.mSubRangeMax; + } else { + map.mMinValue = info.minValue; + map.mMaxValue = info.maxValue; + } + + map.mTransType = CAAUMIDIMap::GetTransformer(info.flags); +} + +OSStatus CAAUMIDIMapManager::SortedInsertToParamaterMaps (AUParameterMIDIMapping *maps, UInt32 inNumMaps, AUBase &That) +{ + for (unsigned int i = 0; i < inNumMaps; ++i) + { + CAAUMIDIMap map(maps[i]); + + FillInMap (map, That); + + int idx = FindParameterIndex (maps[i]); + if (idx > -1) + mParameterMaps.erase(mParameterMaps.begin() + idx); + + // least disruptive place to put this is at the end + mParameterMaps.push_back(map); + } + + std::sort(mParameterMaps.begin(), mParameterMaps.end(), CompareMIDIMap()); + + return noErr; +} + +void CAAUMIDIMapManager::GetHotParameterMap(AUParameterMIDIMapping &outMap ) +{ + outMap = mHotMap; +} + +void CAAUMIDIMapManager::SortedRemoveFromParameterMaps(AUParameterMIDIMapping *maps, UInt32 inNumMaps, bool &outMapDidChange) +{ + if (hotMapping) { + hotMapping = false; + } + + outMapDidChange = false; + for (unsigned int i = 0; i < inNumMaps; ++i) { + int idx = FindParameterIndex (maps[i]); + if (idx > -1) { + //mParameterMaps[idx].Print(); + mParameterMaps.erase(mParameterMaps.begin() + idx); + outMapDidChange = true; + } + } +} + +void CAAUMIDIMapManager::ReplaceAllMaps (AUParameterMIDIMapping* inMappings, UInt32 inNumMaps, AUBase &That) +{ + mParameterMaps.clear(); + + for (unsigned int i = 0; i < inNumMaps; ++i) { + CAAUMIDIMap mapping(inMappings[i]); + + FillInMap (mapping, That); + mParameterMaps.push_back (mapping); + } + + std::sort(mParameterMaps.begin(),mParameterMaps.end(), CompareMIDIMap()); +} + +bool CAAUMIDIMapManager::HandleHotMapping(UInt8 inStatus, + UInt8 inChannel, + UInt8 inData1, + AUBase &That) +{ //used to set the hot map info + + if (inStatus == 0xf0) return false; + + if (!hotMapping) return false; + hotMapping = false; + + mHotMap.mStatus = inStatus | inChannel; + mHotMap.mData1 = inData1; + + SortedInsertToParamaterMaps (&mHotMap, 1, That); + return true; +} + +#if DEBUG + +void CAAUMIDIMapManager::Print() +{ + for ( ParameterMaps::iterator i = mParameterMaps.begin(); i < mParameterMaps.end(); ++i) { + CAAUMIDIMap* listmap = &(*i); + listmap->Print(); + } +} + +#endif // DEBUG + +void CAAUMIDIMapManager::GetMaps(AUParameterMIDIMapping* maps) +{ + int i = 0; + for ( ParameterMaps::iterator iter = mParameterMaps.begin(); iter < mParameterMaps.end(); ++iter, ++i) { + AUParameterMIDIMapping &listmap = (*iter); + maps[i] = listmap; + } +} + +int CAAUMIDIMapManager::FindParameterIndex (AUParameterMIDIMapping &inMap) +{ + //used to get back hot mapping and one at a time maps, for ui + + int idx = 0; + for ( ParameterMaps::iterator i = mParameterMaps.begin(); i < mParameterMaps.end(); ++i) { + CAAUMIDIMap & listmap = (*i); + if ( (listmap.mParameterID == inMap.mParameterID) && + (listmap.mScope == inMap.mScope) && + (listmap.mElement == inMap.mElement) ) + { + return idx; + } + idx++; + } + return -1; +} + +bool CAAUMIDIMapManager::FindParameterMapEventMatch( UInt8 inStatus, + UInt8 inChannel, + UInt8 inData1, + UInt8 inData2, + UInt32 inBufferOffset, + AUBase& inAUBase) +{ + bool ret_value = false; + + if (inStatus == 0x90 && !inData2) + inStatus = 0x80 | inChannel; + + //used to test for midi matches once map is made + CAAUMIDIMap tempMap; + tempMap.mStatus = inStatus | inChannel; + tempMap.mData1 = inData1; + + CompareMIDIMap compareObj; + + AudioUnitEvent event; + event.mEventType = kAudioUnitEvent_ParameterValueChange; + event.mArgument.mParameter.mAudioUnit = inAUBase.GetComponentInstance(); + + ParameterMaps::iterator lower_iter = + std::lower_bound(mParameterMaps.begin(), mParameterMaps.end(), tempMap, compareObj); + + while (lower_iter < mParameterMaps.end()) + { + CAAUMIDIMap & map = (*lower_iter); + if (compareObj.Finish(map, tempMap)) + break; + + Float32 value; + if (map.MIDI_Matches(inChannel, inData1, inData2, value)) + { + inAUBase.SetParameter ( map.mParameterID, map.mScope, map.mElement, + map.ParamValueFromMIDILinear(value), inBufferOffset); + + event.mArgument.mParameter.mParameterID = map.mParameterID; + event.mArgument.mParameter.mScope = map.mScope; + event.mArgument.mParameter.mElement = map.mElement; + + AUEventListenerNotify(NULL, NULL, &event); + ret_value = true; + } + ++lower_iter; + } + return ret_value; +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMapManager.h b/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMapManager.h new file mode 100755 index 00000000..c54b0d1f --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAUMIDIMapManager.h @@ -0,0 +1,96 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __CAAUMIDIMapManager_h_ +#define __CAAUMIDIMapManager_h_ + +#include +#include +#include +#include + +class CAAUMIDIMapManager { + +protected: + + typedef std::vector ParameterMaps; + ParameterMaps mParameterMaps; + + bool hotMapping; + AUParameterMIDIMapping mHotMap; + +public: + + CAAUMIDIMapManager(); + + UInt32 NumMaps(){return mParameterMaps.size();} + void GetMaps(AUParameterMIDIMapping* maps); + + int FindParameterIndex(AUParameterMIDIMapping &map); + + void GetHotParameterMap(AUParameterMIDIMapping &outMap); + + void SortedRemoveFromParameterMaps (AUParameterMIDIMapping *maps, UInt32 inNumMaps, bool &outMapDidChange); + OSStatus SortedInsertToParamaterMaps (AUParameterMIDIMapping *maps, UInt32 inNumMaps, AUBase &That); + + void ReplaceAllMaps (AUParameterMIDIMapping* inMappings, UInt32 inNumMaps, AUBase &That); + + bool IsHotMapping(){return hotMapping;} + void SetHotMapping (AUParameterMIDIMapping &inMap){hotMapping = true; mHotMap = inMap; } + + bool HandleHotMapping( UInt8 inStatus, + UInt8 inChannel, + UInt8 inData1, + AUBase &That); + + + bool FindParameterMapEventMatch(UInt8 inStatus, + UInt8 inChannel, + UInt8 inData1, + UInt8 inData2, + UInt32 inBufferOffset, + AUBase& inAUBase); +#if DEBUG + void Print(); +#endif +}; + + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAUParameter.cpp b/distrho/src/CoreAudio106/PublicUtility/CAAUParameter.cpp new file mode 100755 index 00000000..7d3bf8a3 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAUParameter.cpp @@ -0,0 +1,394 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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, + mParameterID, + &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, + mParameterID, + &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 = 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/distrho/src/CoreAudio106/PublicUtility/CAAUParameter.h b/distrho/src/CoreAudio106/PublicUtility/CAAUParameter.h new file mode 100755 index 00000000..508dadd3 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAUParameter.h @@ -0,0 +1,185 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/PublicUtility/CAAtomic.h b/distrho/src/CoreAudio106/PublicUtility/CAAtomic.h new file mode 100755 index 00000000..8a3a7ed4 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAtomic.h @@ -0,0 +1,288 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +/* + 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 +#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 + +/* 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/distrho/src/CoreAudio106/PublicUtility/CAAtomicStack.h b/distrho/src/CoreAudio106/PublicUtility/CAAtomicStack.h new file mode 100755 index 00000000..84ddae70 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAtomicStack.h @@ -0,0 +1,209 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __TStack_h__ +#define __TStack_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else +// #include +#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 set_next() and get_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->set_next(mHead); + mHead = item; + } + + T * pop_NA() + { + T *result = mHead; + if (result) + mHead = result->get_next(); + return result; + } + + bool empty() { return mHead == NULL; } + + T * head() { return mHead; } + + // atomic routines + void push_atomic(T *item) + { + T *head; + do { + head = mHead; + item->set_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->get_next(); + } while (p); + do { + head = mHead; + tail->set_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->get_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->get_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->get_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; +}; + +// syntactic sugar +template +class TAtomicStack2 : public CAAtomicStack { +public: + TAtomicStack2(size_t nextPtrOffset) : CAAtomicStack(nextPtrOffset) { } + + T * pop_atomic() { return (T *)CAAtomicStack::pop_atomic(); } + T * pop_atomic_single_reader() { return pop_atomic(); } + T * pop_NA() { return pop_atomic(); } +}; + +#endif // MAC_OS_X_VERSION_MAX_ALLOWED && !TARGET_OS_WIN32 + +#endif // __TStack_h__ diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioBufferList.cpp b/distrho/src/CoreAudio106/PublicUtility/CAAudioBufferList.cpp new file mode 100755 index 00000000..08e3e37a --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioBufferList.cpp @@ -0,0 +1,225 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CAAudioBufferList.h" +#include "CADebugMacros.h" +#include "CALogMacros.h" +#include +#include + +//============================================================================= +// CAAudioBufferList +//============================================================================= + +AudioBufferList* CAAudioBufferList::Create(UInt32 inNumberBuffers) +{ + UInt32 theSize = CalculateByteSize(inNumberBuffers); + AudioBufferList* theAnswer = static_cast(calloc(1, theSize)); + if(theAnswer != NULL) + { + theAnswer->mNumberBuffers = inNumberBuffers; + } + return theAnswer; +} + +void CAAudioBufferList::Destroy(AudioBufferList* inBufferList) +{ + free(inBufferList); +} + +UInt32 CAAudioBufferList::CalculateByteSize(UInt32 inNumberBuffers) +{ + UInt32 theSize = SizeOf32(AudioBufferList) - SizeOf32(AudioBuffer); + theSize += inNumberBuffers * SizeOf32(AudioBuffer); + return theSize; +} + +UInt32 CAAudioBufferList::GetTotalNumberChannels(const AudioBufferList& inBufferList) +{ + UInt32 theAnswer = 0; + + for(UInt32 theIndex = 0; theIndex < inBufferList.mNumberBuffers; ++theIndex) + { + theAnswer += inBufferList.mBuffers[theIndex].mNumberChannels; + } + + return theAnswer; +} + +bool CAAudioBufferList::GetBufferForChannel(const AudioBufferList& inBufferList, UInt32 inChannel, UInt32& outBufferNumber, UInt32& outBufferChannel) +{ + bool theAnswer = false; + UInt32 theIndex = 0; + + while((theIndex < inBufferList.mNumberBuffers) && (inChannel >= inBufferList.mBuffers[theIndex].mNumberChannels)) + { + inChannel -= inBufferList.mBuffers[theIndex].mNumberChannels; + ++theIndex; + } + + if(theIndex < inBufferList.mNumberBuffers) + { + outBufferNumber = theIndex; + outBufferChannel = inChannel; + theAnswer = true; + } + + return theAnswer; +} + +void CAAudioBufferList::Clear(AudioBufferList& outBufferList) +{ + // assumes that "0" is actually the 0 value for this stream format + for(UInt32 theBufferIndex = 0; theBufferIndex < outBufferList.mNumberBuffers; ++theBufferIndex) + { + if(outBufferList.mBuffers[theBufferIndex].mData != NULL) + { + memset(outBufferList.mBuffers[theBufferIndex].mData, 0, outBufferList.mBuffers[theBufferIndex].mDataByteSize); + } + } +} + +void CAAudioBufferList::Copy(const AudioBufferList& inSource, UInt32 inStartingSourceChannel, AudioBufferList& outDestination, UInt32 inStartingDestinationChannel) +{ + // This is a brute force copy method that can handle ABL's that have different buffer layouts + // This means that this method is probably not the fastest way to do this for all cases. + // This method also assumes that both the source and destination sample formats are Float32 + + UInt32 theInputChannel = inStartingSourceChannel; + UInt32 theNumberInputChannels = GetTotalNumberChannels(inSource); + UInt32 theOutputChannel = inStartingDestinationChannel; + UInt32 theNumberOutputChannels = GetTotalNumberChannels(outDestination); + + UInt32 theInputBufferIndex = 0; + UInt32 theInputBufferChannel = 0; + UInt32 theOutputBufferIndex = 0; + UInt32 theOutputBufferChannel = 0; + while((theInputChannel < theNumberInputChannels) && (theOutputChannel < theNumberOutputChannels)) + { + GetBufferForChannel(inSource, theInputChannel, theInputBufferIndex, theInputBufferChannel); + + GetBufferForChannel(inSource, theOutputChannel, theOutputBufferIndex, theOutputBufferChannel); + + CopyChannel(inSource.mBuffers[theInputBufferIndex], theInputBufferChannel, outDestination.mBuffers[theOutputBufferIndex], theOutputBufferChannel); + + ++theInputChannel; + ++theOutputChannel; + } +} + +void CAAudioBufferList::CopyChannel(const AudioBuffer& inSource, UInt32 inSourceChannel, AudioBuffer& outDestination, UInt32 inDestinationChannel) +{ + // set up the stuff for the loop + UInt32 theNumberFramesToCopy = outDestination.mDataByteSize / (outDestination.mNumberChannels * SizeOf32(Float32)); + const Float32* theSource = static_cast(inSource.mData); + Float32* theDestination = static_cast(outDestination.mData); + + // loop through the data and copy the samples + while(theNumberFramesToCopy > 0) + { + // copy the data + theDestination[inDestinationChannel] = theSource[inSourceChannel]; + + // adjust the pointers + --theNumberFramesToCopy; + theSource += inSource.mNumberChannels; + theDestination += outDestination.mNumberChannels; + } +} + +void CAAudioBufferList::Sum(const AudioBufferList& inSourceBufferList, AudioBufferList& ioSummedBufferList) +{ + // assumes that the buffers are Float32 samples and the listst have the same layout + // this is a lame algorithm, by the way. it could at least be unrolled a couple of times + for(UInt32 theBufferIndex = 0; theBufferIndex < ioSummedBufferList.mNumberBuffers; ++theBufferIndex) + { + Float32* theSourceBuffer = static_cast(inSourceBufferList.mBuffers[theBufferIndex].mData); + Float32* theSummedBuffer = static_cast(ioSummedBufferList.mBuffers[theBufferIndex].mData); + UInt32 theNumberSamplesToMix = ioSummedBufferList.mBuffers[theBufferIndex].mDataByteSize / SizeOf32(Float32); + if((theSourceBuffer != NULL) && (theSummedBuffer != NULL) && (theNumberSamplesToMix > 0)) + { + while(theNumberSamplesToMix > 0) + { + *theSummedBuffer += *theSourceBuffer; + ++theSummedBuffer; + ++theSourceBuffer; + --theNumberSamplesToMix; + } + } + } +} + +bool CAAudioBufferList::HasData(AudioBufferList& inBufferList) +{ + bool hasData = false; + for(UInt32 theBufferIndex = 0; !hasData && (theBufferIndex < inBufferList.mNumberBuffers); ++theBufferIndex) + { + if(inBufferList.mBuffers[theBufferIndex].mData != NULL) + { + UInt32* theBuffer = (UInt32*)inBufferList.mBuffers[theBufferIndex].mData; + UInt32 theNumberSamples = inBufferList.mBuffers[theBufferIndex].mDataByteSize / SizeOf32(UInt32); + for(UInt32 theSampleIndex = 0; !hasData && (theSampleIndex < theNumberSamples); ++theSampleIndex) + { + hasData = theBuffer[theSampleIndex] != 0; + } + } + } + return hasData; +} + +#if CoreAudio_Debug +void CAAudioBufferList::PrintToLog(const AudioBufferList& inBufferList) +{ + PrintInt(" Number streams: ", inBufferList.mNumberBuffers); + + for(UInt32 theIndex = 0; theIndex < inBufferList.mNumberBuffers; ++theIndex) + { + PrintIndexedInt(" Channels in stream", theIndex + 1, inBufferList.mBuffers[theIndex].mNumberChannels); + PrintIndexedInt(" Buffer size of stream", theIndex + 1, inBufferList.mBuffers[theIndex].mDataByteSize); + } +} +#endif + +AudioBufferList CAAudioBufferList::sEmptyBufferList = { 0, { { 0, 0, NULL } } }; + diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioBufferList.h b/distrho/src/CoreAudio106/PublicUtility/CAAudioBufferList.h new file mode 100755 index 00000000..db688702 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioBufferList.h @@ -0,0 +1,93 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CAAudioBufferList_h__) +#define __CAAudioBufferList_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +//============================================================================= +// Types +//============================================================================= + +typedef AudioBufferList* AudioBufferListPtr; + +//============================================================================= +// CAAudioBufferList +//============================================================================= + +struct CAAudioBufferList +{ + +// Construction/Destruction +public: + static AudioBufferList* Create(UInt32 inNumberBuffers); + static void Destroy(AudioBufferList* inBufferList); + static UInt32 CalculateByteSize(UInt32 inNumberBuffers); + +// Operations +public: + static UInt32 GetTotalNumberChannels(const AudioBufferList& inBufferList); + static bool GetBufferForChannel(const AudioBufferList& inBufferList, UInt32 inChannel, UInt32& outBufferNumber, UInt32& outBufferChannel); + static void Clear(AudioBufferList& outBufferList); + static void Copy(const AudioBufferList& inSource, UInt32 inStartingSourceChannel, AudioBufferList& outDestination, UInt32 inStartingDestinationChannel); + static void CopyChannel(const AudioBuffer& inSource, UInt32 inSourceChannel, AudioBuffer& outDestination, UInt32 inDestinationChannel); + static void Sum(const AudioBufferList& inSourceBufferList, AudioBufferList& ioSummedBufferList); + static bool HasData(AudioBufferList& inBufferList); +#if CoreAudio_Debug + static void PrintToLog(const AudioBufferList& inBufferList); +#endif + +// Constants +public: + static AudioBufferList sEmptyBufferList; + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayout.cpp b/distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayout.cpp new file mode 100755 index 00000000..db401d17 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayout.cpp @@ -0,0 +1,142 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// 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); +} + +// 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/distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayout.h b/distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayout.h new file mode 100755 index 00000000..bfca6c30 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayout.h @@ -0,0 +1,191 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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); + +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 OffsetOf32(AudioChannelLayout, mChannelDescriptions) + 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; + + 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(size); + } + + static RefCountedLayout *CreateWithLayout(const AudioChannelLayout *layout) { + size_t size = CAAudioChannelLayout::CalculateByteSize(layout->mNumberChannelDescriptions); + RefCountedLayout *acl = new(size) RefCountedLayout(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/distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayoutObject.cpp b/distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayoutObject.cpp new file mode 100755 index 00000000..a5ca17ce --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioChannelLayoutObject.cpp @@ -0,0 +1,193 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CAAudioChannelLayout.h" +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +CAAudioChannelLayout::CAAudioChannelLayout () +{ + mLayout = RefCountedLayout::CreateWithNumberChannelDescriptions(0); +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround) +{ + // this chooses default layouts based on the number of channels... + AudioChannelLayoutTag tag; + + switch (inNumberChannels) + { + default: + // here we have a "broken" layout, in the sense that we haven't any idea how to lay this out + mLayout = RefCountedLayout::CreateWithNumberChannelDescriptions(inNumberChannels); + SetAllToUnknown(*mLayout->GetLayout(), inNumberChannels); + return; // don't fall into the tag case + case 1: + tag = kAudioChannelLayoutTag_Mono; + break; + case 2: + tag = inChooseSurround ? kAudioChannelLayoutTag_Binaural : kAudioChannelLayoutTag_Stereo; + break; + case 4: + tag = inChooseSurround ? kAudioChannelLayoutTag_Ambisonic_B_Format : kAudioChannelLayoutTag_AudioUnit_4; + break; + case 5: + tag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_5_0 : kAudioChannelLayoutTag_AudioUnit_5; + break; + case 6: + tag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_6_0 : kAudioChannelLayoutTag_AudioUnit_6; + break; + case 7: + tag = kAudioChannelLayoutTag_AudioUnit_7_0; + break; + case 8: + tag = kAudioChannelLayoutTag_AudioUnit_8; + break; + } + + mLayout = RefCountedLayout::CreateWithLayoutTag(tag); +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (AudioChannelLayoutTag inLayoutTag) + : mLayout(NULL) +{ + SetWithTag(inLayoutTag); +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (const CAAudioChannelLayout &c) + : mLayout(NULL) +{ + *this = c; +} + + +//============================================================================= +// CAAudioChannelLayout::AudioChannelLayout +//============================================================================= +CAAudioChannelLayout::CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout) + : mLayout(NULL) +{ + *this = inChannelLayout; +} + +//============================================================================= +// CAAudioChannelLayout::~CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout::~CAAudioChannelLayout () +{ + if (mLayout) { + mLayout->release(); + mLayout = NULL; + } +} + +//============================================================================= +// CAAudioChannelLayout::CAAudioChannelLayout +//============================================================================= +CAAudioChannelLayout& CAAudioChannelLayout::operator= (const CAAudioChannelLayout &c) +{ + if (mLayout != c.mLayout) { + if (mLayout) + mLayout->release(); + + if ((mLayout = c.mLayout) != NULL) + mLayout->retain(); + } + + return *this; +} + +CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout) +{ + if (mLayout && &mLayout->Layout() == inChannelLayout) + return *this; + + if (mLayout) + mLayout->release(); + + if (inChannelLayout == NULL) + { + mLayout = RefCountedLayout::CreateWithNumberChannelDescriptions(0); + } + else + { + mLayout = RefCountedLayout::CreateWithLayout(inChannelLayout); + } + return *this; +} + +void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag) +{ + if (mLayout) + mLayout->release(); + + mLayout = RefCountedLayout::CreateWithLayoutTag(inTag); +} + +//============================================================================= +// CAAudioChannelLayout::operator== +//============================================================================= +bool CAAudioChannelLayout::operator== (const CAAudioChannelLayout &c) const +{ + if (mLayout == c.mLayout) + return true; + return Layout() == c.Layout(); +} + +//============================================================================= +// CAAudioChannelLayout::Print +//============================================================================= +void CAAudioChannelLayout::Print (FILE* file) const +{ + CAShowAudioChannelLayout (file, &Layout()); +} + diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioFileFormats.cpp b/distrho/src/CoreAudio106/PublicUtility/CAAudioFileFormats.cpp new file mode 100755 index 00000000..67f716d3 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioFileFormats.cpp @@ -0,0 +1,415 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CAAudioFileFormats.h" +#include +#include + +CAAudioFileFormats *CAAudioFileFormats::sInstance = NULL; + +CAAudioFileFormats *CAAudioFileFormats::Instance(bool loadDataFormats) +{ + if (sInstance == NULL) + sInstance = new CAAudioFileFormats(loadDataFormats); + return sInstance; +} + +/* +class CompareFileFormatNames { +public: + bool operator() (const CAAudioFileFormats::FileFormatInfo &a, const CAAudioFileFormats::FileFormatInfo &b) + { + return CFStringCompare(a.mFileTypeName, b.mFileTypeName, + kCFCompareCaseInsensitive | kCFCompareLocalized) == kCFCompareLessThan; + } +};*/ + +static int CompareFileFormatNames(const void *va, const void *vb) +{ + CAAudioFileFormats::FileFormatInfo *a = (CAAudioFileFormats::FileFormatInfo *)va, + *b = (CAAudioFileFormats::FileFormatInfo *)vb; + return CFStringCompare(a->mFileTypeName, b->mFileTypeName, + kCFCompareCaseInsensitive | kCFCompareLocalized); +} + +CAAudioFileFormats::CAAudioFileFormats(bool loadDataFormats) : + mNumFileFormats(0), mFileFormats(NULL) +{ + OSStatus err; + UInt32 size; + UInt32 *fileTypes = NULL; + + // get all file types + err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_WritableTypes, 0, NULL, &size); + if (err != noErr) goto bail; + mNumFileFormats = size / sizeof(UInt32); + mFileFormats = new FileFormatInfo[mNumFileFormats]; + fileTypes = new UInt32[mNumFileFormats]; + err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_WritableTypes, 0, NULL, &size, fileTypes); + if (err != noErr) goto bail; + + // get info for each file type + for (int i = 0; i < mNumFileFormats; ++i) { + FileFormatInfo *ffi = &mFileFormats[i]; + OSType filetype = fileTypes[i]; + + ffi->mFileTypeID = filetype; + + // file type name + ffi->mFileTypeName = NULL; + size = sizeof(CFStringRef); + err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_FileTypeName, sizeof(UInt32), &filetype, &size, &ffi->mFileTypeName); + if (ffi->mFileTypeName) + CFRetain(ffi->mFileTypeName); + + // file extensions + size = sizeof(CFArrayRef); + err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_ExtensionsForType, + sizeof(OSType), &filetype, &size, &ffi->mExtensions); + if (err) + ffi->mExtensions = NULL; + + // file data formats + ffi->mNumDataFormats = 0; + ffi->mDataFormats = NULL; + + if (loadDataFormats) + ffi->LoadDataFormats(); + } + + // sort file formats by name + qsort(mFileFormats, mNumFileFormats, sizeof(FileFormatInfo), CompareFileFormatNames); +bail: + delete[] fileTypes; +} + +void CAAudioFileFormats::FileFormatInfo::LoadDataFormats() +{ + if (mDataFormats != NULL) return; + + UInt32 *writableFormats = NULL, *readableFormats = NULL; + int nWritableFormats, nReadableFormats; + // get all writable formats + UInt32 size; + OSStatus err = AudioFormatGetPropertyInfo(kAudioFormatProperty_EncodeFormatIDs, 0, NULL, &size); + if (err != noErr) goto bail; + nWritableFormats = size / sizeof(UInt32); + writableFormats = new UInt32[nWritableFormats]; + err = AudioFormatGetProperty(kAudioFormatProperty_EncodeFormatIDs, 0, NULL, &size, writableFormats); + if (err != noErr) goto bail; + + // get all readable formats + err = AudioFormatGetPropertyInfo(kAudioFormatProperty_DecodeFormatIDs, 0, NULL, &size); + if (err != noErr) goto bail; + nReadableFormats = size / sizeof(UInt32); + readableFormats = new UInt32[nReadableFormats]; + err = AudioFormatGetProperty(kAudioFormatProperty_DecodeFormatIDs, 0, NULL, &size, readableFormats); + if (err != noErr) goto bail; + + err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_AvailableFormatIDs, sizeof(UInt32), &mFileTypeID, &size); + if (err == noErr) { + mNumDataFormats = size / sizeof(OSType); + OSType *formatIDs = new OSType[mNumDataFormats]; + err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AvailableFormatIDs, + sizeof(UInt32), &mFileTypeID, &size, formatIDs); + if (err == noErr) { + mDataFormats = new DataFormatInfo[mNumDataFormats]; + for (int j = 0; j < mNumDataFormats; ++j) { + int k; + bool anyBigEndian = false, anyLittleEndian = false; + DataFormatInfo *dfi = &mDataFormats[j]; + dfi->mFormatID = formatIDs[j]; + dfi->mReadable = (dfi->mFormatID == kAudioFormatLinearPCM); + dfi->mWritable = (dfi->mFormatID == kAudioFormatLinearPCM); + for (k = 0; k < nReadableFormats; ++k) + if (readableFormats[k] == dfi->mFormatID) { + dfi->mReadable = true; + break; + } + for (k = 0; k < nWritableFormats; ++k) + if (writableFormats[k] == dfi->mFormatID) { + dfi->mWritable = true; + break; + } + + dfi->mNumVariants = 0; + AudioFileTypeAndFormatID tf = { mFileTypeID, dfi->mFormatID }; + err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_AvailableStreamDescriptionsForFormat, + sizeof(AudioFileTypeAndFormatID), &tf, &size); + if (err == noErr) { + dfi->mNumVariants = size / sizeof(AudioStreamBasicDescription); + dfi->mVariants = new AudioStreamBasicDescription[dfi->mNumVariants]; + err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AvailableStreamDescriptionsForFormat, + sizeof(AudioFileTypeAndFormatID), &tf, &size, dfi->mVariants); + if (err) { + dfi->mNumVariants = 0; + delete[] dfi->mVariants; + dfi->mVariants = NULL; + } else { + for (k = 0; k < dfi->mNumVariants; ++k) { + AudioStreamBasicDescription *desc = &dfi->mVariants[k]; + if (desc->mBitsPerChannel > 8) { + if (desc->mFormatFlags & kAudioFormatFlagIsBigEndian) + anyBigEndian = true; + else + anyLittleEndian = true; + } + } + } + } + + dfi->mEitherEndianPCM = (anyBigEndian && anyLittleEndian); + } + } + delete[] formatIDs; + } +bail: + delete[] readableFormats; + delete[] writableFormats; +} + +// note that the outgoing format will have zero for the sample rate, channels per frame, bytesPerPacket, bytesPerFrame +bool CAAudioFileFormats::InferDataFormatFromFileFormat(AudioFileTypeID filetype, CAStreamBasicDescription &fmt) +{ + // if the file format only supports one data format + for (int i = 0; i < mNumFileFormats; ++i) { + FileFormatInfo *ffi = &mFileFormats[i]; + ffi->LoadDataFormats(); + if (ffi->mFileTypeID == filetype && ffi->mNumDataFormats > 0) { + DataFormatInfo *dfi = &ffi->mDataFormats[0]; + if (ffi->mNumDataFormats > 1) { + // file can contain multiple data formats. Take PCM if it's there. + for (int j = 0; j < ffi->mNumDataFormats; ++j) { + if (ffi->mDataFormats[j].mFormatID == kAudioFormatLinearPCM) { + dfi = &ffi->mDataFormats[j]; + break; + } + } + } + memset(&fmt, 0, sizeof(fmt)); + fmt.mFormatID = dfi->mFormatID; + if (dfi->mNumVariants > 0) { + // take the first variant as a default + fmt = dfi->mVariants[0]; + if (dfi->mNumVariants > 1 && dfi->mFormatID == kAudioFormatLinearPCM) { + // look for a 16-bit variant as a better default + for (int j = 0; j < dfi->mNumVariants; ++j) { + AudioStreamBasicDescription *desc = &dfi->mVariants[j]; + if (desc->mBitsPerChannel == 16) { + fmt = *desc; + break; + } + } + } + } + return true; + } + } + return false; +} + +bool CAAudioFileFormats::InferFileFormatFromFilename(CFStringRef filename, AudioFileTypeID &filetype) +{ + bool result = false; + CFRange range = CFStringFind(filename, CFSTR("."), kCFCompareBackwards); + if (range.location == kCFNotFound) return false; + range.location += 1; + range.length = CFStringGetLength(filename) - range.location; + CFStringRef ext = CFStringCreateWithSubstring(NULL, filename, range); + for (int i = 0; i < mNumFileFormats; ++i) { + FileFormatInfo *ffi = &mFileFormats[i]; + if (ffi->MatchExtension(ext)) { + filetype = ffi->mFileTypeID; + result = true; + break; + } + } + CFRelease(ext); + return result; +} + +bool CAAudioFileFormats::InferFileFormatFromFilename(const char *filename, AudioFileTypeID &filetype) +{ + if (filename == NULL) return false; + CFStringRef cfname = CFStringCreateWithCString(NULL, filename, kCFStringEncodingUTF8); + bool result = InferFileFormatFromFilename(cfname, filetype); + CFRelease(cfname); + return result; +} + +bool CAAudioFileFormats::InferFileFormatFromDataFormat(const CAStreamBasicDescription &fmt, + AudioFileTypeID &filetype) +{ + // if there's exactly one file format that supports this data format + FileFormatInfo *theFileFormat = NULL; + for (int i = 0; i < mNumFileFormats; ++i) { + FileFormatInfo *ffi = &mFileFormats[i]; + ffi->LoadDataFormats(); + DataFormatInfo *dfi = ffi->mDataFormats, *dfiend = dfi + ffi->mNumDataFormats; + for ( ; dfi < dfiend; ++dfi) + if (dfi->mFormatID == fmt.mFormatID) { + if (theFileFormat != NULL) + return false; // ambiguous + theFileFormat = ffi; // got a candidate + } + } + if (theFileFormat == NULL) + return false; + filetype = theFileFormat->mFileTypeID; + return true; +} + +bool CAAudioFileFormats::IsKnownDataFormat(OSType dataFormat) +{ + for (int i = 0; i < mNumFileFormats; ++i) { + FileFormatInfo *ffi = &mFileFormats[i]; + ffi->LoadDataFormats(); + DataFormatInfo *dfi = ffi->mDataFormats, *dfiend = dfi + ffi->mNumDataFormats; + for ( ; dfi < dfiend; ++dfi) + if (dfi->mFormatID == dataFormat) + return true; + } + return false; +} + +CAAudioFileFormats::FileFormatInfo * CAAudioFileFormats::FindFileFormat(UInt32 formatID) +{ + for (int i = 0; i < mNumFileFormats; ++i) { + FileFormatInfo *ffi = &mFileFormats[i]; + if (ffi->mFileTypeID == formatID) + return ffi; + } + return NULL; +} + +bool CAAudioFileFormats::FileFormatInfo::AnyWritableFormats() +{ + LoadDataFormats(); + DataFormatInfo *dfi = mDataFormats, *dfiend = dfi + mNumDataFormats; + for ( ; dfi < dfiend; ++dfi) + if (dfi->mWritable) + return true; + return false; +} + +char *OSTypeToStr(char *buf, OSType t) +{ + char *p = buf; + char str[4], *q = str; + *(UInt32 *)str = CFSwapInt32HostToBig(t); + for (int i = 0; i < 4; ++i) { + if (isprint(*q) && *q != '\\') + *p++ = *q++; + else { + sprintf(p, "\\x%02x", *q++); + p += 4; + } + } + *p = '\0'; + return buf; +} + +int StrToOSType(const char *str, OSType &t) +{ + char buf[4]; + const char *p = str; + int x; + for (int i = 0; i < 4; ++i) { + if (*p != '\\') { + if ((buf[i] = *p++) == '\0') { + // special-case for 'aac ': if we only got three characters, assume the last was a space + if (i == 3) { + --p; + buf[i] = ' '; + break; + } + goto fail; + } + } else { + if (*++p != 'x') goto fail; + if (sscanf(++p, "%02X", &x) != 1) goto fail; + buf[i] = x; + p += 2; + } + } + t = CFSwapInt32BigToHost(*(UInt32 *)buf); + return p - str; +fail: + return 0; +} + +#if DEBUG + +void CAAudioFileFormats::DebugPrint() +{ + for (int i = 0; i < mNumFileFormats; ++i) + mFileFormats[i].DebugPrint(); +} + +void CAAudioFileFormats::FileFormatInfo::DebugPrint() +{ + char ftype[20]; + char ftypename[64]; + CFStringGetCString(mFileTypeName, ftypename, sizeof(ftypename), kCFStringEncodingUTF8); + printf("File type: '%s' = %s\n Extensions:", OSTypeToStr(ftype, mFileTypeID), ftypename); + int i, n = NumberOfExtensions(); + for (i = 0; i < n; ++i) { + GetExtension(i, ftype, sizeof(ftype)); + printf(" .%s", ftype); + } + LoadDataFormats(); + printf("\n Formats:\n"); + for (i = 0; i < mNumDataFormats; ++i) + mDataFormats[i].DebugPrint(); +} + +void CAAudioFileFormats::DataFormatInfo::DebugPrint() +{ + char buf[20]; + static const char *ny[] = { "not ", "" }; + printf(" '%s': %sreadable %swritable\n", OSTypeToStr(buf, mFormatID), ny[mReadable], ny[mWritable]); + for (int i = 0; i < mNumVariants; ++i) { + CAStreamBasicDescription desc(mVariants[i]); + desc.PrintFormat(stdout, " ", ""); + //printf(" %d bytes/frame\n", desc.mBytesPerFrame); + } +} +#endif + diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioFileFormats.h b/distrho/src/CoreAudio106/PublicUtility/CAAudioFileFormats.h new file mode 100755 index 00000000..589652e4 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioFileFormats.h @@ -0,0 +1,143 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __CAAudioFileFormats_h__ +#define __CAAudioFileFormats_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif +#include "CAStreamBasicDescription.h" + +class CAAudioFileFormats { +public: + enum { noErr = 0 }; + + struct DataFormatInfo { + DataFormatInfo() : mVariants(NULL) { } + ~DataFormatInfo() { delete[] mVariants; } + + UInt32 mFormatID; + int mNumVariants; + AudioStreamBasicDescription * mVariants; + bool mReadable; + bool mWritable; + bool mEitherEndianPCM; + +#if DEBUG + void DebugPrint(); +#endif + }; + + struct FileFormatInfo { + FileFormatInfo() : mFileTypeName(NULL), mExtensions(NULL), mDataFormats(NULL) { } + ~FileFormatInfo() { + delete[] mDataFormats; + if (mFileTypeName) + CFRelease(mFileTypeName); + if (mExtensions) + CFRelease(mExtensions); + } + + AudioFileTypeID mFileTypeID; + CFStringRef mFileTypeName; + CFArrayRef mExtensions; + int mNumDataFormats; + DataFormatInfo * mDataFormats; // NULL until loaded! + + int NumberOfExtensions() { return mExtensions ? CFArrayGetCount(mExtensions) : 0; } + char * GetExtension(int index, char *buf, int buflen) { + CFStringRef cfext = (CFStringRef)CFArrayGetValueAtIndex(mExtensions, index); + CFStringGetCString(cfext, buf, buflen, kCFStringEncodingUTF8); + return buf; + } + bool MatchExtension(CFStringRef testExt) { // testExt should not include "." + CFIndex n = NumberOfExtensions(); + for (CFIndex i = 0; i < n; ++i) { + CFStringRef ext = (CFStringRef)CFArrayGetValueAtIndex(mExtensions, i); + if (CFStringCompare(ext, testExt, kCFCompareCaseInsensitive) == kCFCompareEqualTo) + return true; + } + return false; + } + bool AnyWritableFormats(); + void LoadDataFormats(); + +#if DEBUG + void DebugPrint(); +#endif + }; + +private: // use Instance() + CAAudioFileFormats(bool loadDataFormats); + ~CAAudioFileFormats(); +public: + + bool InferDataFormatFromFileFormat(AudioFileTypeID filetype, CAStreamBasicDescription &fmt); + + bool InferFileFormatFromFilename(const char *filename, AudioFileTypeID &filetype); + + bool InferFileFormatFromFilename(CFStringRef filename, AudioFileTypeID &filetype); + + bool InferFileFormatFromDataFormat(const CAStreamBasicDescription &fmt, AudioFileTypeID &filetype); + + bool IsKnownDataFormat(UInt32 dataFormat); + +#if DEBUG + void DebugPrint(); +#endif + + int mNumFileFormats; + FileFormatInfo * mFileFormats; + + FileFormatInfo * FindFileFormat(UInt32 formatID); + + static CAAudioFileFormats * Instance(bool loadDataFormats=true); + +private: + static CAAudioFileFormats * sInstance; +}; + +char * OSTypeToStr(char *buf, UInt32 t); +int StrToOSType(const char *str, UInt32 &t); + +#endif // __CAAudioFileFormats_h__ diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioTimeStamp.cpp b/distrho/src/CoreAudio106/PublicUtility/CAAudioTimeStamp.cpp new file mode 100755 index 00000000..c0bfbe4e --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioTimeStamp.cpp @@ -0,0 +1,127 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CAAudioTimeStamp.h" + +//============================================================================= +// CAAudioTimeStamp +//============================================================================= + +const AudioTimeStamp CAAudioTimeStamp::kZero = { 0.0, 0, 0.0, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 0 }; + +bool operator<(const AudioTimeStamp& x, const AudioTimeStamp& y) +{ + bool isLessThan = false; + bool isDone = false; + + // check the sample time + if(!isDone) + { + if((x.mFlags & kAudioTimeStampSampleTimeValid) && (y.mFlags & kAudioTimeStampSampleTimeValid)) + { + isLessThan = x.mSampleTime < y.mSampleTime; + isDone = true; + } + } + + // check the host time + if(!isDone) + { + if((x.mFlags & kAudioTimeStampHostTimeValid) && (y.mFlags & kAudioTimeStampHostTimeValid)) + { + isLessThan = x.mHostTime < y.mHostTime; + isDone = true; + } + } + + // check the word clock time + if(!isDone) + { + if((x.mFlags & kAudioTimeStampWordClockTimeValid) && (y.mFlags & kAudioTimeStampWordClockTimeValid)) + { + isLessThan = x.mWordClockTime < y.mWordClockTime; + isDone = true; + } + } + + return isLessThan; +} + +bool operator==(const AudioTimeStamp& x, const AudioTimeStamp& y) +{ + bool isEqual = false; + bool isDone = false; + + // check the sample time + if(!isDone) + { + if((x.mFlags & kAudioTimeStampSampleTimeValid) && (y.mFlags & kAudioTimeStampSampleTimeValid)) + { + isEqual = x.mSampleTime == y.mSampleTime; + isDone = true; + } + } + + // check the host time + if(!isDone) + { + if((x.mFlags & kAudioTimeStampHostTimeValid) && (y.mFlags & kAudioTimeStampHostTimeValid)) + { + isEqual = x.mHostTime == y.mHostTime; + isDone = true; + } + } + + // check the word clock time + if(!isDone) + { + if((x.mFlags & kAudioTimeStampWordClockTimeValid) && (y.mFlags & kAudioTimeStampWordClockTimeValid)) + { + isEqual = x.mWordClockTime == y.mWordClockTime; + isDone = true; + } + } + + return isEqual; +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioTimeStamp.h b/distrho/src/CoreAudio106/PublicUtility/CAAudioTimeStamp.h new file mode 100755 index 00000000..18261bcb --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioTimeStamp.h @@ -0,0 +1,90 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CAAudioTimeStamp_h__) +#define __CAAudioTimeStamp_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +#include + +//============================================================================= +// CAAudioTimeStamp +//============================================================================= + +struct CAAudioTimeStamp +: + public AudioTimeStamp +{ + +// Construction/Destruction +public: + CAAudioTimeStamp() { memset(this, 0, sizeof(AudioTimeStamp)); } + CAAudioTimeStamp(const AudioTimeStamp& v) { memcpy(this, &v, sizeof(AudioTimeStamp)); } + CAAudioTimeStamp(Float64 inSampleTime) { memset(this, 0, sizeof(AudioTimeStamp)); mSampleTime = inSampleTime; mFlags = kAudioTimeStampSampleTimeValid; } + CAAudioTimeStamp(UInt64 inHostTime) { memset(this, 0, sizeof(AudioTimeStamp)); mHostTime = inHostTime; mFlags = kAudioTimeStampHostTimeValid; } + CAAudioTimeStamp(Float64 inSampleTime, UInt64 inHostTime) { memset(this, 0, sizeof(AudioTimeStamp)); mSampleTime = inSampleTime; mHostTime = inHostTime; mFlags = kAudioTimeStampSampleTimeValid | kAudioTimeStampHostTimeValid; } + +// Assignment +public: + CAAudioTimeStamp& operator=(const AudioTimeStamp& v) { memcpy(this, &v, sizeof(AudioTimeStamp)); return *this; } + +// Constants +public: + static const AudioTimeStamp kZero; + +}; + +bool operator<(const AudioTimeStamp& x, const AudioTimeStamp& y); +bool operator==(const AudioTimeStamp& x, const AudioTimeStamp& y); +inline bool operator!=(const AudioTimeStamp& x, const AudioTimeStamp& y) { return !(x == y); } +inline bool operator<=(const AudioTimeStamp& x, const AudioTimeStamp& y) { return (x < y) || (x == y); } +inline bool operator>=(const AudioTimeStamp& x, const AudioTimeStamp& y) { return !(x < y); } +inline bool operator>(const AudioTimeStamp& x, const AudioTimeStamp& y) { return !((x < y) || (x == y)); } + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioUnit.cpp b/distrho/src/CoreAudio106/PublicUtility/CAAudioUnit.cpp new file mode 100755 index 00000000..e4e60d59 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioUnit.cpp @@ -0,0 +1,1257 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CAAudioUnit.h" + +#if !TARGET_OS_IPHONE +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include + #include +#else + #include + #include +#endif +#endif + +#include "CAXException.h" +#include "CAReferenceCounted.h" +#include "AUOutputBL.h" //this is for the Preroll only + +struct StackAUChannelInfo { + StackAUChannelInfo (UInt32 inSize) : mChanInfo ((AUChannelInfo*)malloc (inSize)) {} + ~StackAUChannelInfo() { free (mChanInfo); } + + AUChannelInfo* mChanInfo; +}; + +// is this symbol is not defined then we use the default setting which is that fast dispatch +// is supported on a desktop environment +#ifndef CA_AU_USE_FAST_DISPATCH + #define CA_AU_USE_FAST_DISPATCH !TARGET_OS_IPHONE +#endif + +class CAAudioUnit::AUState : public CAReferenceCounted { +public: + AUState (AudioComponent inComp) + : mUnit(0), mNode (0) + { + OSStatus result = ::AudioComponentInstanceNew (inComp, &mUnit); + if (result) + throw result; + Init(); + } + + AUState (const AUNode &inNode, const AudioUnit& inUnit) + : mUnit (inUnit), mNode (inNode) + { + Init(); + } + + ~AUState(); + + AudioUnit mUnit; + AUNode mNode; + + OSStatus GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 &outValue) const + { +#if CA_AU_USE_FAST_DISPATCH + if (mGetParamProc != NULL) { + return (mGetParamProc) (mConnInstanceStorage, inID, scope, element, &outValue); + } +#endif + return AudioUnitGetParameter(mUnit, inID, scope, element, &outValue); + } + + OSStatus SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 value, UInt32 bufferOffsetFrames) + { +#if CA_AU_USE_FAST_DISPATCH + if (mSetParamProc != NULL) { + return (mSetParamProc) (mConnInstanceStorage, inID, scope, element, value, bufferOffsetFrames); + } +#endif + return AudioUnitSetParameter(mUnit, inID, scope, element, value, bufferOffsetFrames); + } + + OSStatus Render (AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData) + { +#if CA_AU_USE_FAST_DISPATCH + if (mRenderProc != NULL) { + return (mRenderProc) (mConnInstanceStorage, ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData); + } +#endif + return AudioUnitRender(mUnit, ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData); + } + +#if !TARGET_OS_IPHONE + OSStatus MIDIEvent (UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) + { +#if !TARGET_OS_WIN32 +#if CA_AU_USE_FAST_DISPATCH + if (mMIDIEventProc != NULL) { + return (mMIDIEventProc) (mConnInstanceStorage, inStatus, inData1, inData2, inOffsetSampleFrame); + } +#endif + return MusicDeviceMIDIEvent (mUnit, inStatus, inData1, inData2, inOffsetSampleFrame); +#else // ON WINDOWS _ NO MIDI EVENT dispatch + return paramErr; +#endif + } + + OSStatus StartNote (MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) + { +#if !TARGET_OS_WIN32 +#if CA_AU_USE_FAST_DISPATCH + if (mStartNoteProc != NULL) { + return (mStartNoteProc) (mConnInstanceStorage, inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams); + } +#endif + return MusicDeviceStartNote (mUnit, inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams); +#else + return paramErr; +#endif + } + OSStatus StopNote (MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) + { +#if !TARGET_OS_WIN32 +#if CA_AU_USE_FAST_DISPATCH + if (mStopNoteProc != NULL) { + return (mStopNoteProc) (mConnInstanceStorage, inGroupID, inNoteInstanceID, inOffsetSampleFrame); + } +#endif + return MusicDeviceStopNote (mUnit, inGroupID, inNoteInstanceID, inOffsetSampleFrame); +#else + return paramErr; +#endif + } +#endif// !TARGET_OS_IPHONE + +private: + // get the fast dispatch pointers + void Init() + { +#if CA_AU_USE_FAST_DISPATCH + UInt32 size = sizeof(AudioUnitRenderProc); + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kAudioUnitRenderSelect, + &mRenderProc, &size) != noErr) + mRenderProc = NULL; + + size = sizeof(AudioUnitGetParameterProc); + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kAudioUnitGetParameterSelect, + &mGetParamProc, &size) != noErr) + mGetParamProc = NULL; + + size = sizeof(AudioUnitSetParameterProc); + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kAudioUnitSetParameterSelect, + &mSetParamProc, &size) != noErr) + mSetParamProc = NULL; + + size = sizeof(MusicDeviceMIDIEventProc); + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kMusicDeviceMIDIEventSelect, + &mMIDIEventProc, &size) != noErr) + mMIDIEventProc = NULL; + + size = sizeof(MusicDeviceStartNoteProc); + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kMusicDeviceStartNoteSelect, + &mStartNoteProc, &size) != noErr) + mStartNoteProc = NULL; + + size = sizeof(MusicDeviceStopNoteProc); + if (AudioUnitGetProperty(mUnit, kAudioUnitProperty_FastDispatch, + kAudioUnitScope_Global, kMusicDeviceStopNoteSelect, + &mStopNoteProc, &size) != noErr) + mStopNoteProc = NULL; + + if (mRenderProc || mGetParamProc || mSetParamProc || mMIDIEventProc || mStartNoteProc || mStopNoteProc) { + mConnInstanceStorage = GetComponentInstanceStorage ( mUnit ); + } else + mConnInstanceStorage = NULL; +#else + mConnInstanceStorage = NULL; +#endif + } + +#if CA_AU_USE_FAST_DISPATCH + AudioUnitRenderProc mRenderProc; + AudioUnitGetParameterProc mGetParamProc; + AudioUnitSetParameterProc mSetParamProc; + MusicDeviceMIDIEventProc mMIDIEventProc; + MusicDeviceStartNoteProc mStartNoteProc; + MusicDeviceStopNoteProc mStopNoteProc; +#endif + + void * mConnInstanceStorage; + +private: + // get the compiler to tell us when we do a bad thing!!! + AUState () {} + AUState (const AUState&) {} + AUState& operator= (const AUState&) { return *this; } +}; + + +CAAudioUnit::AUState::~AUState () +{ + if (mUnit && (mNode == 0)) { + ::AudioComponentInstanceDispose (mUnit); + } + mNode = 0; + mUnit = 0; +} + +OSStatus CAAudioUnit::Open (const CAComponent& inComp, CAAudioUnit &outUnit) +{ + try { + outUnit = inComp; + return noErr; + } catch (OSStatus res) { + return res; + } catch (...) { + return -1; + } +} + +CAAudioUnit::CAAudioUnit (const AudioUnit& inUnit) + : mComp (inUnit), mDataPtr (new AUState (kCAAU_DoNotKnowIfAUNode, inUnit)) +{ +} + +CAAudioUnit::CAAudioUnit (const CAComponent& inComp) + : mComp (inComp), mDataPtr (new AUState (mComp.Comp())) +{ +} + +CAAudioUnit::CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit) + : mComp (inUnit), mDataPtr(new AUState (inNode, inUnit)) +{ +} + +CAAudioUnit::~CAAudioUnit () +{ + Close(); +} + +void CAAudioUnit::Close() +{ + if (mDataPtr) { + mDataPtr->release(); + mDataPtr = NULL; + } +} + +CAAudioUnit& CAAudioUnit::operator= (const CAAudioUnit &a) +{ + if (mDataPtr != a.mDataPtr) { + if (mDataPtr) + mDataPtr->release(); + + if ((mDataPtr = a.mDataPtr) != NULL) + mDataPtr->retain(); + + mComp = a.mComp; + } + + return *this; +} + +bool CAAudioUnit::operator== (const CAAudioUnit& y) const +{ + if (mDataPtr == y.mDataPtr) return true; + AudioUnit au1 = mDataPtr ? mDataPtr->mUnit : 0; + AudioUnit au2 = y.mDataPtr ? y.mDataPtr->mUnit : 0; + return au1 == au2; +} + +bool CAAudioUnit::operator== (const AudioUnit& y) const +{ + if (!mDataPtr) return false; + return mDataPtr->mUnit == y; +} + +OSStatus CAAudioUnit::RemovePropertyListener (AudioUnitPropertyID inID, + AudioUnitPropertyListenerProc inProc, + void * inProcUserData) +{ + // we call this first. If it fails we call the old API as the failure can + // mean that the AU doesn't implement that selector. + OSStatus result = AudioUnitRemovePropertyListenerWithUserData(AU(), inID, + inProc, inProcUserData); + #if !__LP64__ && !TARGET_OS_IPHONE + if (result) result = AudioUnitRemovePropertyListener (AU(), inID, inProc); + #endif + return result; +} + +#pragma mark __State Management + +bool CAAudioUnit::IsValid () const +{ + return mDataPtr ? mDataPtr->mUnit != 0 : false; +} + +AudioUnit CAAudioUnit::AU() const +{ + return mDataPtr ? mDataPtr->mUnit : 0; +} + +AUNode CAAudioUnit::GetAUNode () const +{ + return mDataPtr ? mDataPtr->mNode : 0; +} + +#pragma mark __Format Handling + +bool CAAudioUnit::CanDo ( int inChannelsIn, + int inChannelsOut) const +{ + // this is the default assumption of an audio effect unit + Boolean* isWritable = 0; + UInt32 dataSize = 0; + // lets see if the unit has any channel restrictions + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + &dataSize, isWritable); //don't care if this is writable + + // if this property is NOT implemented an FX unit + // is expected to deal with same channel valance in and out + if (result) + { + if (Comp().Desc().IsEffect() && (inChannelsIn == inChannelsOut) + || Comp().Desc().IsOffline() && (inChannelsIn == inChannelsOut)) + { + return true; + } + else + { + // the au should either really tell us about this + // or we will assume the worst + return false; + } + } + + StackAUChannelInfo info (dataSize); + + result = GetProperty (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + info.mChanInfo, &dataSize); + if (result) { return false; } + + return ValidateChannelPair (inChannelsIn, inChannelsOut, info.mChanInfo, (dataSize / sizeof (AUChannelInfo))); +} + +bool CAAudioUnit::ValidateChannelPair (int inChannelsIn, + int inChannelsOut, + const AUChannelInfo * info, + UInt32 numChanInfo) const +{ +// we've the following cases (some combinations) to test here: +/* +>0 An explicit number of channels on either side +0 that side (generally input!) has no elements +-1 wild card: +-1,-1 any num channels as long as same channels on in and out +-1,-2 any num channels channels on in and out - special meaning +-2+ indicates total num channs AU can handle + - elements configurable to any num channels, + - element count in scope must be writable +*/ + + //now chan layout can contain -1 for either scope (ie. doesn't care) + for (unsigned int i = 0; i < numChanInfo; ++i) + { + //less than zero on both sides - check for special attributes + if ((info[i].inChannels < 0) && (info[i].outChannels < 0)) + { + // these are our wild card matches + if (info[i].inChannels == -1 && info[i].outChannels == -1) { + if (inChannelsIn && inChannelsOut) { + if (inChannelsOut == inChannelsIn) + return true; + } else + return true; // if one of these is zero, then a -1 means any + } + else if ((info[i].inChannels == -1 && info[i].outChannels == -2) + || (info[i].inChannels == -2 && info[i].outChannels == -1)) + { + return true; + } + // these are our total num channels matches + // element count MUST be writable + else { + bool outWrite = false; bool inWrite = false; + IsElementCountWritable (kAudioUnitScope_Output, outWrite); + IsElementCountWritable (kAudioUnitScope_Input, inWrite); + if (inWrite && outWrite) { + if ((inChannelsOut <= abs(info[i].outChannels)) + && (inChannelsIn <= abs(info[i].inChannels))) + { + return true; + } + } + } + } + + // special meaning on input, specific num on output + else if (info[i].inChannels < 0) { + if (info[i].outChannels == inChannelsOut) + { + // can do any in channels + if (info[i].inChannels == -1) { + return true; + } + // total chans on input + else { + bool inWrite = false; + IsElementCountWritable (kAudioUnitScope_Input, inWrite); + if (inWrite && (inChannelsIn <= abs(info[i].inChannels))) { + return true; + } + } + } + } + + // special meaning on output, specific num on input + else if (info[i].outChannels < 0) { + if (info[i].inChannels == inChannelsIn) + { + // can do any out channels + if (info[i].outChannels == -1) { + return true; + } + // total chans on output + else { + bool outWrite = false; + IsElementCountWritable (kAudioUnitScope_Output, outWrite); + if (outWrite && (inChannelsOut <= abs(info[i].outChannels))) { + return true; + } + } + } + } + + // both chans in struct >= 0 - thus has to explicitly match + else if ((info[i].inChannels == inChannelsIn) && (info[i].outChannels == inChannelsOut)) { + return true; + } + + // now check to see if a wild card on the args (inChannelsIn or inChannelsOut chans is zero) is found + // tells us to match just one side of the scopes + else if (inChannelsIn == 0) { + if (info[i].outChannels == inChannelsOut) { + return true; + } + } + else if (inChannelsOut == 0) { + if (info[i].inChannels == inChannelsIn) { + return true; + } + } + } + + return false; +} + +bool CheckDynCount (SInt32 inTotalChans, const CAAUChanHelper &inHelper) +{ + int totalChans = 0; + for (unsigned int i = 0; i < inHelper.mNumEls; ++i) + totalChans += inHelper.mChans[i]; + return (totalChans <= inTotalChans); +} + +bool CAAudioUnit::CheckOneSide (const CAAUChanHelper &inHelper, + bool checkOutput, + const AUChannelInfo *info, + UInt32 numInfo) const +{ + // now we can use the wildcard option (see above impl) to see if this matches + for (unsigned int el = 0; el < inHelper.mNumEls; ++el) { + bool testAlready = false; + for (unsigned int i = 0; i < el; ++i) { + if (inHelper.mChans[i] == inHelper.mChans[el]) { + testAlready = true; + break; + } + } + if (!testAlready) { + if (checkOutput) { + if (!ValidateChannelPair (0, inHelper.mChans[el], info, numInfo)) return false; + } else { + if (!ValidateChannelPair (inHelper.mChans[el], 0, info, numInfo)) return false; + } + } + } + return true; +} + +bool CAAudioUnit::CanDo (const CAAUChanHelper &inputs, + const CAAUChanHelper &outputs) const + +{ +// first check our state + // huh! + if (inputs.mNumEls == 0 && outputs.mNumEls == 0) return false; + + UInt32 elCount; + if (GetElementCount (kAudioUnitScope_Input, elCount)) { return false; } + if (elCount != inputs.mNumEls) return false; + + if (GetElementCount (kAudioUnitScope_Output, elCount)) { return false; } + if (elCount != outputs.mNumEls) return false; + +// (1) special cases (effects and sources (generators and instruments) only) + UInt32 dataSize = 0; + if (GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, &dataSize, NULL) != noErr) + { + if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) { + UInt32 numChan = outputs.mNumEls > 0 ? outputs.mChans[0] : inputs.mChans[0]; + for (unsigned int in = 0; in < inputs.mNumEls; ++in) + if (numChan != inputs.mChans[in]) return false; + for (unsigned int out = 0; out < outputs.mNumEls; ++out) + if (numChan != outputs.mChans[out]) return false; + return true; + } + + // in this case, all the channels have to match the current config + if (Comp().Desc().IsGenerator() || Comp().Desc().IsMusicDevice()) { + for (unsigned int in = 0; in < inputs.mNumEls; ++in) { + UInt32 chan; + if (NumberChannels (kAudioUnitScope_Input, in, chan)) return false; + if (chan != UInt32(inputs.mChans[in])) return false; + } + for (unsigned int out = 0; out < outputs.mNumEls; ++out) { + UInt32 chan; + if (NumberChannels (kAudioUnitScope_Output, out, chan)) return false; + if (chan != UInt32(outputs.mChans[out])) return false; + } + return true; + } + + // if we get here we can't determine anything about channel capabilities + return false; + } + + StackAUChannelInfo info (dataSize); + + if (GetProperty (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + info.mChanInfo, &dataSize) != noErr) + { + return false; + } + + int numInfo = dataSize / sizeof(AUChannelInfo); + +// (2) Test for dynamic capability (or no elements on that scope) + SInt32 dynInChans = 0; + if (ValidateDynamicScope (kAudioUnitScope_Input, dynInChans, info.mChanInfo, numInfo)) { + if (CheckDynCount (dynInChans, inputs) == false) return false; + } + + SInt32 dynOutChans = 0; + if (ValidateDynamicScope (kAudioUnitScope_Output, dynOutChans, info.mChanInfo, numInfo)) { + if (CheckDynCount (dynOutChans, outputs) == false) return false; + } + + if (dynOutChans && dynInChans) { return true; } + +// (3) Just need to test one side + if (dynInChans || (inputs.mNumEls == 0)) { + return CheckOneSide (outputs, true, info.mChanInfo, numInfo); + } + + if (dynOutChans || (outputs.mNumEls == 0)) { + return CheckOneSide (inputs, false, info.mChanInfo, numInfo); + } + +// (4) - not a dynamic AU, has ins and outs, and has channel constraints so we test every possible pairing + for (unsigned int in = 0; in < inputs.mNumEls; ++in) + { + bool testInAlready = false; + for (unsigned int i = 0; i < in; ++i) { + if (inputs.mChans[i] == inputs.mChans[in]) { + testInAlready = true; + break; + } + } + if (!testInAlready) { + for (unsigned int out = 0; out < outputs.mNumEls; ++out) { + // try to save a little bit and not test the same pairing multiple times... + bool testOutAlready = false; + for (unsigned int i = 0; i < out; ++i) { + if (outputs.mChans[i] == outputs.mChans[out]) { + testOutAlready = true; + break; + } + } + if (!testOutAlready) { + if (!ValidateChannelPair (inputs.mChans[in], outputs.mChans[out],info.mChanInfo, numInfo)) { + return false; + } + } + } + } + } + + return true; +} + +bool CAAudioUnit::SupportsNumChannels () const +{ + // this is the default assumption of an audio effect unit + Boolean* isWritable = 0; + UInt32 dataSize = 0; + // lets see if the unit has any channel restrictions + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + &dataSize, isWritable); //don't care if this is writable + + // if this property is NOT implemented an FX unit + // is expected to deal with same channel valance in and out + if (result) { + if (Comp().Desc().IsEffect() || Comp().Desc().IsOffline()) + return true; + } + return result == noErr; +} + +OSStatus CAAudioUnit::GetChannelLayoutTags (AudioUnitScope inScope, + AudioUnitElement inEl, + ChannelTagVector &outChannelVector) const +{ + if (HasChannelLayouts (inScope, inEl) == false) return kAudioUnitErr_InvalidProperty; + + UInt32 dataSize; + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedChannelLayoutTags, + inScope, inEl, + &dataSize, NULL); + + if (result) return result; + + // OK lets get our channel layouts and see if the one we want is present + AudioChannelLayoutTag* info = (AudioChannelLayoutTag*)malloc (dataSize); + result = AudioUnitGetProperty (AU(), + kAudioUnitProperty_SupportedChannelLayoutTags, + inScope, inEl, + info, &dataSize); + if (result) goto home; + + outChannelVector.erase (outChannelVector.begin(), outChannelVector.end()); + for (unsigned int i = 0; i < (dataSize / sizeof (AudioChannelLayoutTag)); ++i) + outChannelVector.push_back (info[i]); + +home: + free (info); + return result; +} + +bool CAAudioUnit::HasChannelLayouts (AudioUnitScope inScope, + AudioUnitElement inEl) const +{ + OSStatus result = AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_SupportedChannelLayoutTags, + inScope, inEl, + NULL, NULL); + return !result; +} + +bool CAAudioUnit::HasChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl) const +{ + Boolean writable; + UInt32 size; + + return AudioUnitGetPropertyInfo (AU(), + kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, + &size, &writable) == noErr; +} + +OSStatus CAAudioUnit::GetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + CAAudioChannelLayout &outLayout) const +{ + UInt32 size; + OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, &size, NULL); + if (result) return result; + + AudioChannelLayout *layout = (AudioChannelLayout*)malloc (size); + + ca_require_noerr (result = AudioUnitGetProperty (AU(), kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, layout, &size), home); + + outLayout = CAAudioChannelLayout (layout); + +home: + free (layout); + return result; +} + +OSStatus CAAudioUnit::SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + const CAAudioChannelLayout &inLayout) +{ + OSStatus result = AudioUnitSetProperty (AU(), + kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, + inLayout, inLayout.Size()); + return result; +} + +OSStatus CAAudioUnit::SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + const AudioChannelLayout &inLayout, + UInt32 inSize) +{ + OSStatus result = AudioUnitSetProperty (AU(), + kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, + &inLayout, inSize); + return result; +} + +OSStatus CAAudioUnit::ClearChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl) +{ + return AudioUnitSetProperty (AU(), + kAudioUnitProperty_AudioChannelLayout, + inScope, inEl, NULL, 0); +} + +OSStatus CAAudioUnit::GetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + AudioStreamBasicDescription &outFormat) const +{ + UInt32 dataSize = sizeof (AudioStreamBasicDescription); + return AudioUnitGetProperty (AU(), kAudioUnitProperty_StreamFormat, + inScope, inEl, + &outFormat, &dataSize); +} + +OSStatus CAAudioUnit::SetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + const AudioStreamBasicDescription &inFormat) +{ + return AudioUnitSetProperty (AU(), kAudioUnitProperty_StreamFormat, + inScope, inEl, + const_cast(&inFormat), + sizeof (AudioStreamBasicDescription)); +} + +OSStatus CAAudioUnit::GetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 &outRate) const +{ + UInt32 dataSize = sizeof (Float64); + return AudioUnitGetProperty (AU(), kAudioUnitProperty_SampleRate, + inScope, inEl, + &outRate, &dataSize); +} + +OSStatus CAAudioUnit::SetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 inRate) +{ + AudioStreamBasicDescription desc; + OSStatus result = GetFormat (inScope, inEl, desc); + if (result) return result; + desc.mSampleRate = inRate; + return SetFormat (inScope, inEl, desc); +} + +OSStatus CAAudioUnit::SetSampleRate (Float64 inSampleRate) +{ + OSStatus result; + + UInt32 elCount; + ca_require_noerr (result = GetElementCount(kAudioUnitScope_Input, elCount), home); + if (elCount) { + for (unsigned int i = 0; i < elCount; ++i) { + ca_require_noerr (result = SetSampleRate (kAudioUnitScope_Input, i, inSampleRate), home); + } + } + + ca_require_noerr (result = GetElementCount(kAudioUnitScope_Output, elCount), home); + if (elCount) { + for (unsigned int i = 0; i < elCount; ++i) { + ca_require_noerr (result = SetSampleRate (kAudioUnitScope_Output, i, inSampleRate), home); + } + } + +home: + return result; +} + +OSStatus CAAudioUnit::NumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 &outChans) const +{ + AudioStreamBasicDescription desc; + OSStatus result = GetFormat (inScope, inEl, desc); + if (!result) + outChans = desc.mChannelsPerFrame; + return result; +} + +OSStatus CAAudioUnit::SetNumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 inChans) +{ + // set this as the output of the AU + CAStreamBasicDescription desc; + OSStatus result = GetFormat (inScope, inEl, desc); + if (result) return result; + desc.SetAUCanonical (inChans, desc.IsInterleaved()); + result = SetFormat (inScope, inEl, desc); + return result; +} + +OSStatus CAAudioUnit::IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const +{ + Boolean isWritable; + UInt32 outDataSize; + OSStatus result = GetPropertyInfo (kAudioUnitProperty_ElementCount, inScope, 0, &outDataSize, &isWritable); + if (result) + return result; + outWritable = isWritable ? true : false; + return noErr; +} + +OSStatus CAAudioUnit::GetElementCount (AudioUnitScope inScope, UInt32 &outCount) const +{ + UInt32 propSize = sizeof(outCount); + return GetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &outCount, &propSize); +} + +OSStatus CAAudioUnit::SetElementCount (AudioUnitScope inScope, UInt32 inCount) +{ + return SetProperty (kAudioUnitProperty_ElementCount, inScope, 0, &inCount, sizeof(inCount)); +} + +bool CAAudioUnit::HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const +{ + // ok - now we need to check the AU's capability here. + // this is the default assumption of an audio effect unit + Boolean* isWritable = 0; + UInt32 dataSize = 0; + OSStatus result = GetPropertyInfo (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + &dataSize, isWritable); //don't care if this is writable + + // AU has to explicitly tell us about this. + if (result) return false; + + StackAUChannelInfo info (dataSize); + + result = GetProperty (kAudioUnitProperty_SupportedNumChannels, + kAudioUnitScope_Global, 0, + info.mChanInfo, &dataSize); + if (result) return false; + + return ValidateDynamicScope (inScope, outTotalNumChannels, info.mChanInfo, (dataSize / sizeof(AUChannelInfo))); +} + +// as we've already checked that the element count is writable +// the following conditions will match this.. +/* +-1, -2 -> signifies no restrictions +-2, -1 -> signifies no restrictions -> in this case outTotalNumChannels == -1 (any num channels) + +-N (where N is less than -2), signifies the total channel count on the scope side (in or out) +*/ +bool CAAudioUnit::ValidateDynamicScope (AudioUnitScope inScope, + SInt32 &outTotalNumChannels, + const AUChannelInfo *info, + UInt32 numInfo) const +{ + bool writable = false; + OSStatus result = IsElementCountWritable (inScope, writable); + if (result || (writable == false)) + return false; + + //now chan layout can contain -1 for either scope (ie. doesn't care) + for (unsigned int i = 0; i < numInfo; ++i) + { + // lets test the special wild card case first... + // this says the AU can do any num channels on input or output - for eg. Matrix Mixer + if (((info[i].inChannels == -1) && (info[i].outChannels == -2)) + || ((info[i].inChannels == -2) && (info[i].outChannels == -1))) + { + outTotalNumChannels = -1; + return true; + } + + // ok lets now test our special case.... + if (inScope == kAudioUnitScope_Input) { + // isn't dynamic on this side at least + if (info[i].inChannels >= 0) + continue; + + if (info[i].inChannels < -2) { + outTotalNumChannels = abs (info[i].inChannels); + return true; + } + } + + else if (inScope == kAudioUnitScope_Output) { + // isn't dynamic on this side at least + if (info[i].outChannels >= 0) + continue; + + if (info[i].outChannels < -2) { + outTotalNumChannels = abs (info[i].outChannels); + return true; + } + } + + else { + break; // wrong scope was specified + } + } + + return false; +} + +OSStatus CAAudioUnit::ConfigureDynamicScope (AudioUnitScope inScope, + UInt32 inNumElements, + UInt32 *inChannelsPerElement, + Float64 inSampleRate) +{ + SInt32 numChannels = 0; + bool isDyamic = HasDynamicScope (inScope, numChannels); + if (isDyamic == false) + return kAudioUnitErr_InvalidProperty; + + //lets to a sanity check... + // if numChannels == -1, then it can do "any"... + if (numChannels > 0) { + SInt32 count = 0; + for (unsigned int i = 0; i < inNumElements; ++i) + count += inChannelsPerElement[i]; + if (count > numChannels) + return kAudioUnitErr_InvalidPropertyValue; + } + + OSStatus result = SetElementCount (inScope, inNumElements); + if (result) + return result; + + CAStreamBasicDescription desc; + desc.mSampleRate = inSampleRate; + for (unsigned int i = 0; i < inNumElements; ++i) { + desc.SetAUCanonical (inChannelsPerElement[i], false); + result = SetFormat (inScope, i, desc); + if (result) + return result; + } + return noErr; +} + +#pragma mark __Properties + +bool CAAudioUnit::CanBypass () const +{ + Boolean outWritable; + OSStatus result = AudioUnitGetPropertyInfo (AU(), kAudioUnitProperty_BypassEffect, + kAudioUnitScope_Global, 0, + NULL, &outWritable); + return (!result && outWritable); +} + +bool CAAudioUnit::GetBypass () const +{ + UInt32 dataSize = sizeof (UInt32); + UInt32 outBypass; + OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_BypassEffect, + kAudioUnitScope_Global, 0, + &outBypass, &dataSize); + return (result ? false : outBypass); +} + +OSStatus CAAudioUnit::SetBypass (bool inBypass) const +{ + UInt32 bypass = inBypass ? 1 : 0; + return AudioUnitSetProperty (AU(), kAudioUnitProperty_BypassEffect, + kAudioUnitScope_Global, 0, + &bypass, sizeof (UInt32)); +} + +Float64 CAAudioUnit::Latency () const +{ + Float64 secs; + UInt32 size = sizeof(secs); + if (GetProperty (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, &secs, &size)) + return 0; + return secs; +} + +OSStatus CAAudioUnit::GetAUPreset (CFPropertyListRef &outData) const +{ + UInt32 dataSize = sizeof(outData); + return AudioUnitGetProperty (AU(), kAudioUnitProperty_ClassInfo, + kAudioUnitScope_Global, 0, + &outData, &dataSize); +} + +OSStatus CAAudioUnit::SetAUPreset (CFPropertyListRef &inData) +{ + return AudioUnitSetProperty (AU(), kAudioUnitProperty_ClassInfo, + kAudioUnitScope_Global, 0, + &inData, sizeof (CFPropertyListRef)); +} + +#if !TARGET_OS_IPHONE +OSStatus CAAudioUnit::SetAUPresetFromDocument (CFPropertyListRef &inData) +{ + return AudioUnitSetProperty (AU(), kAudioUnitProperty_ClassInfoFromDocument, + kAudioUnitScope_Global, 0, + &inData, sizeof (CFPropertyListRef)); +} +#endif + +OSStatus CAAudioUnit::GetPresentPreset (AUPreset &outData) const +{ + UInt32 dataSize = sizeof(outData); + OSStatus result = AudioUnitGetProperty (AU(), kAudioUnitProperty_PresentPreset, + kAudioUnitScope_Global, 0, + &outData, &dataSize); +#if !TARGET_OS_IPHONE +#ifndef __LP64__ + if (result == kAudioUnitErr_InvalidProperty) { + dataSize = sizeof(outData); + result = AudioUnitGetProperty (AU(), kAudioUnitProperty_CurrentPreset, + kAudioUnitScope_Global, 0, + &outData, &dataSize); + if (result == noErr) { + // we now retain the CFString in the preset so for the client of this API + // it is consistent (ie. the string should be released when done) + if (outData.presetName) + CFRetain (outData.presetName); + } + } +#endif +#endif + return result; +} + +OSStatus CAAudioUnit::SetPresentPreset (AUPreset &inData) +{ + OSStatus result = AudioUnitSetProperty (AU(), kAudioUnitProperty_PresentPreset, + kAudioUnitScope_Global, 0, + &inData, sizeof (AUPreset)); +#if !TARGET_OS_IPHONE +#ifndef __LP64__ + if (result == kAudioUnitErr_InvalidProperty) { + result = AudioUnitSetProperty (AU(), kAudioUnitProperty_CurrentPreset, + kAudioUnitScope_Global, 0, + &inData, sizeof (AUPreset)); + } +#endif +#endif + return result; +} + +bool CAAudioUnit::HasCustomView () const +{ +#if !TARGET_OS_IPHONE + UInt32 dataSize = 0; + OSStatus result = -4/*unimpErr*/; +#ifndef __LP64__ + result = GetPropertyInfo(kAudioUnitProperty_GetUIComponentList, + kAudioUnitScope_Global, 0, + &dataSize, NULL); +#endif + if (result || !dataSize) { + dataSize = 0; + result = GetPropertyInfo(kAudioUnitProperty_CocoaUI, + kAudioUnitScope_Global, 0, + &dataSize, NULL); + if (result || !dataSize) + return false; + } + return true; +#else + return false; +#endif + +} + +OSStatus CAAudioUnit::GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 &outValue) const +{ + return mDataPtr ? mDataPtr->GetParameter (inID, scope, element, outValue) : paramErr; +} + +OSStatus CAAudioUnit::SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 value, UInt32 bufferOffsetFrames) +{ + return mDataPtr ? mDataPtr->SetParameter (inID, scope, element, value, bufferOffsetFrames) : paramErr; +} + +#if !TARGET_OS_IPHONE +OSStatus CAAudioUnit::MIDIEvent (UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame) +{ + return mDataPtr ? mDataPtr->MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame) : paramErr; +} + +OSStatus CAAudioUnit::StartNote (MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) +{ + return mDataPtr ? mDataPtr->StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams) + : paramErr; +} + +OSStatus CAAudioUnit::StopNote (MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame) +{ + return mDataPtr ? mDataPtr->StopNote (inGroupID, inNoteInstanceID, inOffsetSampleFrame) : paramErr; +} +#endif + + +#pragma mark __Render + +OSStatus CAAudioUnit::Render (AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData) +{ + return mDataPtr ? mDataPtr->Render (ioActionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData) : paramErr; +} + +#pragma mark __CAAUChanHelper + +CAAUChanHelper::CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope) + :mChans(NULL), mNumEls(0), mDidAllocate(false) +{ + UInt32 elCount; + if (inAU.GetElementCount (inScope, elCount)) return; + if (elCount > kStaticElCount) { + mChans = new UInt32[elCount]; + mDidAllocate = true; + memset (mChans, 0, sizeof(int) * elCount); + } else { + mChans = mStaticChans; + memset (mChans, 0, sizeof(int) * kStaticElCount); + } + for (unsigned int i = 0; i < elCount; ++i) { + UInt32 numChans; + if (inAU.NumberChannels (inScope, i, numChans)) return; + mChans[i] = numChans; + } + mNumEls = elCount; +} + +CAAUChanHelper::CAAUChanHelper(UInt32 inMaxElems) + : mNumEls(inMaxElems), mDidAllocate(false) +{ + if (inMaxElems > kStaticElCount) { + mChans = new UInt32[inMaxElems]; + mDidAllocate = true; + memset (mChans, 0, sizeof(int) * inMaxElems); + } else { + mChans = mStaticChans; + memset (mChans, 0, sizeof(int) * kStaticElCount); + } +} + +CAAUChanHelper::~CAAUChanHelper() +{ + if (mDidAllocate) delete [] mChans; +} + +CAAUChanHelper& CAAUChanHelper::operator= (const CAAUChanHelper &c) +{ + if (mDidAllocate) delete [] mChans; + if (c.mDidAllocate) { + mChans = new UInt32[c.mNumEls]; + mDidAllocate = true; + } else { + mDidAllocate = false; + mChans = mStaticChans; + } + memcpy (mChans, c.mChans, c.mNumEls * sizeof(int)); + + return *this; +} + + +#pragma mark __Print Utilities + +void CAAudioUnit::Print (FILE* file) const +{ + fprintf (file, "AudioUnit:%p\n", AU()); + if (IsValid()) { + fprintf (file, "\tnode=%ld\t", (long)GetAUNode()); Comp().Print (file); + } +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioUnit.h b/distrho/src/CoreAudio106/PublicUtility/CAAudioUnit.h new file mode 100755 index 00000000..c94c795f --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioUnit.h @@ -0,0 +1,417 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __CAAudioUnit_h__ +#define __CAAudioUnit_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include + #if !TARGET_OS_IPHONE + #include + #endif + #include +#else + #include + #include + #include + #include + #include + #include +#endif + +#include +#include "CAStreamBasicDescription.h" +#include "CAComponent.h" +#include "CAAudioChannelLayout.h" + +// defined below +class CAAUChanHelper; + +// These constructors will NOT throw exceptions - so "check" after creation if AU IsValid() +// The destructor will NOT automatically close the AU down +// This state should be managed by the Caller +// once closed, the unit represented by this object is no longer valid +// it is up to the user of this object to ensure its validity is in sync +// if it is removed from a graph + +// methods that can significantly change the state of the AU (like its format) are +// NOT const whereas those that don't change the externally related state of the AU are not const + +class CAAudioUnit { + enum { + paramErr = -50, + badComponentSelector = (long)0x80008002 + }; +public: + typedef std::vector ChannelTagVector; + typedef ChannelTagVector::iterator ChannelTagVectorIter; + +public: + CAAudioUnit () + : mDataPtr(0) {} + + CAAudioUnit (const AudioUnit& inUnit); + + CAAudioUnit (const AUNode &inNode, const AudioUnit& inUnit); + + CAAudioUnit (const CAAudioUnit& y) + : mDataPtr(0) { *this = y; } + + static OSStatus Open (const CAComponent& inComp, CAAudioUnit &outUnit); + + ~CAAudioUnit (); + + void Close (); + + + CAAudioUnit& operator= (const CAAudioUnit& y); + + bool operator== (const CAAudioUnit& y) const; + + bool operator== (const AudioUnit& y) const; + +#pragma mark __State Management + bool IsValid () const; + + AudioUnit AU() const; + operator AudioUnit () const { return AU(); } + + const CAComponent& Comp() const { return mComp; } + + bool FromAUGraph () const { return GetAUNode() != 0 && GetAUNode() != kCAAU_DoNotKnowIfAUNode; } + + AUNode GetAUNode () const; + operator AUNode () const { return GetAUNode(); } + +#pragma mark __API Wrapper + OSStatus Initialize() const { + return AudioUnitInitialize(AU()); + } + OSStatus Uninitialize() const { + return AudioUnitUninitialize(AU()); + } + OSStatus GetPropertyInfo(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element, + UInt32 *outDataSize, Boolean *outWritable) const + { + return AudioUnitGetPropertyInfo(AU(), propID, scope, element, outDataSize, outWritable); + } + OSStatus GetProperty(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element, + void *outData, UInt32 *ioDataSize) const + { + return AudioUnitGetProperty(AU(), propID, scope, element, outData, ioDataSize); + } + OSStatus SetProperty(AudioUnitPropertyID propID, AudioUnitScope scope, AudioUnitElement element, + const void *inData, UInt32 inDataSize) + { + return AudioUnitSetProperty(AU(), propID, scope, element, inData, inDataSize); + } + OSStatus SetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 value, UInt32 bufferOffsetFrames=0); + + OSStatus GetParameter(AudioUnitParameterID inID, AudioUnitScope scope, AudioUnitElement element, + Float32 &outValue) const; + + OSStatus Render (AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inOutputBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData); + + OSStatus Reset (AudioUnitScope scope, AudioUnitElement element) + { + return AudioUnitReset (AU(), scope, element); + } + OSStatus GlobalReset () + { + return AudioUnitReset (AU(), kAudioUnitScope_Global, 0); + } + + OSStatus AddRenderNotify (AURenderCallback inProc, void *inProcRefCon) + { + return AudioUnitAddRenderNotify (AU(), inProc, inProcRefCon); + } + + OSStatus RemoveRenderNotify (AURenderCallback inProc, void *inProcRefCon) + { + return AudioUnitRemoveRenderNotify (AU(), inProc, inProcRefCon); + } + + OSStatus AddPropertyListener (AudioUnitPropertyID inID, + AudioUnitPropertyListenerProc inProc, + void * inProcRefCon) + { + return AudioUnitAddPropertyListener (AU(), inID, inProc, inProcRefCon); + } + + OSStatus RemovePropertyListener (AudioUnitPropertyID inID, + AudioUnitPropertyListenerProc inProc, + void * inProcUserData); + +#if !TARGET_OS_IPHONE +// Fast dispatch support for MIDI Effects or Music Devices + OSStatus MIDIEvent (UInt32 inStatus, + UInt32 inData1, + UInt32 inData2, + UInt32 inOffsetSampleFrame); + + // uses the default VoiceForGroup value - this is the normal case + OSStatus StartNote (MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams) + { + return StartNote (kMusicNoteEvent_UseGroupInstrument, + inGroupID, outNoteInstanceID, + inOffsetSampleFrame, inParams); + } + + OSStatus StartNote (MusicDeviceInstrumentID inInstrument, + MusicDeviceGroupID inGroupID, + NoteInstanceID * outNoteInstanceID, + UInt32 inOffsetSampleFrame, + const MusicDeviceNoteParams * inParams); + + OSStatus StopNote (MusicDeviceGroupID inGroupID, + NoteInstanceID inNoteInstanceID, + UInt32 inOffsetSampleFrame); +#endif + +#pragma mark __Format Utilities + // typically you ask this about an AU + // These Questions are asking about Input and Output... + + // These ones just say whether an AU can do a single combination of channels + // and is fine if the AU has a single output (and if an input, a single input) + bool CanDo (int inChannelsInOut) const + { + return CanDo (inChannelsInOut, inChannelsInOut); + } + + bool CanDo ( int inChannelsIn, + int inChannelsOut) const; + + // This version does a more thorough test for ANY AU with ANY ins/outs + // you pass in the channel helper (for the current element count on that scope) + + bool CanDo ( const CAAUChanHelper &input, + const CAAUChanHelper &output) const; + + bool SupportsNumChannels () const; + + bool HasChannelLayouts (AudioUnitScope inScope, + AudioUnitElement inEl) const; + + OSStatus GetChannelLayoutTags (AudioUnitScope inScope, + AudioUnitElement inEl, + ChannelTagVector &outChannelVector) const; + + bool HasChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl) const; + + OSStatus GetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + CAAudioChannelLayout &outLayout) const; + + OSStatus SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + const CAAudioChannelLayout &inLayout); + + OSStatus SetChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl, + const AudioChannelLayout &inLayout, + UInt32 inSize); + + OSStatus ClearChannelLayout (AudioUnitScope inScope, + AudioUnitElement inEl); + + OSStatus GetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + AudioStreamBasicDescription &outFormat) const; + // if an AudioChannelLayout is either required or set, this call can fail + // and the SetChannelLayout call should be used to set the format + OSStatus SetFormat (AudioUnitScope inScope, + AudioUnitElement inEl, + const AudioStreamBasicDescription &inFormat); + + OSStatus GetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 &outRate) const; + OSStatus SetSampleRate (AudioUnitScope inScope, + AudioUnitElement inEl, + Float64 inRate); + + // this sets the sample rate on all in/out buses of the AU + OSStatus SetSampleRate (Float64 inSampleRate); + + OSStatus NumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 &outChans) const; + + OSStatus GetNumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 &outChans) const + { + return NumberChannels (inScope, inEl, outChans); + } + + OSStatus SetNumberChannels (AudioUnitScope inScope, + AudioUnitElement inEl, + UInt32 inChans); + + OSStatus IsElementCountWritable (AudioUnitScope inScope, bool &outWritable) const; + + OSStatus GetElementCount (AudioUnitScope inScope, UInt32 &outCount) const; + + OSStatus SetElementCount (AudioUnitScope inScope, UInt32 inCount); + + // value of -1 for outTotalNumChannels indicates no restriction on num channels + // for ex. the Matrix Mixer satisfies this (its in/out element count is writable, and can be set to + // any number of channels. + // outTotalNumChannels is only valid if method returns true... + bool HasDynamicInputs (SInt32 &outTotalNumChannels) const + { + return HasDynamicScope (kAudioUnitScope_Input, outTotalNumChannels); + } + + bool HasDynamicOutputs (SInt32 &outTotalNumChannels) const + { + return HasDynamicScope (kAudioUnitScope_Output, outTotalNumChannels); + } + + // here, if the in (or out) elements are dynamic, then you supply the number of elements + // you want on in (or out) scope, and the number of channels on each consecutive element + OSStatus ConfigureDynamicInput (UInt32 inNumElements, UInt32 *inChannelsPerElement, Float64 inSampleRate) + { + return ConfigureDynamicScope (kAudioUnitScope_Input, inNumElements, inChannelsPerElement, inSampleRate); + } + + OSStatus ConfigureDynamicOutput (UInt32 inNumElements, UInt32 *inChannelsPerElement, Float64 inSampleRate) + { + return ConfigureDynamicScope (kAudioUnitScope_Output, inNumElements, inChannelsPerElement, inSampleRate); + } + + bool CanBypass () const; + + bool GetBypass () const; + + OSStatus SetBypass (bool inBypass) const; + + Float64 Latency () const; + + // these calls just deal with the global preset state + // you could rescope them to deal with presets on the part scope + OSStatus GetAUPreset (CFPropertyListRef &outData) const; + + OSStatus SetAUPreset (CFPropertyListRef &inData); + + OSStatus SetAUPresetFromDocument (CFPropertyListRef &inData); + + OSStatus GetPresentPreset (AUPreset &outData) const; + + OSStatus SetPresentPreset (AUPreset &inData); + + bool HasCustomView () const; + +#pragma mark __Print + void Print () const { Print (stdout); } + void Print (FILE* file) const; + +private: + CAComponent mComp; + + class AUState; + AUState* mDataPtr; + + // this can throw - so wrap this up in a static that returns a result code... + CAAudioUnit (const CAComponent& inComp); + + bool HasDynamicScope (AudioUnitScope inScope, SInt32 &outTotalNumChannels) const; + OSStatus ConfigureDynamicScope (AudioUnitScope inScope, + UInt32 inNumElements, + UInt32 *inChannelsPerElement, + Float64 inSampleRate); + bool ValidateChannelPair (int inChannelsIn, + int inChannelsOut, + const AUChannelInfo * info, + UInt32 numChanInfo) const; + + bool ValidateDynamicScope (AudioUnitScope inScope, + SInt32 &outTotalNumChannels, + const AUChannelInfo * info, + UInt32 numInfo) const; + bool CheckOneSide (const CAAUChanHelper &inHelper, + bool checkOutput, + const AUChannelInfo *info, + UInt32 numInfo) const; + enum { + kCAAU_DoNotKnowIfAUNode = -1 + }; +}; + +class CAAUChanHelper { +public: + CAAUChanHelper() + : mChans(mStaticChans), mNumEls(0), mDidAllocate(false) + { + memset (mChans, 0, sizeof(UInt32) * kStaticElCount); + } + CAAUChanHelper(UInt32 inMaxElems); + CAAUChanHelper(const CAAudioUnit &inAU, AudioUnitScope inScope); + CAAUChanHelper (const CAAUChanHelper &c) + : mChans(mStaticChans), mNumEls(0), mDidAllocate(false) + { *this = c; } + + ~CAAUChanHelper(); + + CAAUChanHelper& operator= (const CAAUChanHelper &c); + + UInt32 * mChans; + UInt32 mNumEls; + +private: + enum { + kStaticElCount = 8 + }; + UInt32 mStaticChans[kStaticElCount]; + bool mDidAllocate; +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioUnitOutputCapturer.h b/distrho/src/CoreAudio106/PublicUtility/CAAudioUnitOutputCapturer.h new file mode 100755 index 00000000..80c993ee --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioUnitOutputCapturer.h @@ -0,0 +1,137 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __CAAudioUnitOutputCapturer_h__ +#define __CAAudioUnitOutputCapturer_h__ + +#include + +/* + Class to capture output from an AudioUnit for analysis. + + example: + + CFURL fileurl = CFURLCreateWithFileSystemPath(NULL, CFSTR("/tmp/recording.caf"), kCFURLPOSIXPathStyle, false); + + CAAudioUnitOutputCapturer captor(someAU, fileurl, 'caff', anASBD); + + { + captor.Start(); + ... + captor.Stop(); + } // can repeat + + captor.Close(); // can be omitted; happens automatically from destructor +*/ + +class CAAudioUnitOutputCapturer { +public: + enum { noErr = 0 }; + + CAAudioUnitOutputCapturer(AudioUnit au, CFURLRef outputFileURL, AudioFileTypeID fileType, const AudioStreamBasicDescription &format, UInt32 busNumber = 0) : + mFileOpen(false), + mClientFormatSet(false), + mAudioUnit(au), + mExtAudioFile(NULL), + mBusNumber (busNumber) + { + CFShow(outputFileURL); + OSStatus err = ExtAudioFileCreateWithURL(outputFileURL, fileType, &format, NULL, kAudioFileFlags_EraseFile, &mExtAudioFile); + if (!err) + mFileOpen = true; + } + + void Start() { + if (mFileOpen) { + if (!mClientFormatSet) { + AudioStreamBasicDescription clientFormat; + UInt32 size = sizeof(clientFormat); + AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, mBusNumber, &clientFormat, &size); + ExtAudioFileSetProperty(mExtAudioFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat); + mClientFormatSet = true; + } + ExtAudioFileWriteAsync(mExtAudioFile, 0, NULL); // initialize async writes + AudioUnitAddRenderNotify(mAudioUnit, RenderCallback, this); + } + } + + void Stop() { + if (mFileOpen) + AudioUnitRemoveRenderNotify(mAudioUnit, RenderCallback, this); + } + + void Close() { + if (mExtAudioFile) { + ExtAudioFileDispose(mExtAudioFile); + mExtAudioFile = NULL; + } + } + + ~CAAudioUnitOutputCapturer() { + Close(); + } + +private: + static OSStatus RenderCallback( void * inRefCon, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData) + { + if (*ioActionFlags & kAudioUnitRenderAction_PostRender) { + CAAudioUnitOutputCapturer *This = (CAAudioUnitOutputCapturer *)inRefCon; + static int TEMP_kAudioUnitRenderAction_PostRenderError = (1 << 8); + if (This->mBusNumber == inBusNumber && !(*ioActionFlags & TEMP_kAudioUnitRenderAction_PostRenderError)) { + OSStatus result = ExtAudioFileWrite(This->mExtAudioFile, inNumberFrames, ioData); + if (result) DebugMessageN1("ERROR WRITING FRAMES: %d\n", result); + } + } + return noErr; + } + + bool mFileOpen; + bool mClientFormatSet; + AudioUnit mAudioUnit; + ExtAudioFileRef mExtAudioFile; + UInt32 mBusNumber; +}; + +#endif // __CAAudioUnitOutputCapturer_h__ diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioValueRange.cpp b/distrho/src/CoreAudio106/PublicUtility/CAAudioValueRange.cpp new file mode 100755 index 00000000..f3374bb5 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioValueRange.cpp @@ -0,0 +1,244 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAAudioValueRange.h" + +// Standard Library +#include + +//================================================================================================== +// CAAudioValueRange +//================================================================================================== + +Float64 CAAudioValueRange::PickCommonSampleRate(const AudioValueRange& inRange) +{ + // This routine will pick a "common" sample rate from the give range of rates or the maximum + // if no common rates can be found. It assumes that inRange contains a continuous range of + // sample rates. + Float64 theAnswer = inRange.mMaximum; + + if(ContainsValue(inRange, 44100.0)) + { + theAnswer = 44100.0; + } + else if(ContainsValue(inRange, 48000.0)) + { + theAnswer = 48000.0; + } + else if(ContainsValue(inRange, 96000.0)) + { + theAnswer = 96000.0; + } + else if(ContainsValue(inRange, 88200.0)) + { + theAnswer = 88200.0; + } + else if(ContainsValue(inRange, 64000.0)) + { + theAnswer = 64000.0; + } + else if(ContainsValue(inRange, 32000.0)) + { + theAnswer = 32000.0; + } + else if(ContainsValue(inRange, 24000.0)) + { + theAnswer = 24000.0; + } + else if(ContainsValue(inRange, 22050.0)) + { + theAnswer = 22050.0; + } + else if(ContainsValue(inRange, 16000.0)) + { + theAnswer = 16000.0; + } + else if(ContainsValue(inRange, 12000.0)) + { + theAnswer = 12000.0; + } + else if(ContainsValue(inRange, 11025.0)) + { + theAnswer = 11025.0; + } + else if(ContainsValue(inRange, 8000.0)) + { + theAnswer = 8000.0; + } + + return theAnswer; +} + +bool CAAudioValueRange::Intersection(const AudioValueRange& x, const AudioValueRange& y, AudioValueRange& outRange) +{ + bool isNonEmpty; + if(!IsStrictlyLessThan(x, y) && !IsStrictlyGreaterThan(x, y)) + { + outRange.mMinimum = std::max(x.mMinimum, y.mMinimum); + outRange.mMaximum = std::min(x.mMaximum, y.mMaximum); + isNonEmpty = true; + } + else + { + outRange.mMinimum = 0; + outRange.mMaximum = 0; + isNonEmpty = false; + } + return isNonEmpty; +} + +bool CAAudioValueRange::Union(const AudioValueRange& x, const AudioValueRange& y, AudioValueRange& outRange) +{ + bool isDisjoint; + if(!IsStrictlyLessThan(x, y) && !IsStrictlyGreaterThan(x, y)) + { + outRange.mMinimum = std::min(x.mMinimum, y.mMinimum); + outRange.mMaximum = std::max(x.mMaximum, y.mMaximum); + isDisjoint = false; + } + else + { + outRange.mMinimum = 0; + outRange.mMaximum = 0; + isDisjoint = true; + } + return isDisjoint; +} + +void CAAudioValueRange_ComputeUnion(const AudioValueRange& inRange, const CAAudioValueRangeList& inRangeList, CAAudioValueRangeList& outUnion) +{ + // this method assumes that the ranges in inRangeList are disjoint and that they are sorted from low to high and + outUnion.clear(); + + // start at the beginning of inRangeList + CAAudioValueRangeList::const_iterator theIterator = inRangeList.begin(); + + // iterate through inRangeList and add all the ranges that are strictly less than inRange + while((theIterator != inRangeList.end()) && CAAudioValueRange::IsStrictlyLessThan(*theIterator, inRange)) + { + // put this range in the union + outUnion.push_back(*theIterator); + + // go to the next one + std::advance(theIterator, 1); + } + + if(theIterator != inRangeList.end()) + { + if(!CAAudioValueRange::IsStrictlyGreaterThan(*theIterator, inRange)) + { + // inRange intersects the range that theIterator points at, but might actually intersect several contiguous ranges + + // initialize the starting point, noting that we can skip the current one since we already know it's in the intersection + CAAudioValueRangeList::const_iterator theGreaterIterator = theIterator; + std::advance(theGreaterIterator, 1); + + // iterate until we find a range that is strictly greater than inRange + while((theGreaterIterator != inRangeList.end()) && !CAAudioValueRange::IsStrictlyGreaterThan(*theGreaterIterator, inRange)) + { + // go to the next one + std::advance(theGreaterIterator, 1); + } + + // theGreaterIterator now points at either one past the highest range in the intersection or the end of the vector + // Either way, we have to adjust it to point at the true highest range in the intersection + std::advance(theGreaterIterator, -1); + + // now theIterator points at the lowest range in the intersection and theGreaterIterator points at the highest + // so we can compute the coagulated range + AudioValueRange theCoagulation; + theCoagulation.mMinimum = std::min(theIterator->mMinimum, inRange.mMinimum); + theCoagulation.mMaximum = std::max(theGreaterIterator->mMaximum, inRange.mMaximum); + + // add the coagulation to the union + outUnion.push_back(theCoagulation); + + // adjust theIterator to point at the next range for processing + theIterator = theGreaterIterator; + std::advance(theIterator, 1); + } + else + { + // the range theIterator points at is strictly greater than inRange, so insert inRange in front of it and we're done + outUnion.push_back(inRange); + } + + // we need to now copy the remaining higher ranges in inRangeList into the union + while(theIterator != inRangeList.end()) + { + // put this range in the union + outUnion.push_back(*theIterator); + + // go to the next one + std::advance(theIterator, 1); + } + } + else + { + // inRange is larger than all of the ranges in inRangeList, so just add it onto the end of the union and we're done + // This is also the case if inRangeList is empty + outUnion.push_back(inRange); + } +} + +void CAAudioValueRange_ComputeIntersection(const AudioValueRange& inRange, const CAAudioValueRangeList& inRangeList, CAAudioValueRangeList& outIntersections) +{ + outIntersections.clear(); + // iterate through the list and compute the intersections + CAAudioValueRangeList::const_iterator theIterator = inRangeList.begin(); + while(theIterator != inRangeList.end()) + { + // figure out if the range intersects + AudioValueRange theIntersection; + if(CAAudioValueRange::Intersection(inRange, *theIterator, theIntersection)) + { + // it does, so add the intersection to the return list + outIntersections.push_back(theIntersection); + } + + // go to the next one + std::advance(theIterator, 1); + } +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAudioValueRange.h b/distrho/src/CoreAudio106/PublicUtility/CAAudioValueRange.h new file mode 100755 index 00000000..cbb643e9 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAudioValueRange.h @@ -0,0 +1,114 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CAAudioValueRange_h__) +#define __CAAudioValueRange_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif +// Standard Library Includes +#include +#include + +//============================================================================= +// CAAudioValueRange +//============================================================================= + +struct CAAudioValueRange +: + public AudioValueRange +{ + +// Construction/Destruction +public: + CAAudioValueRange() { mMinimum = 0.0; mMaximum = 0.0; } + CAAudioValueRange(const AudioValueRange& v) { mMinimum = v.mMinimum; mMaximum = v.mMaximum; } + CAAudioValueRange(Float64 inMinimum, Float64 inMaximum) { mMinimum = inMinimum; mMaximum = inMaximum; } + +// Assignment +public: + CAAudioValueRange& operator=(const AudioValueRange& v) { mMinimum = v.mMinimum; mMaximum = v.mMaximum; return *this; } + +// Operations +public: + static bool ContainsValue(const AudioValueRange& inRange, Float64 inValue) { return (inValue >= inRange.mMinimum) && (inValue <= inRange.mMaximum); } + static Float64 PickCommonSampleRate(const AudioValueRange& inRange); + static bool IsStrictlyLessThan(const AudioValueRange& x, const AudioValueRange& y) { return x.mMaximum < y.mMinimum; } + static bool IsStrictlyGreaterThan(const AudioValueRange& x, const AudioValueRange& y) { return x.mMinimum > y.mMaximum; } + static bool IsStrictlyContainedBy(const AudioValueRange& x, const AudioValueRange& y) { return (x.mMinimum >= y.mMinimum) && (x.mMaximum <= y.mMaximum); } + static bool OverlapsLow(const AudioValueRange& x, const AudioValueRange& y) { return (x.mMinimum < y.mMinimum) && (x.mMaximum >= y.mMinimum) && (x.mMaximum <= y.mMaximum); } + static bool OverlapsHigh(const AudioValueRange& x, const AudioValueRange& y) { return (x.mMinimum >= y.mMinimum) && (x.mMinimum <= y.mMaximum) && (x.mMaximum > y.mMaximum); } + static bool Intersection(const AudioValueRange& x, const AudioValueRange& y, AudioValueRange& outRange); + static bool Union(const AudioValueRange& x, const AudioValueRange& y, AudioValueRange& outRange); + +// STL Helpers +public: + struct LessThan + : + public std::binary_function + { + bool operator()(const AudioValueRange& x, const AudioValueRange& y) const + { + return x.mMinimum < y.mMinimum; + } + }; + +}; + +inline bool operator<(const AudioValueRange& x, const AudioValueRange& y) { return x.mMinimum < y.mMinimum; } +inline bool operator==(const AudioValueRange& x, const AudioValueRange& y) { return (x.mMinimum == y.mMinimum) && (x.mMaximum == y.mMaximum); } +inline bool operator!=(const AudioValueRange& x, const AudioValueRange& y) { return !(x == y); } +inline bool operator<=(const AudioValueRange& x, const AudioValueRange& y) { return (x < y) || (x == y); } +inline bool operator>=(const AudioValueRange& x, const AudioValueRange& y) { return !(x < y); } +inline bool operator>(const AudioValueRange& x, const AudioValueRange& y) { return !((x < y) || (x == y)); } + +typedef std::vector CAAudioValueRangeList; +void CAAudioValueRange_ComputeUnion(const AudioValueRange& inRange, const CAAudioValueRangeList& inRangeList, CAAudioValueRangeList& outUnion); +void CAAudioValueRange_ComputeIntersection(const AudioValueRange& inRange, const CAAudioValueRangeList& inRangeList, CAAudioValueRangeList& outIntersections); + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAAutoDisposer.h b/distrho/src/CoreAudio106/PublicUtility/CAAutoDisposer.h new file mode 100755 index 00000000..e060d6fb --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAAutoDisposer.h @@ -0,0 +1,502 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/PublicUtility/CABitOperations.h b/distrho/src/CoreAudio106/PublicUtility/CABitOperations.h new file mode 100755 index 00000000..f7be2882 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CABitOperations.h @@ -0,0 +1,192 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef _CABitOperations_h_ +#define _CABitOperations_h_ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + //#include + #include +#else +// #include + #include "CFBase.h" +#endif +#include + +// return whether a number is a power of two +inline UInt32 IsPowerOfTwo(UInt32 x) +{ + return (x & (x-1)) == 0; +} + +// count the leading zeroes in a word +#ifdef __MWERKS__ + +// Metrowerks Codewarrior. powerpc native count leading zeroes instruction: +#define CountLeadingZeroes(x) ((int)__cntlzw((unsigned int)x)) + +#elif TARGET_OS_WIN32 + +static int CountLeadingZeroes( int arg ) +{ + __asm{ + bsr eax, arg + mov ecx, 63 + cmovz eax, ecx + xor eax, 31 + } + return arg; +} + +#else + +static __inline__ int CountLeadingZeroes(int arg) { +#if TARGET_CPU_PPC || TARGET_CPU_PPC64 + __asm__ volatile("cntlzw %0, %1" : "=r" (arg) : "r" (arg)); + return arg; +#elif TARGET_CPU_X86 || TARGET_CPU_X86_64 + __asm__ volatile( + "bsrl %0, %0\n\t" + "movl $63, %%ecx\n\t" + "cmove %%ecx, %0\n\t" + "xorl $31, %0" + : "=r" (arg) + : "0" (arg) : "%ecx" + ); + return arg; +#else + if (arg == 0) return 32; + return __builtin_clz(arg); +#endif +} + +#endif + +// count trailing zeroes +inline UInt32 CountTrailingZeroes(UInt32 x) +{ + return 32 - CountLeadingZeroes(~x & (x-1)); +} + +// count leading ones +inline UInt32 CountLeadingOnes(UInt32 x) +{ + return CountLeadingZeroes(~x); +} + +// count trailing ones +inline UInt32 CountTrailingOnes(UInt32 x) +{ + return 32 - CountLeadingZeroes(x & (~x-1)); +} + +// number of bits required to represent x. +inline UInt32 NumBits(UInt32 x) +{ + return 32 - CountLeadingZeroes(x); +} + +// base 2 log of next power of two greater or equal to x +inline UInt32 Log2Ceil(UInt32 x) +{ + return 32 - CountLeadingZeroes(x - 1); +} + +// next power of two greater or equal to x +inline UInt32 NextPowerOfTwo(UInt32 x) +{ + return 1L << Log2Ceil(x); +} + +// 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; +} + +// counting the zero bits in a word +inline UInt32 CountZeroes(UInt32 x) +{ + return CountOnes(~x); +} + +// return the bit position (0..31) of the least significant bit +inline UInt32 LSBitPos(UInt32 x) +{ + return CountTrailingZeroes(x & -(SInt32)x); +} + +// isolate the least significant bit +inline UInt32 LSBit(UInt32 x) +{ + return x & -(SInt32)x; +} + +// return the bit position (0..31) of the most significant bit +inline UInt32 MSBitPos(UInt32 x) +{ + return 31 - CountLeadingZeroes(x); +} + +// isolate the most significant bit +inline UInt32 MSBit(UInt32 x) +{ + return 1UL << MSBitPos(x); +} + +// Division optimized for power of 2 denominators +inline UInt32 DivInt(UInt32 numerator, UInt32 denominator) +{ + if(IsPowerOfTwo(denominator)) + return numerator >> (31 - CountLeadingZeroes(denominator)); + else + return numerator/denominator; +} + +#endif + diff --git a/distrho/src/CoreAudio106/PublicUtility/CABool.h b/distrho/src/CoreAudio106/PublicUtility/CABool.h new file mode 100755 index 00000000..04c8a2f4 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CABool.h @@ -0,0 +1,82 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CABool_h__) +#define __CABool_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#include "CADebugMacros.h" +#include "CAException.h" + +//============================================================================= +// CABool +// +// This class implements a boolean value that has a third state that marks +// it as uninitialized. Accessing the value of an instance of this class that +// is uninitialized will throw an exception. +//============================================================================= + +class CABool +{ + +// Construction/Destruction +public: + CABool() : mValue(-1) {} + CABool(bool inValue) : mValue(inValue ? 1 : 0) {} + CABool(const CABool& inValue) : mValue(inValue.mValue) {} + ~CABool() {} + + CABool& operator=(bool inValue) { mValue = inValue; return *this; } + CABool& operator=(const CABool& inValue) { mValue = inValue.mValue; return *this; } + + operator bool() const { ThrowIf(mValue == -1, CAException('nope'), "CABool: uninitialized"); return mValue != 0; } + bool IsInitialized() const { return mValue != -1; } + void Uninitialize() { mValue = -1; } + +private: + SInt32 mValue; + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CABufferList.cpp b/distrho/src/CoreAudio106/PublicUtility/CABufferList.cpp new file mode 100755 index 00000000..a7963490 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CABufferList.cpp @@ -0,0 +1,252 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CABufferList.h" +#include "CAByteOrder.h" + +void CABufferList::AllocateBuffers(UInt32 nBytes) +{ + if (nBytes <= GetNumBytes()) return; + + if (mNumberBuffers > 1) + // align successive buffers for Altivec and to take alternating + // cache line hits by spacing them by odd multiples of 16 + nBytes = ((nBytes + 15) & ~15) | 16; + UInt32 memorySize = nBytes * mNumberBuffers; + Byte *newMemory = new Byte[memorySize], *p = newMemory; + memset(newMemory, 0, memorySize); // get page faults now, not later + + AudioBuffer *buf = mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++buf) { + if (buf->mData != NULL && buf->mDataByteSize > 0) + // preserve existing buffer contents + memcpy(p, buf->mData, buf->mDataByteSize); + buf->mDataByteSize = nBytes; + buf->mData = p; + p += nBytes; + } + Byte *oldMemory = mBufferMemory; + mBufferMemory = newMemory; + delete[] oldMemory; +} + +void CABufferList::AllocateBuffersAndCopyFrom(UInt32 nBytes, CABufferList *inSrcList, CABufferList *inSetPtrList) +{ + if (mNumberBuffers != inSrcList->mNumberBuffers) return; + if (mNumberBuffers != inSetPtrList->mNumberBuffers) return; + if (nBytes <= GetNumBytes()) { + CopyAllFrom(inSrcList, inSetPtrList); + return; + } + inSetPtrList->VerifyNotTrashingOwnedBuffer(); + UInt32 fromByteSize = inSrcList->GetNumBytes(); + + if (mNumberBuffers > 1) + // align successive buffers for Altivec and to take alternating + // cache line hits by spacing them by odd multiples of 16 + nBytes = ((nBytes + 15) & ~15) | 16; + UInt32 memorySize = nBytes * mNumberBuffers; + Byte *newMemory = new Byte[memorySize], *p = newMemory; + memset(newMemory, 0, memorySize); // make buffer "hot" + + AudioBuffer *buf = mBuffers; + AudioBuffer *ptrBuf = inSetPtrList->mBuffers; + AudioBuffer *srcBuf = inSrcList->mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++buf, ++ptrBuf, ++srcBuf) { + if (srcBuf->mData != NULL && srcBuf->mDataByteSize > 0) + // preserve existing buffer contents + memmove(p, srcBuf->mData, srcBuf->mDataByteSize); + buf->mDataByteSize = nBytes; + buf->mData = p; + ptrBuf->mDataByteSize = srcBuf->mDataByteSize; + ptrBuf->mData = p; + p += nBytes; + } + Byte *oldMemory = mBufferMemory; + mBufferMemory = newMemory; + if (inSrcList != inSetPtrList) + inSrcList->BytesConsumed(fromByteSize); + delete[] oldMemory; +} + +void CABufferList::DeallocateBuffers() +{ + AudioBuffer *buf = mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++buf) { + buf->mData = NULL; + buf->mDataByteSize = 0; + } + if (mBufferMemory != NULL) { + delete[] mBufferMemory; + mBufferMemory = NULL; + } + +} + +static void show(const AudioBufferList &abl, int framesToPrint, int wordSize, const char *label, const char *fmtstr=NULL) +{ + printf("%s %p (%d fr%s):\n", label ? label : "AudioBufferList", &abl, framesToPrint, fmtstr ? fmtstr : ""); + const AudioBuffer *buf = abl.mBuffers; + for (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++buf) { + printf(" [%2d] %5dbytes %dch @ %p", (int)i, (int)buf->mDataByteSize, (int)buf->mNumberChannels, buf->mData); + if (framesToPrint && buf->mData != NULL) { + printf(":"); + Byte *p = (Byte *)buf->mData; + for (int j = framesToPrint * buf->mNumberChannels; --j >= 0; ) + switch (wordSize) { + case 0: // native float + printf(" %6.3f", *(Float32 *)p); + p += sizeof(Float32); + break; + // positive: big endian + case 1: + case -1: + printf(" %02X", *p); + p += 1; + break; + case 2: + printf(" %04X", CFSwapInt16BigToHost(*(UInt16 *)p)); + p += 2; + break; + case 3: + printf(" %06X", (p[0] << 16) | (p[1] << 8) | p[2]); + p += 3; + break; + case 4: + printf(" %08X", (unsigned int)CFSwapInt32BigToHost(*(UInt32 *)p)); + p += 4; + break; + case 10: + printf(" %6.3f", CASwapFloat32BigToHost(*(Float32 *)p)); + p += sizeof(Float32); + break; + case -2: + printf(" %04X", CFSwapInt16LittleToHost(*(UInt16 *)p)); + p += 2; + break; + case -3: + printf(" %06X", (p[2] << 16) | (p[1] << 8) | p[0]); + p += 3; + break; + case -4: + printf(" %08X", (unsigned int)CFSwapInt32LittleToHost(*(UInt32 *)p)); + p += 4; + break; + case -10: + printf(" %6.3f", CASwapFloat32LittleToHost(*(Float32 *)p)); + p += sizeof(Float32); + break; + } + } + printf("\n"); + } +} + +void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, const AudioStreamBasicDescription &asbd, const char *label) +{ + CAStreamBasicDescription fmt(asbd); + int wordSize = 1; + char fmtstr[80] = { 0 }; + + if (fmt.mFormatID == kAudioFormatLinearPCM) { + if (fmt.mFormatFlags & kLinearPCMFormatFlagIsFloat) { + if (fmt.mBitsPerChannel == 32) { + if (fmt.mFormatFlags & kLinearPCMFormatFlagIsBigEndian) { + wordSize = 10; + strcpy(fmtstr, ", BEF"); + } else { + wordSize = -10; + strcpy(fmtstr, ", LEF"); + } + } + } else { + wordSize = fmt.SampleWordSize(); + if (wordSize > 0) { +#if CA_PREFER_FIXED_POINT + int fracbits = (asbd.mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift; + if (fracbits > 0) + sprintf(fmtstr, ", %d.%d-bit", (int)asbd.mBitsPerChannel - fracbits, fracbits); + else +#endif + sprintf(fmtstr, ", %d-bit", (int)asbd.mBitsPerChannel); + + if (!(fmt.mFormatFlags & kLinearPCMFormatFlagIsBigEndian)) { + wordSize = -wordSize; + strcat(fmtstr, " LEI"); + } else { + strcat(fmtstr, " BEI"); + } + } + } + } + show(abl, framesToPrint, wordSize, label, fmtstr); +} + +void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, int wordSize, const char *label) +{ + show(abl, framesToPrint, wordSize, label); +} + +extern "C" void CAShowAudioBufferList(const AudioBufferList *abl, int framesToPrint, int wordSize) +{ + show(*abl, framesToPrint, wordSize, NULL); +} + +// if the return result is odd, there was a null buffer. +extern "C" int CrashIfClientProvidedBogusAudioBufferList(const AudioBufferList *abl, bool nullok) +{ + const AudioBuffer *buf = abl->mBuffers, *bufend = buf + abl->mNumberBuffers; + int sum = 0; // defeat attempts by the compiler to optimize away the code that touches the buffers + int anyNull = 0; + for ( ; buf < bufend; ++buf) { + const int *p = (const int *)buf->mData; + if (p == NULL) { + anyNull = 1; + if (nullok) continue; + } + unsigned datasize = buf->mDataByteSize; + if (datasize >= sizeof(int)) { + sum += p[0]; + sum += p[datasize / sizeof(int) - 1]; + } + } + return anyNull | (sum & ~1); +} + diff --git a/distrho/src/CoreAudio106/PublicUtility/CABufferList.h b/distrho/src/CoreAudio106/PublicUtility/CABufferList.h new file mode 100755 index 00000000..0d3b88b8 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CABufferList.h @@ -0,0 +1,298 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __CABufferList_h__ +#define __CABufferList_h__ + +#include +#include "CAStreamBasicDescription.h" +#include "CAXException.h" + +void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, const AudioStreamBasicDescription &fmt, const char *label=NULL); +void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, int wordSize, const char *label=NULL); +extern "C" void CAShowAudioBufferList(const AudioBufferList *abl, int framesToPrint, int wordSize); +extern "C" int CrashIfClientProvidedBogusAudioBufferList(const AudioBufferList *abl, bool nullOK=false); + +/* ____________________________________________________________________________ +// CABufferList - variable length buffer list + + This class is designed for use in non-simplistic cases. For AudioUnits, AUBufferList + is preferred. + + CABufferList can be used in one of two ways: + - as mutable pointers into non-owned memory + - as an immutable array of buffers (owns its own memory). + + All buffers are assumed to have the same format (number of channels, word size), so that + we can assume their mDataByteSizes are all the same. +____________________________________________________________________________ */ +class CABufferList { +public: + void * operator new(size_t /*size*/, int nBuffers) { + return ::operator new(sizeof(CABufferList) + (nBuffers-1) * sizeof(AudioBuffer)); + } + static CABufferList * New(const char *name, const CAStreamBasicDescription &format) + { + UInt32 numBuffers = format.NumberChannelStreams(), channelsPerBuffer = format.NumberInterleavedChannels(); + return new(numBuffers) CABufferList(name, numBuffers, channelsPerBuffer); + } + +protected: + CABufferList(const char *name, UInt32 numBuffers, UInt32 channelsPerBuffer) : + mName(name), + mBufferMemory(NULL) + { + //XAssert(numBuffers > 0 /*&& channelsPerBuffer > 0*/); + mNumberBuffers = numBuffers; + AudioBuffer *buf = mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++buf) { + buf->mNumberChannels = channelsPerBuffer; + buf->mDataByteSize = 0; + buf->mData = NULL; + } + } + +public: + ~CABufferList() + { + if (mBufferMemory) + delete[] mBufferMemory; + } + + const char * Name() { return mName; } + + const AudioBufferList & GetBufferList() const { return *(AudioBufferList *)&mNumberBuffers; } + + AudioBufferList & GetModifiableBufferList() + { + VerifyNotTrashingOwnedBuffer(); + return _GetBufferList(); + } + + UInt32 GetNumberBuffers() const { return mNumberBuffers; } + + UInt32 GetNumBytes() const + { + return mBuffers[0].mDataByteSize; + } + + void SetBytes(UInt32 nBytes, void *data) + { + VerifyNotTrashingOwnedBuffer(); + XAssert(mNumberBuffers == 1); + mBuffers[0].mDataByteSize = nBytes; + mBuffers[0].mData = data; + } + + void CopyAllFrom(CABufferList *srcbl, CABufferList *ptrbl) + // copies bytes from srcbl + // make ptrbl reflect the length copied + // note that srcbl may be same as ptrbl! + { + // Note that this buffer *can* own memory and its pointers/lengths are not + // altered; only its buffer contents, which are copied from srcbl. + // The pointers/lengths in ptrbl are updated to reflect the addresses/lengths + // of the copied data, and srcbl's contents are consumed. + ptrbl->VerifyNotTrashingOwnedBuffer(); + UInt32 nBytes = srcbl->GetNumBytes(); + AudioBuffer *mybuf = mBuffers, *srcbuf = srcbl->mBuffers, + *ptrbuf = ptrbl->mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++mybuf, ++srcbuf, ++ptrbuf) { + memmove(mybuf->mData, srcbuf->mData, srcbuf->mDataByteSize); + ptrbuf->mData = mybuf->mData; + ptrbuf->mDataByteSize = srcbuf->mDataByteSize; + } + if (srcbl != ptrbl) + srcbl->BytesConsumed(nBytes); + } + + void AppendFrom(CABufferList *blp, UInt32 nBytes) + { + VerifyNotTrashingOwnedBuffer(); + AudioBuffer *mybuf = mBuffers, *srcbuf = blp->mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++mybuf, ++srcbuf) { + XAssert(nBytes <= srcbuf->mDataByteSize); + memcpy((Byte *)mybuf->mData + mybuf->mDataByteSize, srcbuf->mData, nBytes); + mybuf->mDataByteSize += nBytes; + } + blp->BytesConsumed(nBytes); + } + + void PadWithZeroes(UInt32 desiredBufferSize) + // for cases where an algorithm (e.g. SRC) requires some + // padding to create silence following end-of-file + { + VerifyNotTrashingOwnedBuffer(); + if (GetNumBytes() > desiredBufferSize) return; + AudioBuffer *buf = mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++buf) { + memset((Byte *)buf->mData + buf->mDataByteSize, 0, desiredBufferSize - buf->mDataByteSize); + buf->mDataByteSize = desiredBufferSize; + } + } + + void SetToZeroes(UInt32 nBytes) + { + VerifyNotTrashingOwnedBuffer(); + AudioBuffer *buf = mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++buf) { + memset((Byte *)buf->mData, 0, nBytes); + buf->mDataByteSize = nBytes; + } + } + + void Reset() + { + DeallocateBuffers(); + } + + Boolean SameDataAs(const CABufferList* anotherBufferList) + { + // check to see if two buffer lists point to the same memory. + if (mNumberBuffers != anotherBufferList->mNumberBuffers) return false; + + for (UInt32 i = 0; i < mNumberBuffers; ++i) { + if (mBuffers[i].mData != anotherBufferList->mBuffers[i].mData) return false; + } + return true; + } + + void BytesConsumed(UInt32 nBytes) + // advance buffer pointers, decrease buffer sizes + { + VerifyNotTrashingOwnedBuffer(); + AudioBuffer *buf = mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++buf) { + XAssert(nBytes <= buf->mDataByteSize); + buf->mData = (Byte *)buf->mData + nBytes; + buf->mDataByteSize -= nBytes; + } + } + + void SetFrom(const AudioBufferList *abl) + { + VerifyNotTrashingOwnedBuffer(); + memcpy(&_GetBufferList(), abl, (char *)&abl->mBuffers[abl->mNumberBuffers] - (char *)abl); + } + + void SetFrom(const CABufferList *blp) + { + SetFrom(&blp->GetBufferList()); + } + + void SetFrom(const AudioBufferList *abl, UInt32 nBytes) + { + VerifyNotTrashingOwnedBuffer(); + AudioBuffer *mybuf = mBuffers; + const AudioBuffer *srcbuf = abl->mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++mybuf, ++srcbuf) { + mybuf->mNumberChannels = srcbuf->mNumberChannels; + mybuf->mDataByteSize = nBytes; + mybuf->mData = srcbuf->mData; + } + } + + void SetFrom(const CABufferList *blp, UInt32 nBytes) + { + SetFrom(&blp->GetBufferList(), nBytes); + } + + AudioBufferList * ToAudioBufferList(AudioBufferList *abl) const + { + memcpy(abl, &GetBufferList(), (char *)&abl->mBuffers[mNumberBuffers] - (char *)abl); + return abl; + } + + void AllocateBuffers(UInt32 nBytes); + void AllocateBuffersAndCopyFrom(UInt32 nBytes, CABufferList *inCopyFromList, CABufferList *inSetPtrList); + + void DeallocateBuffers(); + + void UseExternalBuffer(Byte *ptr, UInt32 nBytes); + + void AdvanceBufferPointers(UInt32 nBytes) + // this is for bufferlists that function simply as + // an array of pointers into another bufferlist, being advanced, + // as in RenderOutput implementations + { + VerifyNotTrashingOwnedBuffer(); + AudioBuffer *buf = mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++buf) { + buf->mData = (Byte *)buf->mData + nBytes; + buf->mDataByteSize -= nBytes; + } + } + + void SetNumBytes(UInt32 nBytes) + { + VerifyNotTrashingOwnedBuffer(); + AudioBuffer *buf = mBuffers; + for (UInt32 i = mNumberBuffers; i--; ++buf) + buf->mDataByteSize = nBytes; + } + + void Print(const char *label=NULL, int nframes=0, int wordSize=0) const + { + if (label == NULL) + label = mName; + printf("%s - ", label); + CAShowAudioBufferList(&GetBufferList(), nframes, wordSize); + if (mBufferMemory) + printf(" owned memory @ 0x%p:\n", mBufferMemory); + } + +protected: + AudioBufferList & _GetBufferList() { return *(AudioBufferList *)&mNumberBuffers; } // use with care + // if we make this public, then we lose ability to call VerifyNotTrashingOwnedBuffer + void VerifyNotTrashingOwnedBuffer() + { + // This needs to be called from places where we are modifying the buffer list. + // It's an error to modify the buffer pointers or lengths if we own the buffer memory. + XAssert(mBufferMemory == NULL); + } + + const char * mName; // for debugging + Byte * mBufferMemory; + // the rest must exactly mirror the structure of AudioBufferList + UInt32 mNumberBuffers; + AudioBuffer mBuffers[1]; +}; + +#endif // __CABufferList_h__ diff --git a/distrho/src/CoreAudio106/PublicUtility/CABundleLocker.cpp b/distrho/src/CoreAudio106/PublicUtility/CABundleLocker.cpp new file mode 100755 index 00000000..43dabd0e --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CABundleLocker.cpp @@ -0,0 +1,78 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CABundleLocker.h" +#include + +/* +some bundle operations are not thread safe, notably CFCopyLocalizedStringFromTableInBundle +*/ + +static pthread_mutex_t sCABundleLocker = PTHREAD_MUTEX_INITIALIZER; + +#define RECURSIVE_LOCK 0 + +#if RECURSIVE_LOCK +static pthread_once_t sOnce = PTHREAD_ONCE_INIT; + +static void InitCABundleLocker() +{ + // 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(&sCABundleLocker, &attr); + pthread_mutexattr_destroy(&attr); +} +#endif + +CABundleLocker::CABundleLocker() +{ +#if RECURSIVE_LOCK + pthread_once(&sOnce, InitCABundleLocker); +#endif + pthread_mutex_lock(&sCABundleLocker); +} + +CABundleLocker::~CABundleLocker() +{ + pthread_mutex_unlock(&sCABundleLocker); +} + diff --git a/distrho/src/CoreAudio106/PublicUtility/CABundleLocker.h b/distrho/src/CoreAudio106/PublicUtility/CABundleLocker.h new file mode 100755 index 00000000..0fb1a976 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CABundleLocker.h @@ -0,0 +1,61 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef _CABundleLocker_h_ +#define _CABundleLocker_h_ + +/* +some bundle operations are not thread safe, notably CFCopyLocalizedStringFromTableInBundle +*/ + +class CABundleLocker +{ +public: + +#if TARGET_OS_MAC + CABundleLocker(); + ~CABundleLocker(); +#else + CABundleLocker() {} + ~CABundleLocker() {} +#endif +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAByteOrder.h b/distrho/src/CoreAudio106/PublicUtility/CAByteOrder.h new file mode 100755 index 00000000..8b65f21e --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAByteOrder.h @@ -0,0 +1,155 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CAByteOrder_h__) +#define __CAByteOrder_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include "CoreFoundation.h" +#endif + + +#if defined(__cplusplus) +extern "C" { +#endif + +CF_INLINE Float32 CASwapFloat32 (Float32 arg) { + union { + Float32 f; + UInt32 i; + } flip; + + flip.f = arg; + flip.i = CFSwapInt32 (flip.i); + + return flip.f; +} + +CF_INLINE Float64 CASwapFloat64 (Float64 arg) { + union { + Float64 f; + UInt64 i; + } flip; + + flip.f = arg; + flip.i = CFSwapInt64 (flip.i); + + return flip.f; +} + +#pragma mark -Flippers + +CF_INLINE Float32 CASwapFloat32BigToHost(Float32 arg) { +#if defined(__BIG_ENDIAN__) + return arg; +#else + return CASwapFloat32(arg); +#endif +} + +CF_INLINE Float64 CASwapFloat64BigToHost(Float64 arg) { +#if defined(__BIG_ENDIAN__) + return arg; +#else + return CASwapFloat64(arg); +#endif +} + +CF_INLINE Float32 CASwapFloat32HostToBig(Float32 arg) { +#if defined(__BIG_ENDIAN__) + return arg; +#else + return CASwapFloat32(arg); +#endif +} + +CF_INLINE Float64 CASwapFloat64HostToBig(Float64 arg) { +#if defined(__BIG_ENDIAN__) + return arg; +#else + return CASwapFloat64(arg); +#endif +} + +CF_INLINE Float32 CASwapFloat32LittleToHost(Float32 arg) { +#if defined(__LITTLE_ENDIAN__) + return arg; +#else + return CASwapFloat32(arg); +#endif +} + +CF_INLINE Float64 CASwapFloat64LittleToHost(Float64 arg) { +#if defined(__LITTLE_ENDIAN__) + return arg; +#else + return CASwapFloat64(arg); +#endif +} + +CF_INLINE Float32 CASwapFloat32HostToLittle(Float32 arg) { +#if defined(__LITTLE_ENDIAN__) + return arg; +#else + return CASwapFloat32(arg); +#endif +} + +CF_INLINE Float64 CASwapFloat64HostToLittle(Float64 arg) { +#if defined(__LITTLE_ENDIAN__) + return arg; +#else + return CASwapFloat64(arg); +#endif +} + + +#if defined(__cplusplus) +} +#endif + +#endif \ No newline at end of file diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFArray.cpp b/distrho/src/CoreAudio106/PublicUtility/CACFArray.cpp new file mode 100755 index 00000000..b7b6820e --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFArray.cpp @@ -0,0 +1,788 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CACFArray.h" + +// PublicUtility Includes +#include "CACFDictionary.h" +#include "CACFNumber.h" +#include "CACFString.h" + +//============================================================================= +// CACFArray +//============================================================================= + +bool CACFArray::HasItem(const void* inItem) const +{ + bool theAnswer = false; + if(mCFArray != NULL) + { + CFRange theRange = { 0, CFArrayGetCount(mCFArray)}; + theAnswer = CFArrayContainsValue(mCFArray, theRange, inItem); + } + return theAnswer; +} + +bool CACFArray::GetIndexOfItem(const void* inItem, UInt32& outIndex) const +{ + bool theAnswer = false; + outIndex = 0; + if(mCFArray != NULL) + { + CFRange theRange = { 0, CFArrayGetCount(mCFArray)}; + CFIndex theIndex = CFArrayGetFirstIndexOfValue(mCFArray, theRange, inItem); + if(theIndex != -1) + { + theAnswer = true; + outIndex = ToUInt32(theIndex); + } + } + return theAnswer; +} + +bool CACFArray::GetBool(UInt32 inIndex, bool& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inIndex, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFBooleanGetTypeID())) + { + outValue = CFBooleanGetValue(static_cast(theValue)); + theAnswer = true; + } + else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + SInt32 theNumericValue = 0; + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &theNumericValue); + outValue = theNumericValue != 0; + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetSInt32(UInt32 inIndex, SInt32& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberSInt32Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetUInt32(UInt32 inIndex, UInt32& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberSInt32Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetSInt64(UInt32 inIndex, SInt64& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberSInt64Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetUInt64(UInt32 inIndex, UInt64& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberSInt64Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetFloat32(UInt32 inIndex, Float32& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberFloat32Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetFloat64(UInt32 inIndex, Float64& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theItem), kCFNumberFloat64Type, &outItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetString(UInt32 inIndex, CFStringRef& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFStringGetTypeID())) + { + outItem = static_cast(theItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetArray(UInt32 inIndex, CFArrayRef& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFArrayGetTypeID())) + { + outItem = static_cast(theItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetDictionary(UInt32 inIndex, CFDictionaryRef& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFDictionaryGetTypeID())) + { + outItem = static_cast(theItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetData(UInt32 inIndex, CFDataRef& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFDataGetTypeID())) + { + outItem = static_cast(theItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetUUID(UInt32 inIndex, CFUUIDRef& outItem) const +{ + bool theAnswer = false; + + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFUUIDGetTypeID())) + { + outItem = static_cast(theItem); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFArray::GetCFType(UInt32 inIndex, CFTypeRef& outItem) const +{ + bool theAnswer = false; + + if((mCFArray != NULL) && (inIndex < GetNumberItems())) + { + outItem = CFArrayGetValueAtIndex(mCFArray, inIndex); + theAnswer = outItem != NULL; + } + + return theAnswer; +} + +void CACFArray::GetCACFString(UInt32 inIndex, CACFString& outItem) const +{ + outItem = static_cast(NULL); + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFStringGetTypeID())) + { + outItem = static_cast(theItem); + } + } +} + +void CACFArray::GetCACFArray(UInt32 inIndex, CACFArray& outItem) const +{ + outItem = static_cast(NULL); + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFArrayGetTypeID())) + { + outItem = static_cast(theItem); + } + } +} + +void CACFArray::GetCACFDictionary(UInt32 inIndex, CACFDictionary& outItem) const +{ + outItem = static_cast(NULL); + CFTypeRef theItem = NULL; + if(GetCFType(inIndex, theItem)) + { + if((theItem != NULL) && (CFGetTypeID(theItem) == CFDictionaryGetTypeID())) + { + outItem = static_cast(theItem); + } + } +} + +bool CACFArray::AppendBool(bool inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFBoolean theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFBoolean()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendSInt32(SInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendUInt32(UInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendSInt64(SInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendUInt64(UInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendFloat32(Float32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendFloat64(Float64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = AppendCFType(theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::AppendString(const CFStringRef inItem) +{ + return AppendCFType(inItem); +} + +bool CACFArray::AppendArray(const CFArrayRef inItem) +{ + return AppendCFType(inItem); +} + +bool CACFArray::AppendDictionary(const CFDictionaryRef inItem) +{ + return AppendCFType(inItem); +} + +bool CACFArray::AppendData(const CFDataRef inItem) +{ + return AppendCFType(inItem); +} + +bool CACFArray::AppendCFType(const CFTypeRef inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CFArrayAppendValue(mCFArray, inItem); + theAnswer = true; + } + + return theAnswer; +} + +bool CACFArray::InsertBool(UInt32 inIndex, bool inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFBoolean theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFBoolean()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertSInt32(UInt32 inIndex, SInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertUInt32(UInt32 inIndex, UInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertSInt64(UInt32 inIndex, SInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertUInt64(UInt32 inIndex, UInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertFloat32(UInt32 inIndex, Float32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertFloat64(UInt32 inIndex, Float64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = InsertCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::InsertString(UInt32 inIndex, const CFStringRef inItem) +{ + return InsertCFType(inIndex, inItem); +} + +bool CACFArray::InsertArray(UInt32 inIndex, const CFArrayRef inItem) +{ + return InsertCFType(inIndex, inItem); +} + +bool CACFArray::InsertDictionary(UInt32 inIndex, const CFDictionaryRef inItem) +{ + return InsertCFType(inIndex, inItem); +} + +bool CACFArray::InsertData(UInt32 inIndex, const CFDataRef inItem) +{ + return InsertCFType(inIndex, inItem); +} + +bool CACFArray::InsertCFType(UInt32 inIndex, const CFTypeRef inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable) + { + if(inIndex < GetNumberItems()) + { + CFArrayInsertValueAtIndex(mCFArray, inIndex, inItem); + } + else + { + CFArrayAppendValue(mCFArray, inItem); + } + theAnswer = true; + } + + return theAnswer; +} + +bool CACFArray::SetBool(UInt32 inIndex, bool inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFBoolean theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFBoolean()); + } + } + + return theAnswer; +} + +bool CACFArray::SetSInt32(UInt32 inIndex, SInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetUInt32(UInt32 inIndex, UInt32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetSInt64(UInt32 inIndex, SInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetUInt64(UInt32 inIndex, UInt64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetFloat32(UInt32 inIndex, Float32 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetFloat64(UInt32 inIndex, Float64 inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CACFNumber theItem(inItem); + if(theItem.IsValid()) + { + theAnswer = SetCFType(inIndex, theItem.GetCFNumber()); + } + } + + return theAnswer; +} + +bool CACFArray::SetString(UInt32 inIndex, const CFStringRef inItem) +{ + return SetCFType(inIndex, inItem); +} + +bool CACFArray::SetArray(UInt32 inIndex, const CFArrayRef inItem) +{ + return SetCFType(inIndex, inItem); +} + +bool CACFArray::SetDictionary(UInt32 inIndex, const CFDictionaryRef inItem) +{ + return SetCFType(inIndex, inItem); +} + +bool CACFArray::SetData(UInt32 inIndex, const CFDataRef inItem) +{ + return SetCFType(inIndex, inItem); +} + +bool CACFArray::SetCFType(UInt32 inIndex, const CFTypeRef inItem) +{ + bool theAnswer = false; + + if((mCFArray != NULL) && mMutable && (inIndex <= GetNumberItems())) + { + CFArraySetValueAtIndex(mCFArray, inIndex, inItem); + theAnswer = true; + } + + return theAnswer; +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFArray.h b/distrho/src/CoreAudio106/PublicUtility/CACFArray.h new file mode 100755 index 00000000..252b3e45 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFArray.h @@ -0,0 +1,186 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFArray_h__) +#define __CACFArray_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +#include "CADebugMacros.h" + +//============================================================================= +// Types +//============================================================================= + +class CACFDictionary; +class CACFString; + +//============================================================================= +// CACFArray +//============================================================================= + +class CACFArray +{ + +// Construction/Destruction +public: + CACFArray(bool inRelease = true) : mCFArray(CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)), mRelease(inRelease), mMutable(true) {} + CACFArray(UInt32 inMaxNumberItems, bool inRelease) : mCFArray(CFArrayCreateMutable(NULL, inMaxNumberItems, &kCFTypeArrayCallBacks)), mRelease(inRelease), mMutable(true) {} + CACFArray(CFArrayRef inCFArray, bool inRelease) : mCFArray(const_cast(inCFArray)), mRelease(inRelease), mMutable(false) {} + CACFArray(CFMutableArrayRef inCFArray, bool inRelease) : mCFArray(inCFArray), mRelease(inRelease), mMutable(true) {} + CACFArray(const CACFArray& inArray) : mCFArray(inArray.mCFArray), mRelease(inArray.mRelease), mMutable(inArray.mMutable) { Retain(); } + CACFArray& operator=(const CACFArray& inArray) { Release(); mCFArray = inArray.mCFArray; mRelease = inArray.mRelease; mMutable = inArray.mMutable; Retain(); return *this; } + CACFArray& operator=(CFArrayRef inCFArray) { Release(); mCFArray = const_cast(inCFArray); mMutable = false; Retain(); return *this; } + CACFArray& operator=(CFMutableArrayRef inCFArray) { Release(); mCFArray = inCFArray; mMutable = true; Retain(); return *this; } + ~CACFArray() { Release(); } + +private: + void Retain() { if(mRelease && (mCFArray != NULL)) { CFRetain(mCFArray); } } + void Release() { if(mRelease && (mCFArray != NULL)) { CFRelease(mCFArray); } } + +// Attributes +public: + bool IsValid() const { return mCFArray != NULL; } + bool IsMutable() const { return mMutable; } + bool CanModify() const { return mMutable && (mCFArray != NULL); } + + bool WillRelease() const { return mRelease; } + void ShouldRelease(bool inRelease) { mRelease = inRelease; } + + CFTypeID GetTypeID() const { return CFGetTypeID(mCFArray); } + + CFArrayRef GetCFArray() const { return mCFArray; } + CFArrayRef CopyCFArray() const { if(mCFArray != NULL) { CFRetain(mCFArray); } return mCFArray; } + + CFMutableArrayRef GetCFMutableArray() const { return mCFArray; } + CFMutableArrayRef CopyCFMutableArray() const { if(mCFArray != NULL) { CFRetain(mCFArray); } return mCFArray; } + CFPropertyListRef AsPropertyList() const { return mCFArray; } + + void SetCFMutableArrayFromCopy(CFArrayRef inArray, bool inRelease = true) { Release(); mCFArray = CFArrayCreateMutableCopy(NULL, 0, inArray); mMutable = true; mRelease = inRelease; } + +// Item Operations +public: + UInt32 GetNumberItems() const { UInt32 theAnswer = 0; if(mCFArray != NULL) { theAnswer = ToUInt32(CFArrayGetCount(mCFArray)); } return theAnswer; } + bool HasItem(const void* inItem) const; + void RemoveItem(const void* inItem) { UInt32 theIndex; if(CanModify() && GetIndexOfItem(inItem, theIndex)) { RemoveItemAtIndex(theIndex); } } + bool GetIndexOfItem(const void* inItem, UInt32& outIndex) const; + void RemoveItemAtIndex(UInt32 inIndex) { if(CanModify()) { CFArrayRemoveValueAtIndex(mCFArray, inIndex); } } + void Clear() { if(CanModify()) { CFArrayRemoveAllValues(mCFArray); } } + void Sort(CFComparatorFunction inCompareFunction) { if(CanModify()) { CFRange theRange = { 0, CFArrayGetCount(mCFArray) }; CFArraySortValues(mCFArray, theRange, inCompareFunction, NULL); } } + void SortNumbers() { Sort((CFComparatorFunction)CFNumberCompare); } + void SortStrings() { Sort((CFComparatorFunction)CFStringCompare); } + + bool GetBool(UInt32 inIndex, bool& outValue) const; + bool GetSInt32(UInt32 inIndex, SInt32& outItem) const; + bool GetUInt32(UInt32 inIndex, UInt32& outItem) const; + bool GetSInt64(UInt32 inIndex, SInt64& outItem) const; + bool GetUInt64(UInt32 inIndex, UInt64& outItem) const; + bool GetFloat32(UInt32 inIndex, Float32& outItem) const; + bool GetFloat64(UInt32 inIndex, Float64& outItem) const; + bool GetString(UInt32 inIndex, CFStringRef& outItem) const; + bool GetArray(UInt32 inIndex, CFArrayRef& outItem) const; + bool GetDictionary(UInt32 inIndex, CFDictionaryRef& outItem) const; + bool GetData(UInt32 inIndex, CFDataRef& outItem) const; + bool GetUUID(UInt32 inIndex, CFUUIDRef& outItem) const; + bool GetCFType(UInt32 inIndex, CFTypeRef& outItem) const; + + void GetCACFString(UInt32 inIndex, CACFString& outItem) const; + void GetCACFArray(UInt32 inIndex, CACFArray& outItem) const; + void GetCACFDictionary(UInt32 inIndex, CACFDictionary& outItem) const; + + bool AppendBool(bool inItem); + bool AppendSInt32(SInt32 inItem); + bool AppendUInt32(UInt32 inItem); + bool AppendSInt64(SInt64 inItem); + bool AppendUInt64(UInt64 inItem); + bool AppendFloat32(Float32 inItem); + bool AppendFloat64(Float64 inItem); + bool AppendString(const CFStringRef inItem); + bool AppendArray(const CFArrayRef inItem); + bool AppendDictionary(const CFDictionaryRef inItem); + bool AppendData(const CFDataRef inItem); + bool AppendCFType(const CFTypeRef inItem); + + bool InsertBool(UInt32 inIndex, bool inItem); + bool InsertSInt32(UInt32 inIndex, SInt32 inItem); + bool InsertUInt32(UInt32 inIndex, UInt32 inItem); + bool InsertSInt64(UInt32 inIndex, SInt64 inItem); + bool InsertUInt64(UInt32 inIndex, UInt64 inItem); + bool InsertFloat32(UInt32 inIndex, Float32 inItem); + bool InsertFloat64(UInt32 inIndex, Float64 inItem); + bool InsertString(UInt32 inIndex, const CFStringRef inItem); + bool InsertArray(UInt32 inIndex, const CFArrayRef inItem); + bool InsertDictionary(UInt32 inIndex, const CFDictionaryRef inItem); + bool InsertData(UInt32 inIndex, const CFDataRef inItem); + bool InsertCFType(UInt32 inIndex, const CFTypeRef inItem); + + bool SetBool(UInt32 inIndex, bool inItem); + bool SetSInt32(UInt32 inIndex, SInt32 inItem); + bool SetUInt32(UInt32 inIndex, UInt32 inItem); + bool SetSInt64(UInt32 inIndex, SInt64 inItem); + bool SetUInt64(UInt32 inIndex, UInt64 inItem); + bool SetFloat32(UInt32 inIndex, Float32 inItem); + bool SetFloat64(UInt32 inIndex, Float64 inItem); + bool SetString(UInt32 inIndex, const CFStringRef inItem); + bool SetArray(UInt32 inIndex, const CFArrayRef inItem); + bool SetDictionary(UInt32 inIndex, const CFDictionaryRef inItem); + bool SetData(UInt32 inIndex, const CFDataRef inItem); + bool SetCFType(UInt32 inIndex, const CFTypeRef inItem); + +// Implementation +private: + CFMutableArrayRef mCFArray; + bool mRelease; + bool mMutable; + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFData.h b/distrho/src/CoreAudio106/PublicUtility/CACFData.h new file mode 100755 index 00000000..6178a869 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFData.h @@ -0,0 +1,101 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFData_h__) +#define __CACFData_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +#include "CADebugMacros.h" + +//============================================================================= +// CACFData +//============================================================================= + +class CACFData +{ + +// Construction/Destruction +public: + CACFData(CFDataRef inCFData, bool inWillRelease = true) : mCFData(inCFData), mWillRelease(inWillRelease) {} + CACFData(const void* inData, UInt32 inDataSize) : mCFData(NULL), mWillRelease(true) { mCFData = CFDataCreate(NULL, static_cast(inData), inDataSize); } + ~CACFData() { Release(); } + CACFData(const CACFData& inNumber) : mCFData(inNumber.mCFData), mWillRelease(inNumber.mWillRelease) { Retain(); } + CACFData& operator=(const CACFData& inNumber) { Release(); mCFData = inNumber.mCFData; mWillRelease = inNumber.mWillRelease; Retain(); return *this; } + CACFData& operator=(CFDataRef inCFData) { Release(); mCFData = inCFData; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFData != NULL)) { CFRetain(mCFData); } } + void Release() { if(mWillRelease && (mCFData != NULL)) { CFRelease(mCFData); } } + + CFDataRef mCFData; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() { return mCFData != NULL; } + +// Value Access +public: + CFDataRef GetCFData() const { return mCFData; } + CFDataRef CopyCFData() const { if(mCFData != NULL) { CFRetain(mCFData); } return mCFData; } + + UInt32 GetSize() const { return ToUInt32(CFDataGetLength(mCFData)); } + const void* GetDataPtr() const { return CFDataGetBytePtr(mCFData); } + void CopyData(UInt32 inStartOffset, void* outData, UInt32 inDataSize) const { CFRange theRange = { inStartOffset, inDataSize }; CFDataGetBytes(mCFData, theRange, static_cast(outData)); } + + SInt32 GetSInt32() const { SInt32 theAnswer = 0; CopyData(0, &theAnswer, SizeOf32(SInt32)); return theAnswer; } + Float32 GetFloat32() const { Float32 theAnswer = 0; CopyData(0, &theAnswer, SizeOf32(Float32)); return theAnswer; } + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFDictionary.cpp b/distrho/src/CoreAudio106/PublicUtility/CACFDictionary.cpp new file mode 100755 index 00000000..5f9406f9 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFDictionary.cpp @@ -0,0 +1,561 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CACFDictionary.h" + +// PublicUtility Includes +#include "CACFArray.h" +#include "CACFNumber.h" +#include "CACFString.h" + +//============================================================================= +// CACFDictionary +//============================================================================= + +bool CACFDictionary::HasKey(const CFStringRef inKey) const +{ + return CFDictionaryContainsKey(mCFDictionary, inKey) != 0; +} + +UInt32 CACFDictionary::Size () const +{ + return ToUInt32(CFDictionaryGetCount(mCFDictionary)); +} + +void CACFDictionary::GetKeys (const void **keys) const +{ + CFDictionaryGetKeysAndValues(mCFDictionary, keys, NULL); +} + +bool CACFDictionary::GetBool(const CFStringRef inKey, bool& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFBooleanGetTypeID())) + { + outValue = CFBooleanGetValue(static_cast(theValue)); + theAnswer = true; + } + else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + SInt32 theNumericValue = 0; + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &theNumericValue); + outValue = theNumericValue != 0; + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetSInt32(const CFStringRef inKey, SInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetUInt32(const CFStringRef inKey, UInt32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetSInt64(const CFStringRef inKey, SInt64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetUInt64(const CFStringRef inKey, UInt64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberSInt64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFloat32(const CFStringRef inKey, Float32& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberFloat32Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFloat64(const CFStringRef inKey, Float64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + CFNumberGetValue(static_cast(theValue), kCFNumberFloat64Type, &outValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetFixed64(const CFStringRef inKey, Float64& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) + { + SInt64 theFixed64 = 0; + CFNumberGetValue(static_cast(theValue), kCFNumberSInt64Type, &theFixed64); + outValue = static_cast(theFixed64 >> 32); + outValue += static_cast(theFixed64 & 0x00000000FFFFFFFFLL) / static_cast(0x0000000100000000LL); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetString(const CFStringRef inKey, CFStringRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetArray(const CFStringRef inKey, CFArrayRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFArrayGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetDictionary(const CFStringRef inKey, CFDictionaryRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFDictionaryGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetData(const CFStringRef inKey, CFDataRef& outValue) const +{ + bool theAnswer = false; + + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFDataGetTypeID())) + { + outValue = static_cast(theValue); + theAnswer = true; + } + } + + return theAnswer; +} + +bool CACFDictionary::GetCFType(const CFStringRef inKey, CFTypeRef& outValue) const +{ + bool theAnswer = false; + + if(mCFDictionary != NULL) + { + outValue = CFDictionaryGetValue(mCFDictionary, inKey); + theAnswer = (outValue != NULL); + } + + return theAnswer; +} + +bool CACFDictionary::GetCFTypeWithCStringKey(const char* inKey, CFTypeRef& outValue) const +{ + bool theAnswer = false; + + if(mCFDictionary != NULL) + { + CACFString theKey(inKey); + if(theKey.IsValid()) + { + theAnswer = GetCFType(theKey.GetCFString(), outValue); + } + } + + return theAnswer; +} + +void CACFDictionary::GetCACFString(const CFStringRef inKey, CACFString& outValue) const +{ + outValue = static_cast(NULL); + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) + { + outValue = static_cast(theValue); + } + } +} + +void CACFDictionary::GetCACFArray(const CFStringRef inKey, CACFArray& outValue) const +{ + outValue = static_cast(NULL); + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFArrayGetTypeID())) + { + outValue = static_cast(theValue); + } + } +} + +void CACFDictionary::GetCACFDictionary(const CFStringRef inKey, CACFDictionary& outValue) const +{ + outValue = static_cast(NULL); + CFTypeRef theValue = NULL; + if(GetCFType(inKey, theValue)) + { + if((theValue != NULL) && (CFGetTypeID(theValue) == CFDictionaryGetTypeID())) + { + outValue = static_cast(theValue); + } + } +} + +bool CACFDictionary::AddBool(const CFStringRef inKey, bool inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFBoolean theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFBoolean()); + } + + return theAnswer; +} + +bool CACFDictionary::AddSInt32(const CFStringRef inKey, SInt32 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddUInt32(const CFStringRef inKey, UInt32 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddSInt64(const CFStringRef inKey, SInt64 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddUInt64(const CFStringRef inKey, UInt64 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddFloat32(const CFStringRef inKey, Float32 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddFloat64(const CFStringRef inKey, Float64 inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFNumber theValue(inValue); + theAnswer = AddCFType(inKey, theValue.GetCFNumber()); + } + + return theAnswer; +} + +bool CACFDictionary::AddNumber(const CFStringRef inKey, const CFNumberRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddString(const CFStringRef inKey, const CFStringRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddArray(const CFStringRef inKey, const CFArrayRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddDictionary(const CFStringRef inKey, const CFDictionaryRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddData(const CFStringRef inKey, const CFDataRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + theAnswer = AddCFType(inKey, inValue); + } + + return theAnswer; +} + +bool CACFDictionary::AddCFType(const CFStringRef inKey, const CFTypeRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CFDictionarySetValue(mCFDictionary, inKey, inValue); + theAnswer = true; + } + + return theAnswer; +} + +bool CACFDictionary::AddURL(const CFStringRef inKey, const CFURLRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CFDictionarySetValue(mCFDictionary, inKey, inValue); + theAnswer = true; + } + + return theAnswer; +} + +bool CACFDictionary::AddCFTypeWithCStringKey(const char* inKey, const CFTypeRef inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFString theKey(inKey); + if(theKey.IsValid()) + { + theAnswer = AddCFType(theKey.GetCFString(), inValue); + } + } + + return theAnswer; +} + +bool CACFDictionary::AddCString(const CFStringRef inKey, const char* inValue) +{ + bool theAnswer = false; + + if(mMutable && (mCFDictionary != NULL)) + { + CACFString theValue(inValue); + if(theValue.IsValid()) + { + theAnswer = AddCFType(inKey, theValue.GetCFString()); + } + } + + return theAnswer; +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFDictionary.h b/distrho/src/CoreAudio106/PublicUtility/CACFDictionary.h new file mode 100755 index 00000000..92aeabf6 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFDictionary.h @@ -0,0 +1,162 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFDictionary_h__) +#define __CACFDictionary_h__ + +//============================================================================= +// Includes +//============================================================================= + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +//============================================================================= +// Types +//============================================================================= + +class CACFArray; +class CACFString; + +//============================================================================= +// CACFDictionary +//============================================================================= + +class CACFDictionary +{ + +// Construction/Destruction +public: + CACFDictionary(bool inRelease = true) : mCFDictionary(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)), mRelease(inRelease), mMutable(true) {} + CACFDictionary(CFDictionaryRef inCFDictionary, bool inRelease) : mCFDictionary(const_cast(inCFDictionary)), mRelease(inRelease), mMutable(false) {} + CACFDictionary(CFMutableDictionaryRef inCFDictionary, bool inRelease) : mCFDictionary(inCFDictionary), mRelease(inRelease), mMutable(true) {} + CACFDictionary(const CACFDictionary& inDictionary) : mCFDictionary(inDictionary.mCFDictionary), mRelease(inDictionary.mRelease), mMutable(inDictionary.mMutable) { Retain(); } + CACFDictionary& operator=(const CACFDictionary& inDictionary) { Release(); mCFDictionary = inDictionary.mCFDictionary; mRelease = inDictionary.mRelease; mMutable = inDictionary.mMutable; Retain(); return *this; } + CACFDictionary& operator=(CFDictionaryRef inDictionary) { Release(); mCFDictionary = const_cast(inDictionary); mMutable = false; Retain(); return *this; } + CACFDictionary& operator=(CFMutableDictionaryRef inDictionary) { Release(); mCFDictionary = inDictionary; mMutable = true; Retain(); return *this; } + ~CACFDictionary() { Release(); } + +private: + void Retain() { if(mRelease && (mCFDictionary != NULL)) { CFRetain(mCFDictionary); } } + void Release() { if(mRelease && (mCFDictionary != NULL)) { CFRelease(mCFDictionary); } } + +// Attributes +public: + bool IsValid() const { return mCFDictionary != NULL; } + bool IsMutable() const { return mMutable;} + bool CanModify() const { return mMutable && (mCFDictionary != NULL); } + + bool WillRelease() const { return mRelease; } + void ShouldRelease(bool inRelease) { mRelease = inRelease; } + + CFDictionaryRef GetDict() const { return mCFDictionary; } + CFDictionaryRef GetCFDictionary() const { return mCFDictionary; } + CFDictionaryRef CopyCFDictionary() const { if(mCFDictionary != NULL) { CFRetain(mCFDictionary); } return mCFDictionary; } + + CFMutableDictionaryRef GetMutableDict() { return mCFDictionary; } + CFMutableDictionaryRef GetCFMutableDictionary() const { return mCFDictionary; } + CFMutableDictionaryRef CopyCFMutableDictionary() const { if(mCFDictionary != NULL) { CFRetain(mCFDictionary); } return mCFDictionary; } + void SetCFMutableDictionaryFromCopy(CFDictionaryRef inDictionary, bool inRelease = true) { Release(); mCFDictionary = CFDictionaryCreateMutableCopy(NULL, 0, inDictionary); mMutable = true; mRelease = inRelease; } + void SetCFMutableDictionaryToEmpty(bool inRelease = true) { Release(); mCFDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); mMutable = true; mRelease = inRelease; } + + CFPropertyListRef AsPropertyList() const { return mCFDictionary; } + OSStatus GetDictIfMutable(CFMutableDictionaryRef& outDict) const { OSStatus theAnswer = -1; if(mMutable) { outDict = mCFDictionary; theAnswer = 0; } return theAnswer; } + +// Item Operations +public: + bool HasKey(const CFStringRef inKey) const; + UInt32 Size() const; + void GetKeys(const void** keys) const; + + bool GetBool(const CFStringRef inKey, bool& outValue) const; + bool GetSInt32(const CFStringRef inKey, SInt32& outValue) const; + bool GetUInt32(const CFStringRef inKey, UInt32& outValue) const; + bool GetSInt64(const CFStringRef inKey, SInt64& outValue) const; + bool GetUInt64(const CFStringRef inKey, UInt64& outValue) const; + bool GetFloat32(const CFStringRef inKey, Float32& outValue) const; + bool GetFloat64(const CFStringRef inKey, Float64& outValue) const; + bool GetFixed64(const CFStringRef inKey, Float64& outValue) const; + bool GetString(const CFStringRef inKey, CFStringRef& outValue) const; + bool GetArray(const CFStringRef inKey, CFArrayRef& outValue) const; + bool GetDictionary(const CFStringRef inKey, CFDictionaryRef& outValue) const; + bool GetData(const CFStringRef inKey, CFDataRef& outValue) const; + bool GetCFType(const CFStringRef inKey, CFTypeRef& outValue) const; + + bool GetCFTypeWithCStringKey(const char* inKey, CFTypeRef& outValue) const; + + void GetCACFString(const CFStringRef inKey, CACFString& outItem) const; + void GetCACFArray(const CFStringRef inKey, CACFArray& outItem) const; + void GetCACFDictionary(const CFStringRef inKey, CACFDictionary& outItem) const; + + bool AddBool(const CFStringRef inKey, bool inValue); + bool AddSInt32(const CFStringRef inKey, SInt32 inValue); + bool AddUInt32(const CFStringRef inKey, UInt32 inValue); + bool AddSInt64(const CFStringRef inKey, SInt64 inValue); + bool AddUInt64(const CFStringRef inKey, UInt64 inValue); + bool AddFloat32(const CFStringRef inKey, Float32 inValue); + bool AddFloat64(const CFStringRef inKey, Float64 inValue); + bool AddNumber(const CFStringRef inKey, const CFNumberRef inValue); + bool AddString(const CFStringRef inKey, const CFStringRef inValue); + bool AddArray(const CFStringRef inKey, const CFArrayRef inValue); + bool AddDictionary(const CFStringRef inKey, const CFDictionaryRef inValue); + bool AddData(const CFStringRef inKey, const CFDataRef inValue); + bool AddCFType(const CFStringRef inKey, const CFTypeRef inValue); + bool AddURL(const CFStringRef inKey, const CFURLRef inValue); + + bool AddCFTypeWithCStringKey(const char* inKey, const CFTypeRef inValue); + bool AddCString(const CFStringRef inKey, const char* inValue); + + void RemoveKey(const CFStringRef inKey) { if(CanModify()) { CFDictionaryRemoveValue(mCFDictionary, inKey); } } + void Clear() { if(CanModify()) { CFDictionaryRemoveAllValues(mCFDictionary); } } + + void Show() { CFShow(mCFDictionary); } + +// Implementation +private: + CFMutableDictionaryRef mCFDictionary; + bool mRelease; + bool mMutable; +}; + +#endif //__CACFDictionary_h__ diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFDistributedNotification.cpp b/distrho/src/CoreAudio106/PublicUtility/CACFDistributedNotification.cpp new file mode 100755 index 00000000..7a6840a5 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFDistributedNotification.cpp @@ -0,0 +1,100 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CACFDistributedNotification.h" + +// PublicUtility Includes +#include "CADebugMacros.h" + +//================================================================================================== +// CACFDistributedNotification +//================================================================================================== + +void CACFDistributedNotification::AddObserver(const void* inObserver, CFNotificationCallback inCallback, CFStringRef inName, CFNotificationSuspensionBehavior inSuspensionBehavior) +{ +#if !TARGET_OS_IPHONE + CFNotificationCenterRef theCenter = CFNotificationCenterGetDistributedCenter(); + CFNotificationSuspensionBehavior theSuspensionBehavior = inSuspensionBehavior; +#else + CFNotificationCenterRef theCenter = CFNotificationCenterGetDarwinNotifyCenter(); + CFNotificationSuspensionBehavior theSuspensionBehavior = 0; +#endif + + CFNotificationCenterAddObserver(theCenter, inObserver, inCallback, inName, NULL, theSuspensionBehavior); +} + +void CACFDistributedNotification::RemoveObserver(const void* inObserver, CFStringRef inName) +{ +#if !TARGET_OS_IPHONE + CFNotificationCenterRef theCenter = CFNotificationCenterGetDistributedCenter(); +#else + CFNotificationCenterRef theCenter = CFNotificationCenterGetDarwinNotifyCenter(); +#endif + + CFNotificationCenterRemoveObserver(theCenter, inObserver, inName, NULL); +} + +void CACFDistributedNotification::PostNotification(CFStringRef inName, CFDictionaryRef inUserInfo, bool inPostToAllSessions) +{ +#if !TARGET_OS_IPHONE + CFNotificationCenterRef theCenter = CFNotificationCenterGetDistributedCenter(); + CFDictionaryRef theUserInfo = inUserInfo; + CFOptionFlags theFlags = kCFNotificationDeliverImmediately; + if(inPostToAllSessions) + { + theFlags += kCFNotificationPostToAllSessions; + } +#else + // flag unsupported features + Assert(inUserInfo == NULL, "CACFDistributedNotification::PostNotification: distributed notifications do not support a payload"); + Assert(inPostToAllSessions, "CACFDistributedNotification::PostNotification: distributed notifications do not support per-session delivery"); + + CFNotificationCenterRef theCenter = CFNotificationCenterGetDarwinNotifyCenter(); + CFDictionaryRef theUserInfo = NULL; + CFOptionFlags theFlags = 0; +#endif + + CFNotificationCenterPostNotificationWithOptions(theCenter, inName, NULL, theUserInfo, theFlags); +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFDistributedNotification.h b/distrho/src/CoreAudio106/PublicUtility/CACFDistributedNotification.h new file mode 100755 index 00000000..a3eabb3f --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFDistributedNotification.h @@ -0,0 +1,67 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFDistributedNotification_h__) +#define __CACFDistributedNotification_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// System Includes +#include +#include + +//================================================================================================== +// CACFDistributedNotification +//================================================================================================== + +class CACFDistributedNotification +{ + +// Operations +public: + static void AddObserver(const void* inObserver, CFNotificationCallback inCallback, CFStringRef inName, CFNotificationSuspensionBehavior inSuspensionBehavior = CFNotificationSuspensionBehaviorCoalesce); + static void RemoveObserver(const void* inObserver, CFStringRef inName); + static void PostNotification(CFStringRef inName, CFDictionaryRef inUserInfo, bool inPostToAllSessions); + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFMachPort.cpp b/distrho/src/CoreAudio106/PublicUtility/CACFMachPort.cpp new file mode 100755 index 00000000..3732af88 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFMachPort.cpp @@ -0,0 +1,138 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// Includes +//================================================================================================== + +#include "CACFMachPort.h" +#include "CAException.h" +#include "CADebugMacros.h" + +//================================================================================================== +// CACFMachPort +//================================================================================================== + +// This constructor is the short form. The CFMachPort will own the send and receive rights. +CACFMachPort::CACFMachPort(CFMachPortCallBack inCallBack, void* inUserData) +: + mMachPort(NULL), + mRunLoopSource(NULL), + mOwnsPort(true) +{ + CFMachPortContext theContext = { 1, inUserData, NULL, NULL, NULL }; + mMachPort = CFMachPortCreate(NULL, inCallBack, &theContext, NULL); + ThrowIfNULL(mMachPort, CAException('what'), "CACFMachPort::CACFMachPort(s): couldn't create the CFMachPort"); + + mRunLoopSource = CFMachPortCreateRunLoopSource(NULL, mMachPort, 0); + if(mRunLoopSource == NULL) + { + CFMachPortInvalidate(mMachPort); + CFRelease(mMachPort); + mMachPort = NULL; + DebugMessage("CACFMachPort::CACFMachPort(s): couldn't create the CFRunLoopSource"); + throw CAException('what'); + } +} + +// This constructor is the general form: +// - If inMachPort is MACH_PORT_NULL, the CFMachPort will allocate the port and own the send and +// receive rights. Otherwise, the caller owns the rights and is resposible for cleaning them +// up. +// - If inCallBack is NULL, then received messages will just get swallowed by the CFMachPort. +// This is useful if you are only using the CFMachPort to track port death (aka invalidation). +// - If inInvalidationCallBack is non-NULL, then it will be installed as the invalidation +// callback on the CFMachPort. +CACFMachPort::CACFMachPort(mach_port_t inMachPort, CFMachPortCallBack inCallBack, CFMachPortInvalidationCallBack inInvalidationCallBack, void* inUserData) +: + mMachPort(NULL), + mRunLoopSource(NULL), + mOwnsPort(false) +{ + CFMachPortContext theContext = { 1, inUserData, NULL, NULL, NULL }; + + if(inMachPort == MACH_PORT_NULL) + { + mMachPort = CFMachPortCreate(NULL, inCallBack, &theContext, NULL); + ThrowIfNULL(mMachPort, CAException('what'), "CACFMachPort::CACFMachPort: couldn't create the CFMachPort"); + mOwnsPort = true; + } + else + { + mMachPort = CFMachPortCreateWithPort(NULL, inMachPort, inCallBack, &theContext, NULL); + ThrowIfNULL(mMachPort, CAException('what'), "CACFMachPort::CACFMachPort: couldn't create the CFMachPort with a port"); + mOwnsPort = false; + } + + mRunLoopSource = CFMachPortCreateRunLoopSource(NULL, mMachPort, 0); + if(mRunLoopSource == NULL) + { + if(mOwnsPort) + { + CFMachPortInvalidate(mMachPort); + } + CFRelease(mMachPort); + mMachPort = NULL; + DebugMessage("CACFMachPort::CACFMachPort: couldn't create the CFRunLoopSource"); + throw CAException('what'); + } + + if(inInvalidationCallBack != NULL) + { + CFMachPortSetInvalidationCallBack(mMachPort, inInvalidationCallBack); + } +} + +CACFMachPort::~CACFMachPort() +{ + if(mRunLoopSource != NULL) + { + CFRelease(mRunLoopSource); + } + + if(mMachPort != NULL) + { + if(mOwnsPort) + { + CFMachPortInvalidate(mMachPort); + } + CFRelease(mMachPort); + } +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFMachPort.h b/distrho/src/CoreAudio106/PublicUtility/CACFMachPort.h new file mode 100755 index 00000000..00d9523c --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFMachPort.h @@ -0,0 +1,83 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFMachPort_h__) +#define __CACFMachPort_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +#include + +//================================================================================================== +// CACFMachPort +// +// This class wraps a CFMachPort. +// +// Note that when you create a CFMachPort object, CF will attach the run loop source for the the +// Mach Port that handles Port Death notifications (aka the Invalidation Callback) to the current +// thread's run loop. This is something over which there is no control, so be sure to create the +// CFMachPort on the thread on which you want to handle Port Death notificaitons on. +//================================================================================================== + +class CACFMachPort +{ + +// Construction/Destruction +public: + CACFMachPort(CFMachPortCallBack inCallBack, void* inUserData = NULL); + CACFMachPort(mach_port_t inMachPort, CFMachPortCallBack inCallBack, CFMachPortInvalidationCallBack inInvalidationCallBack, void* inUserData); + virtual ~CACFMachPort(); + +// Attributes +public: + CFMachPortRef GetMachPortRef() const { return mMachPort; } + mach_port_t GetMachPort() const { return CFMachPortGetPort(mMachPort); } + CFRunLoopSourceRef GetRunLoopSource() const { return mRunLoopSource; } + +// Implementation +protected: + CFMachPortRef mMachPort; + CFRunLoopSourceRef mRunLoopSource; + bool mOwnsPort; +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFMessagePort.cpp b/distrho/src/CoreAudio106/PublicUtility/CACFMessagePort.cpp new file mode 100755 index 00000000..0907658b --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFMessagePort.cpp @@ -0,0 +1,129 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CACFMessagePort.h" +#include "CADebugMacros.h" +#include "CAException.h" + +//============================================================================= +// CACFLocalMessagePort +//============================================================================= + +CACFLocalMessagePort::CACFLocalMessagePort(CFStringRef inName, CFMessagePortCallBack inPortCallBack, CFMessagePortInvalidationCallBack inInvalidationCallBack, void* inUserData) +: + mMessagePort(NULL), + mRunLoopSource(NULL) +{ + // create the CFMessagePort + CFMessagePortContext theContext = { 0, inUserData, NULL, NULL, NULL }; + mMessagePort = CFMessagePortCreateLocal(NULL, inName, inPortCallBack, &theContext, NULL); + if(mMessagePort != NULL) + { + // add the invalidation callback, if any + if(inInvalidationCallBack != NULL) + { + CFMessagePortSetInvalidationCallBack(mMessagePort, inInvalidationCallBack); + } + + // get the run loop source + mRunLoopSource = CFMessagePortCreateRunLoopSource(NULL, mMessagePort, 0); + } +} + +CACFLocalMessagePort::~CACFLocalMessagePort() +{ + if(mMessagePort != NULL) + { + CFMessagePortInvalidate(mMessagePort); + CFRelease(mMessagePort); + } + + if(mRunLoopSource != NULL) + { + CFRelease(mRunLoopSource); + } +} + +//============================================================================= +// CACFRemoteMessagePort +//============================================================================= + +CACFRemoteMessagePort::CACFRemoteMessagePort(CFStringRef inName, CFMessagePortInvalidationCallBack inInvalidationCallBack) +: + mMessagePort(NULL), + mRunLoopSource(NULL) +{ + // create the CFMessagePort + mMessagePort = CFMessagePortCreateRemote(NULL, inName); + if(mMessagePort != NULL) + { + // failure to create a remote port does not need to throw an exception + // because it isn't really an error since the port in question may not + // exist and this fact requires a more complex response than an excpeption + // provides for. + + // add the invalidation callback, if any + if(inInvalidationCallBack != NULL) + { + CFMessagePortSetInvalidationCallBack(mMessagePort, inInvalidationCallBack); + } + + // get the run loop source + mRunLoopSource = CFMessagePortCreateRunLoopSource(NULL, mMessagePort, 0); + } +} + +CACFRemoteMessagePort::~CACFRemoteMessagePort() +{ + if(mMessagePort != NULL) + { + //CFMessagePortInvalidate(mMessagePort); + CFRelease(mMessagePort); + } + + if(mRunLoopSource != NULL) + { + CFRelease(mRunLoopSource); + } +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFMessagePort.h b/distrho/src/CoreAudio106/PublicUtility/CACFMessagePort.h new file mode 100755 index 00000000..808cca41 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFMessagePort.h @@ -0,0 +1,109 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFMessagePort_h__) +#define __CACFMessagePort_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +//============================================================================= +// CACFLocalMessagePort +//============================================================================= + +class CACFLocalMessagePort +{ + +// Construction/Destruction +public: + CACFLocalMessagePort(CFStringRef inName, CFMessagePortCallBack inPortCallBack, CFMessagePortInvalidationCallBack inInvalidationCallBack, void* inUserData = NULL); + virtual ~CACFLocalMessagePort(); + +// Attributes +public: + bool IsValid() const { return mMessagePort != NULL; } + CFMessagePortRef GetMessagePortRef() const { return mMessagePort; } + CFRunLoopSourceRef GetRunLoopSource() const { return mRunLoopSource; } + +// Implementation +protected: + CFMessagePortRef mMessagePort; + CFRunLoopSourceRef mRunLoopSource; + +}; + +//============================================================================= +// CACFRemoteMessagePort +//============================================================================= + +class CACFRemoteMessagePort +{ + +// Construction/Destruction +public: + CACFRemoteMessagePort(CFStringRef inName, CFMessagePortInvalidationCallBack inInvalidationCallBack); + virtual ~CACFRemoteMessagePort(); + +// Attributes +public: + bool IsValid() const { return mMessagePort != NULL; } + CFMessagePortRef GetMessagePortRef() const { return mMessagePort; } + CFRunLoopSourceRef GetRunLoopSource() const { return mRunLoopSource; } + +// Operations +public: + SInt32 SendRequest(SInt32 inMessageID, CFDataRef inData, CFTimeInterval inSendTimeout, CFTimeInterval inReceiveTimout) const { return CFMessagePortSendRequest(mMessagePort, inMessageID, inData, inSendTimeout, inReceiveTimout, NULL, NULL); } + SInt32 SendRequest(SInt32 inMessageID, CFDataRef inData, CFTimeInterval inSendTimeout, CFTimeInterval inReceiveTimout, CFStringRef inReplyMode, CFDataRef& outReturnData) const { return CFMessagePortSendRequest(mMessagePort, inMessageID, inData, inSendTimeout, inReceiveTimout, inReplyMode, &outReturnData); } + +// Implementation +protected: + CFMessagePortRef mMessagePort; + CFRunLoopSourceRef mRunLoopSource; + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFNumber.cpp b/distrho/src/CoreAudio106/PublicUtility/CACFNumber.cpp new file mode 100755 index 00000000..f0ba17af --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFNumber.cpp @@ -0,0 +1,77 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CACFNumber.h" + +//============================================================================= +// CACFNumber +//============================================================================= + +Float32 CACFNumber::GetFixed32() const +{ + SInt32 theFixedValue = GetSInt32(); + + // this is a 16.16 value so convert it to a float + Float32 theSign = theFixedValue < 0 ? -1.0f : 1.0f; + theFixedValue *= (SInt32)theSign; + Float32 theWholePart = (theFixedValue & 0x7FFF0000) >> 16; + Float32 theFractPart = theFixedValue & 0x0000FFFF; + theFractPart /= 65536.0f; + + return theSign * (theWholePart + theFractPart); +} + +Float64 CACFNumber::GetFixed64() const +{ + SInt64 theFixedValue = GetSInt64(); + + // this is a 32.32 value so convert it to a double + Float64 theSign = theFixedValue < 0 ? -1.0 : 1.0; + theFixedValue *= (SInt64)theSign; + Float64 theWholePart = (theFixedValue & 0x7FFFFFFF00000000LL) >> 32; + Float64 theFractPart = theFixedValue & 0x00000000FFFFFFFFLL; + theFractPart /= 4294967296.0; + + return theSign * (theWholePart + theFractPart); +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFNumber.h b/distrho/src/CoreAudio106/PublicUtility/CACFNumber.h new file mode 100755 index 00000000..7c16f20b --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFNumber.h @@ -0,0 +1,140 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFNumber_h__) +#define __CACFNumber_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +//============================================================================= +// CACFBoolean +//============================================================================= + +class CACFBoolean +{ +// Construction/Destruction +public: + CACFBoolean(CFBooleanRef inCFBoolean, bool inWillRelease = true) : mCFBoolean(inCFBoolean), mWillRelease(inWillRelease) {} + CACFBoolean(bool inValue) : mCFBoolean(inValue ? kCFBooleanTrue : kCFBooleanFalse), mWillRelease(true) { Retain(); } + ~CACFBoolean() { Release(); } + CACFBoolean(const CACFBoolean& inBoolean) : mCFBoolean(inBoolean.mCFBoolean), mWillRelease(inBoolean.mWillRelease) { Retain(); } + CACFBoolean& operator=(const CACFBoolean& inBoolean) { Release(); mCFBoolean = inBoolean.mCFBoolean; mWillRelease = inBoolean.mWillRelease; Retain(); return *this; } + CACFBoolean& operator=(CFBooleanRef inCFBoolean) { Release(); mCFBoolean = inCFBoolean; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFBoolean != NULL)) { CFRetain(mCFBoolean); } } + void Release() { if(mWillRelease && (mCFBoolean != NULL)) { CFRelease(mCFBoolean); } } + + CFBooleanRef mCFBoolean; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() { return mCFBoolean != NULL; } + +// Value Access +public: + CFBooleanRef GetCFBoolean() const { return mCFBoolean; } + CFBooleanRef CopyCFBoolean() const { if(mCFBoolean != NULL) { CFRetain(mCFBoolean); } return mCFBoolean; } + + bool GetBoolean() const { bool theAnswer = false; if(mCFBoolean != NULL) { theAnswer = CFEqual(mCFBoolean, kCFBooleanTrue); } return theAnswer; } + +}; + +//============================================================================= +// CACFNumber +//============================================================================= + +class CACFNumber +{ +// Construction/Destruction +public: + CACFNumber(CFNumberRef inCFNumber, bool inWillRelease = true) : mCFNumber(inCFNumber), mWillRelease(inWillRelease) {} + CACFNumber(SInt32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt32Type, &inValue)), mWillRelease(true) {} + CACFNumber(UInt32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt32Type, &inValue)), mWillRelease(true) {} + CACFNumber(SInt64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt64Type, &inValue)), mWillRelease(true) {} + CACFNumber(UInt64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberSInt64Type, &inValue)), mWillRelease(true) {} + CACFNumber(Float32 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberFloat32Type, &inValue)), mWillRelease(true) {} + CACFNumber(Float64 inValue) : mCFNumber(CFNumberCreate(NULL, kCFNumberFloat64Type, &inValue)), mWillRelease(true) {} + ~CACFNumber() { Release(); } + CACFNumber(const CACFNumber& inNumber) : mCFNumber(inNumber.mCFNumber), mWillRelease(inNumber.mWillRelease) { Retain(); } + CACFNumber& operator=(const CACFNumber& inNumber) { Release(); mCFNumber = inNumber.mCFNumber; mWillRelease = inNumber.mWillRelease; Retain(); return *this; } + CACFNumber& operator=(CFNumberRef inCFNumber) { Release(); mCFNumber = inCFNumber; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFNumber != NULL)) { CFRetain(mCFNumber); } } + void Release() { if(mWillRelease && (mCFNumber != NULL)) { CFRelease(mCFNumber); } } + + CFNumberRef mCFNumber; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() { return mCFNumber != NULL; } + +// Value Access +public: + CFNumberRef GetCFNumber() const { return mCFNumber; } + CFNumberRef CopyCFNumber() const { if(mCFNumber != NULL) { CFRetain(mCFNumber); } return mCFNumber; } + + SInt8 GetSInt8() const { SInt8 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt8Type, &theAnswer); } return theAnswer; } + SInt32 GetSInt32() const { SInt32 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt32Type, &theAnswer); } return theAnswer; } + UInt32 GetUInt32() const { UInt32 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt32Type, &theAnswer); } return theAnswer; } + Float32 GetFloat32() const { Float32 theAnswer = 0.0f; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberFloat32Type, &theAnswer); } return theAnswer; } + Float32 GetFixed32() const; + Float64 GetFixed64() const; + SInt64 GetSInt64() const { SInt64 theAnswer = 0; if(mCFNumber != NULL) { CFNumberGetValue(mCFNumber, kCFNumberSInt64Type, &theAnswer); } return theAnswer; } +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFObject.h b/distrho/src/CoreAudio106/PublicUtility/CACFObject.h new file mode 100755 index 00000000..8ac07058 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFObject.h @@ -0,0 +1,100 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFObject_h__) +#define __CACFObject_h__ + +//============================================================================= +// Includes +//============================================================================= + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +//============================================================================= +// CACFObject +//============================================================================= + +template +class CACFObject +{ + +// Construction/Destruction +public: + CACFObject() : mCFObject(NULL), mWillRelease(true) {} + CACFObject(CFObjectType inCFObject, bool inWillRelease = true) : mCFObject(inCFObject), mWillRelease(inWillRelease) {} + ~CACFObject() { Release(); } + CACFObject(const CACFObject& inObject) : mCFObject(inObject.mCFObject), mWillRelease(inObject.mWillRelease) { Retain(); } + CACFObject& operator=(const CACFObject& inObject) { Release(); mCFObject = inObject.mCFObject; mWillRelease = inObject.mWillRelease; Retain(); return *this; } + CACFObject& operator=(CFObjectType inCFObject) { Release(); mCFObject = inCFObject; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFObject != NULL)) { CFRetain(mCFObject); } } + void Release() { if(mWillRelease && (mCFObject != NULL)) { CFRelease(mCFObject); mCFObject = NULL; } } + + CFObjectType mCFObject; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() const { return mCFObject != NULL; } + CFTypeID GetTypeID() const { return CFGetTypeID(mCFObject); } + bool IsEqual(CFObjectType inCFObject) const { return CFEqual(inCFObject, mCFObject) != 0; } + +// Value Access +public: + CFObjectType GetCFObject() const { return mCFObject; } + CFObjectType CopyCFObject() const { if(mCFObject != NULL) { CFRetain(mCFObject); } return mCFObject; } + +}; + +typedef CACFObject CACFBundle; +typedef CACFObject CACFType; +typedef CACFObject CACFUUID; +typedef CACFObject CACFURL; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFPlugIn.h b/distrho/src/CoreAudio106/PublicUtility/CACFPlugIn.h new file mode 100755 index 00000000..37d82e74 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFPlugIn.h @@ -0,0 +1,95 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFPlugIn_h__) +#define __CACFPlugIn_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// System Includes +#include +#include + +//================================================================================================== +// CACFPlugIn +//================================================================================================== + +class CACFPlugIn +{ + +// Construction/Destruction +public: + CACFPlugIn() : mCFPlugIn(NULL), mWillRelease(true) {} + CACFPlugIn(CFPlugInRef inCFPlugIn, bool inWillRelease = true) : mCFPlugIn(inCFPlugIn), mWillRelease(inWillRelease) {} + CACFPlugIn(CFURLRef inURL, bool inWillRelease = true) : mCFPlugIn(CFPlugInCreate(NULL, inURL)), mWillRelease(inWillRelease) {} + ~CACFPlugIn() { Release(); } + CACFPlugIn(const CACFPlugIn& inObject) : mCFPlugIn(inObject.mCFPlugIn), mWillRelease(inObject.mWillRelease) { Retain(); } + CACFPlugIn& operator=(const CACFPlugIn& inObject) { Release(); mCFPlugIn = inObject.mCFPlugIn; mWillRelease = inObject.mWillRelease; Retain(); return *this; } + CACFPlugIn& operator=(CFPlugInRef inCFPlugIn) { Release(); mCFPlugIn = inCFPlugIn; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFPlugIn != NULL)) { CFRetain(mCFPlugIn); } } + void Release() { if(mWillRelease && (mCFPlugIn != NULL)) { CFRelease(mCFPlugIn); mCFPlugIn = NULL; } } + + CFPlugInRef mCFPlugIn; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() const { return mCFPlugIn != NULL; } + + CFBundleRef GetBundle() const { CFBundleRef theAnswer = NULL; if(IsValid()) { theAnswer = CFPlugInGetBundle(mCFPlugIn); } return theAnswer; } + CFStringRef CopyBundleID() const { CFStringRef theAnswer = NULL; CFBundleRef theBundle = GetBundle(); if(IsValid() && (theBundle != NULL)) { theAnswer = CFBundleGetIdentifier(theBundle); if(theAnswer != NULL) { CFRetain(theAnswer); } } return theAnswer; } + UInt32 GetBundleVersion() const { UInt32 theAnswer = 0; CFBundleRef theBundle = GetBundle(); if(IsValid() && (theBundle != NULL)) { theAnswer = CFBundleGetVersionNumber(theBundle); } return theAnswer; } + CFDictionaryRef CopyBundleInfo() const { CFDictionaryRef theAnswer = NULL; CFBundleRef theBundle = GetBundle(); if(IsValid() && (theBundle != NULL)) { theAnswer = CFBundleGetInfoDictionary(theBundle); if(theAnswer != NULL) { CFRetain(theAnswer); } } return theAnswer; } + CFArrayRef FindFactoriesForType(CFUUIDRef inTypeUUID) const { CFArrayRef theAnswer = NULL; if(IsValid()) { theAnswer = CFPlugInFindFactoriesForPlugInTypeInPlugIn(inTypeUUID, mCFPlugIn); } return theAnswer; } + +// Value Access +public: + CFPlugInRef GetCFPlugIn() const { return mCFPlugIn; } + CFPlugInRef CopyCFPlugIn() const { if(mCFPlugIn != NULL) { CFRetain(mCFPlugIn); } return mCFPlugIn; } + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFPreferences.cpp b/distrho/src/CoreAudio106/PublicUtility/CACFPreferences.cpp new file mode 100755 index 00000000..41e87dce --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFPreferences.cpp @@ -0,0 +1,281 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CACFPreferences.h" + +// PublicUtility Includes +#include "CACFDistributedNotification.h" +#include "CADebugMacros.h" + +//================================================================================================== +// CACFPreferences +//================================================================================================== + +CFPropertyListRef CACFPreferences::CopyValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost) +{ + // synchronize to make sure that what's in memory matches what's on disk + Synchronize(inCurrentUser, inCurrentHost, false); + + CFPropertyListRef theAnswer = NULL; + CFStringRef theUser = inCurrentUser ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser; + CFStringRef theHost = inCurrentHost ? kCFPreferencesCurrentHost : kCFPreferencesAnyHost; + + theAnswer = CFPreferencesCopyValue(inKey, kCFPreferencesAnyApplication, theUser, theHost); + + return theAnswer; +} + +CFStringRef CACFPreferences::CopyStringValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost) +{ + CFStringRef theAnswer = NULL; + + // get the raw value + CFPropertyListRef theRawValue = CopyValue(inKey, inCurrentUser, inCurrentHost); + + if(theRawValue != NULL) + { + // get it's type ID and make sure it's a CFString + CFTypeID theTypeID = CFGetTypeID(theRawValue); + if(theTypeID == CFStringGetTypeID()) + { + // cast the value + theAnswer = static_cast(theRawValue); + } + else + { + CFRelease(theRawValue); + DebugMessage("CACFPreferences::CopyStringValue: not a CFString"); + } + } + + return theAnswer; +} + +CFNumberRef CACFPreferences::CopyNumberValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost) +{ + CFNumberRef theAnswer = NULL; + + // get the raw value + CFPropertyListRef theRawValue = CopyValue(inKey, inCurrentUser, inCurrentHost); + + if(theRawValue != NULL) + { + // get it's type ID and make sure it's a CFNumber + CFTypeID theTypeID = CFGetTypeID(theRawValue); + if(theTypeID == CFNumberGetTypeID()) + { + // cast the value + theAnswer = static_cast(theRawValue); + } + else + { + CFRelease(theRawValue); + DebugMessage("CACFPreferences::CopyNumberValue: not a CFNumber"); + } + } + + return theAnswer; +} + +CFArrayRef CACFPreferences::CopyArrayValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost) +{ + CFArrayRef theAnswer = NULL; + + // get the raw value + CFPropertyListRef theRawValue = CopyValue(inKey, inCurrentUser, inCurrentHost); + + if(theRawValue != NULL) + { + // get it's type ID and make sure it's a CFArray + CFTypeID theTypeID = CFGetTypeID(theRawValue); + if(theTypeID == CFArrayGetTypeID()) + { + // cast the value + theAnswer = static_cast(theRawValue); + } + else + { + CFRelease(theRawValue); + DebugMessage("CACFPreferences::CopyArrayValue: not a CFArray"); + } + } + + return theAnswer; +} + +CFDictionaryRef CACFPreferences::CopyDictionaryValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost) +{ + CFDictionaryRef theAnswer = NULL; + + // get the raw value + CFPropertyListRef theRawValue = CopyValue(inKey, inCurrentUser, inCurrentHost); + + if(theRawValue != NULL) + { + // get it's type ID and make sure it's a CFDictionary + CFTypeID theTypeID = CFGetTypeID(theRawValue); + if(theTypeID == CFDictionaryGetTypeID()) + { + // cast the value + theAnswer = static_cast(theRawValue); + } + else + { + CFRelease(theRawValue); + DebugMessage("CACFPreferences::CopyDictionaryValue: not a CFDictionary"); + } + } + + return theAnswer; +} + +void CACFPreferences::SetValue(CFStringRef inKey, CFPropertyListRef inValue, bool inCurrentUser, bool inCurrentHost, bool inSynchronize) +{ + CFStringRef theUser = inCurrentUser ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser; + CFStringRef theHost = inCurrentHost ? kCFPreferencesCurrentHost : kCFPreferencesAnyHost; + CFPreferencesSetValue(inKey, inValue, kCFPreferencesAnyApplication, theUser, theHost); + + if(inSynchronize) + { + Synchronize(inCurrentUser, inCurrentHost, true); + } +} + +void CACFPreferences::DeleteValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost, bool inSynchronize) +{ + CFStringRef theUser = inCurrentUser ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser; + CFStringRef theHost = inCurrentHost ? kCFPreferencesCurrentHost : kCFPreferencesAnyHost; + CFPreferencesSetValue(inKey, NULL, kCFPreferencesAnyApplication, theUser, theHost); + + if(inSynchronize) + { + Synchronize(theUser, inCurrentHost, true); + } +} + +void CACFPreferences::Synchronize(bool inCurrentUser, bool inCurrentHost, bool inForce) +{ + if(inForce || ArePrefsOutOfDate(inCurrentUser, inCurrentHost)) + { + CFStringRef theUser = inCurrentUser ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser; + CFStringRef theHost = inCurrentHost ? kCFPreferencesCurrentHost : kCFPreferencesAnyHost; + CFPreferencesSynchronize(kCFPreferencesAnyApplication, theUser, theHost); + MarkPrefsClean(inCurrentUser, inCurrentHost); + } +} + +void CACFPreferences::MarkPrefsOutOfDate(bool inCurrentUser, bool inCurrentHost) +{ + if(!inCurrentUser && !inCurrentHost) + { + sAnyUserAnyHostPrefsOutOfDate = true; + } + else if(!inCurrentUser && inCurrentHost) + { + sAnyUserCurrentHostPrefsOutOfDate = true; + } + else if(inCurrentUser && !inCurrentHost) + { + sCurrentUserAnyHostPrefsOutOfDate = true; + } + else if(inCurrentUser && inCurrentHost) + { + sCurrentUserCurrentHostPrefsOutOfDate = true; + } +} + +void CACFPreferences::MarkPrefsClean(bool inCurrentUser, bool inCurrentHost) +{ + if(!inCurrentUser && !inCurrentHost) + { + sAnyUserAnyHostPrefsOutOfDate = false; + } + else if(!inCurrentUser && inCurrentHost) + { + sAnyUserCurrentHostPrefsOutOfDate = false; + } + else if(inCurrentUser && !inCurrentHost) + { + sCurrentUserAnyHostPrefsOutOfDate = false; + } + else if(inCurrentUser && inCurrentHost) + { + sCurrentUserCurrentHostPrefsOutOfDate = false; + } +} + +void CACFPreferences::SendNotification(CFStringRef inName) +{ + CACFDistributedNotification::PostNotification(inName, NULL, true); +} + +bool CACFPreferences::ArePrefsOutOfDate(bool inCurrentUser, bool inCurrentHost) +{ + bool theAnswer = false; + + if(!inCurrentUser && !inCurrentHost) + { + theAnswer = sAnyUserAnyHostPrefsOutOfDate; + } + else if(!inCurrentUser && inCurrentHost) + { + theAnswer = sAnyUserCurrentHostPrefsOutOfDate; + } + else if(inCurrentUser && !inCurrentHost) + { + theAnswer = sCurrentUserAnyHostPrefsOutOfDate; + } + else if(inCurrentUser && inCurrentHost) + { + theAnswer = sCurrentUserCurrentHostPrefsOutOfDate; + } + + return theAnswer; +} + +bool CACFPreferences::sAnyUserAnyHostPrefsOutOfDate = false; +bool CACFPreferences::sAnyUserCurrentHostPrefsOutOfDate = false; +bool CACFPreferences::sCurrentUserAnyHostPrefsOutOfDate = false; +bool CACFPreferences::sCurrentUserCurrentHostPrefsOutOfDate = false; diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFPreferences.h b/distrho/src/CoreAudio106/PublicUtility/CACFPreferences.h new file mode 100755 index 00000000..f4549bc2 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFPreferences.h @@ -0,0 +1,86 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFPreferences_h__) +#define __CACFPreferences_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +//================================================================================================== +// CACFPreferences +//================================================================================================== + +class CACFPreferences +{ + +// Operations +public: + static CFPropertyListRef CopyValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost); + static CFStringRef CopyStringValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost); + static CFNumberRef CopyNumberValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost); + static CFArrayRef CopyArrayValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost); + static CFDictionaryRef CopyDictionaryValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost); + static void SetValue(CFStringRef inKey, CFPropertyListRef inValue, bool inCurrentUser, bool inCurrentHost, bool inSynchronize); + static void DeleteValue(CFStringRef inKey, bool inCurrentUser, bool inCurrentHost, bool inSynchronize); + static void Synchronize(bool inCurrentUser, bool inCurrentHost, bool inForce); + static void MarkPrefsOutOfDate(bool inCurrentUser, bool inCurrentHost); + static void MarkPrefsClean(bool inCurrentUser, bool inCurrentHost); + static void SendNotification(CFStringRef inName); + +private: + static bool ArePrefsOutOfDate(bool inCurrentUser, bool inCurrentHost); + + static bool sAnyUserAnyHostPrefsOutOfDate; + static bool sAnyUserCurrentHostPrefsOutOfDate; + static bool sCurrentUserAnyHostPrefsOutOfDate; + static bool sCurrentUserCurrentHostPrefsOutOfDate; + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFString.cpp b/distrho/src/CoreAudio106/PublicUtility/CACFString.cpp new file mode 100755 index 00000000..ce167012 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFString.cpp @@ -0,0 +1,104 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CACFString.h" + +//============================================================================= +// CACFString +//============================================================================= + +UInt32 CACFString::GetStringByteLength(CFStringRef inCFString, CFStringEncoding inEncoding) +{ + CFIndex theAnswer = 0; + + if(inCFString != NULL) + { + CFRange theRange = { 0, CFStringGetLength(inCFString) }; + CFStringGetBytes(inCFString, theRange, inEncoding, 0, false, NULL, 0x7FFFFFFF, &theAnswer); + } + + return UInt32(theAnswer); +} + +void CACFString::GetCString(CFStringRef inCFString, char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding) +{ + if(ioStringSize > 0) + { + if(inCFString != NULL) + { + CFIndex theLength = 0; + CFRange theRange = { 0, CFStringGetLength(inCFString) }; + CFStringGetBytes(inCFString, theRange, inEncoding, 0, false, (UInt8*)outString, ioStringSize - 1, &theLength); + outString[theLength] = 0; + ioStringSize = ToUInt32(theLength) + 1; + } + else + { + outString[0] = 0; + ioStringSize = 1; + } + } +} + +void CACFString::GetUnicodeString(CFStringRef inCFString, UInt16* outString, UInt32& ioStringSize) +{ + if(ioStringSize > 0) + { + if(inCFString != NULL) + { + CFRange theStringRange = { 0, CFStringGetLength(inCFString) }; + if(static_cast(theStringRange.length) > ioStringSize) + { + theStringRange.length = ioStringSize; + } + CFStringGetCharacters(inCFString, theStringRange, outString); + ioStringSize = ToUInt32(theStringRange.length); + } + else + { + outString[0] = 0; + ioStringSize = 0; + } + } +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CACFString.h b/distrho/src/CoreAudio106/PublicUtility/CACFString.h new file mode 100755 index 00000000..1523d696 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CACFString.h @@ -0,0 +1,163 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CACFString_h__) +#define __CACFString_h__ + +//============================================================================= +// Includes +//============================================================================= + +#include "CADebugMacros.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +//============================================================================= +// CACFString +//============================================================================= + +class CACFString +{ +// Construction/Destruction +public: + CACFString() : mCFString(NULL), mWillRelease(true) {} + CACFString(CFStringRef inCFString, bool inWillRelease = true) : mCFString(inCFString), mWillRelease(inWillRelease) {} + CACFString(const char* inCString, bool inWillRelease = true) : mCFString(CFStringCreateWithCString(NULL, inCString, kCFStringEncodingASCII)), mWillRelease(inWillRelease) {} + CACFString(const char* inCString, CFStringEncoding inCStringEncoding, bool inWillRelease = true) : mCFString(CFStringCreateWithCString(NULL, inCString, inCStringEncoding)), mWillRelease(inWillRelease) {} + ~CACFString() { Release(); } + CACFString(const CACFString& inString) : mCFString(inString.mCFString), mWillRelease(inString.mWillRelease) { Retain(); } + CACFString& operator=(const CACFString& inString) { Release(); mCFString = inString.mCFString; mWillRelease = inString.mWillRelease; Retain(); return *this; } + CACFString& operator=(CFStringRef inCFString) { Release(); mCFString = inCFString; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFString != NULL)) { CFRetain(mCFString); } } + void Release() { if(mWillRelease && (mCFString != NULL)) { CFRelease(mCFString); } } + + CFStringRef mCFString; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() const { return mCFString != NULL; } + bool StartsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFString != NULL) { theAnswer = CFStringHasPrefix(mCFString, inString); } return theAnswer; } + bool EndsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFString != NULL) { theAnswer = CFStringHasSuffix(mCFString, inString); } return theAnswer; } + +// Value Access +public: + CFStringRef GetCFString() const { return mCFString; } + CFStringRef CopyCFString() const { if(mCFString != NULL) { CFRetain(mCFString); } return mCFString; } + UInt32 GetLength() const { UInt32 theAnswer = 0; if(mCFString != NULL) { theAnswer = ToUInt32(CFStringGetLength(mCFString)); } return theAnswer; } + UInt32 GetByteLength(CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { UInt32 theAnswer = 0; if(mCFString != NULL) { theAnswer = GetStringByteLength(mCFString, inEncoding); } return theAnswer; } + void GetCString(char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { GetCString(mCFString, outString, ioStringSize, inEncoding); } + void GetUnicodeString(UInt16* outString, UInt32& ioStringSize) const { GetUnicodeString(mCFString, outString, ioStringSize); } + SInt32 GetAsInteger() { return GetAsInteger(mCFString); } + Float64 GetAsFloat64() { return GetAsFloat64(mCFString); } + + static UInt32 GetStringByteLength(CFStringRef inCFString, CFStringEncoding inEncoding = kCFStringEncodingUTF8); + static void GetCString(CFStringRef inCFString, char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8); + static void GetUnicodeString(CFStringRef inCFString, UInt16* outString, UInt32& ioStringSize); + static SInt32 GetAsInteger(CFStringRef inCFString) { SInt32 theAnswer = 0; if(inCFString != NULL){ theAnswer = CFStringGetIntValue(inCFString); } return theAnswer; } + static Float64 GetAsFloat64(CFStringRef inCFString) { Float64 theAnswer = 0; if(inCFString != NULL){ theAnswer = CFStringGetDoubleValue(inCFString); } return theAnswer; } + +}; + +inline bool operator<(const CACFString& x, const CACFString& y) { return CFStringCompare(x.GetCFString(), y.GetCFString(), 0) == kCFCompareLessThan; } +inline bool operator==(const CACFString& x, const CACFString& y) { return CFStringCompare(x.GetCFString(), y.GetCFString(), 0) == kCFCompareEqualTo; } +inline bool operator!=(const CACFString& x, const CACFString& y) { return !(x == y); } +inline bool operator<=(const CACFString& x, const CACFString& y) { return (x < y) || (x == y); } +inline bool operator>=(const CACFString& x, const CACFString& y) { return !(x < y); } +inline bool operator>(const CACFString& x, const CACFString& y) { return !((x < y) || (x == y)); } + +//============================================================================= +// CACFMutableString +//============================================================================= + +class CACFMutableString +{ +// Construction/Destruction +public: + CACFMutableString() : mCFMutableString(NULL), mWillRelease(true) {} + CACFMutableString(CFMutableStringRef inCFMutableString, bool inWillRelease = true) : mCFMutableString(inCFMutableString), mWillRelease(inWillRelease) {} + CACFMutableString(CFStringRef inStringToCopy, bool /*inMakeCopy*/, bool inWillRelease = true) : mCFMutableString(CFStringCreateMutableCopy(NULL, 0, inStringToCopy)), mWillRelease(inWillRelease) {} + CACFMutableString(const char* inCString, bool inWillRelease = true) : mCFMutableString(NULL), mWillRelease(inWillRelease) { CACFString theString(inCString); mCFMutableString = CFStringCreateMutableCopy(NULL, 0, theString.GetCFString()); } + CACFMutableString(const char* inCString, CFStringEncoding inCStringEncoding, bool inWillRelease = true) : mCFMutableString(NULL), mWillRelease(inWillRelease) { CACFString theString(inCString, inCStringEncoding); mCFMutableString = CFStringCreateMutableCopy(NULL, 0, theString.GetCFString()); } + ~CACFMutableString() { Release(); } + CACFMutableString(const CACFMutableString& inString) : mCFMutableString(inString.mCFMutableString), mWillRelease(inString.mWillRelease) { Retain(); } + CACFMutableString& operator=(const CACFMutableString& inString) { Release(); mCFMutableString = inString.mCFMutableString; mWillRelease = inString.mWillRelease; Retain(); return *this; } + CACFMutableString& operator=(CFMutableStringRef inCFMutableString) { Release(); mCFMutableString = inCFMutableString; mWillRelease = true; return *this; } + +private: + void Retain() { if(mWillRelease && (mCFMutableString != NULL)) { CFRetain(mCFMutableString); } } + void Release() { if(mWillRelease && (mCFMutableString != NULL)) { CFRelease(mCFMutableString); } } + + CFMutableStringRef mCFMutableString; + bool mWillRelease; + +// Operations +public: + void AllowRelease() { mWillRelease = true; } + void DontAllowRelease() { mWillRelease = false; } + bool IsValid() { return mCFMutableString != NULL; } + bool StartsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFMutableString != NULL) { theAnswer = CFStringHasPrefix(mCFMutableString, inString); } return theAnswer; } + bool EndsWith(CFStringRef inString) const { bool theAnswer = false; if(mCFMutableString != NULL) { theAnswer = CFStringHasSuffix(mCFMutableString, inString); } return theAnswer; } + void Append(CFStringRef inString) { if(mCFMutableString != NULL) { CFStringAppend(mCFMutableString, inString); } } + +// Value Access +public: + CFMutableStringRef GetCFMutableString() const { return mCFMutableString; } + CFMutableStringRef CopyCFMutableString() const { if(mCFMutableString != NULL) { CFRetain(mCFMutableString); } return mCFMutableString; } + UInt32 GetLength() const { UInt32 theAnswer = 0; if(mCFMutableString != NULL) { theAnswer = ToUInt32(CFStringGetLength(mCFMutableString)); } return theAnswer; } + UInt32 GetByteLength(CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { UInt32 theAnswer = 0; if(mCFMutableString != NULL) { theAnswer = CACFString::GetStringByteLength(mCFMutableString, inEncoding); } return theAnswer; } + void GetCString(char* outString, UInt32& ioStringSize, CFStringEncoding inEncoding = kCFStringEncodingUTF8) const { CACFString::GetCString(mCFMutableString, outString, ioStringSize, inEncoding); } + void GetUnicodeString(UInt16* outString, UInt32& ioStringSize) const { CACFString::GetUnicodeString(mCFMutableString, outString, ioStringSize); } + SInt32 GetAsInteger() { return CACFString::GetAsInteger(mCFMutableString); } + Float64 GetAsFloat64() { return CACFString::GetAsFloat64(mCFMutableString); } + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAComponent.cpp b/distrho/src/CoreAudio106/PublicUtility/CAComponent.cpp new file mode 100755 index 00000000..0a3574ac --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAComponent.cpp @@ -0,0 +1,176 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CAComponent.h" +#include "CAComponentDescription.h" +#include "CACFDictionary.h" +#include +#include "CAAutoDisposer.h" + +CAComponent::CAComponent (const AudioComponentDescription& inDesc, CAComponent* next) + : mManuName(0), mAUName(0), mCompName(0) +{ + mComp = AudioComponentFindNext ((next ? next->Comp() : NULL), &inDesc); + if (mComp) + AudioComponentGetDescription(Comp(), &mDesc); + else + memcpy (&mDesc, &inDesc, sizeof(AudioComponentDescription)); +} + +CAComponent::CAComponent (const AudioComponent& comp) + : mComp (comp), + mManuName(0), + mAUName(0), + mCompName(0) +{ + AudioComponentGetDescription (Comp(), &mDesc); +} + +CAComponent::CAComponent (const AudioComponentInstance& compInst) + : mComp (NULL), + mManuName(0), + mAUName(0), + mCompName(0) +{ + mComp = AudioComponentInstanceGetComponent (compInst); + AudioComponentGetDescription (Comp(), &mDesc); +} + +CAComponent::CAComponent (OSType inType, OSType inSubtype, OSType inManu) + : mDesc (inType, inSubtype, inManu), + mManuName(0), mAUName(0), mCompName(0) +{ + mComp = AudioComponentFindNext (NULL, &mDesc); + AudioComponentGetDescription (Comp(), &mDesc); +} + +CAComponent::~CAComponent () +{ + Clear(); +} + +OSStatus CAComponent::GetVersion (UInt32 &outVersion) const +{ + return AudioComponentGetVersion (mComp, &outVersion); +} + +void CAComponent::Clear () +{ + if (mManuName) { CFRelease (mManuName); mManuName = 0; } + if (mAUName) { CFRelease (mAUName); mAUName = 0; } + if (mCompName) { CFRelease (mCompName); mCompName = 0; } +} + +CAComponent& CAComponent::operator= (const CAComponent& y) +{ + Clear(); + + mComp = y.mComp; + mDesc = y.mDesc; + + if (y.mManuName) { mManuName = y.mManuName; CFRetain (mManuName); } + if (y.mAUName) { mAUName = y.mAUName; CFRetain (mAUName); } + if (y.mCompName) { mCompName = y.mCompName; CFRetain (mCompName); } + + return *this; +} + +void CAComponent::SetCompNames () const +{ + if (!mCompName) { + + CFStringRef compName; + OSStatus result = AudioComponentCopyName (Comp(), &compName); + if (result) return; + + const_cast(this)->mCompName = compName; + if (compName) + { + CFArrayRef splitStrArray = CFStringCreateArrayBySeparatingStrings(NULL, compName, CFSTR(":")); + + // we need to retain these values so the strings are not lost when the array is released + CFRetain(CFArrayGetValueAtIndex(splitStrArray, 0)); + const_cast(this)->mManuName = (CFStringRef)CFArrayGetValueAtIndex(splitStrArray, 0); + if (CFArrayGetCount(splitStrArray) > 1) + { + CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(splitStrArray, 1); + + CFMutableStringRef mstr = CFStringCreateMutableCopy (NULL, CFStringGetLength(str), str); + + // this needs to trim out white space: + + CFStringTrimWhitespace (mstr); + + const_cast(this)->mAUName = mstr; + } else + const_cast(this)->mAUName = NULL; + + CFRelease(splitStrArray); + } + } +} + +static void _ShowCF (FILE* file, CFStringRef str) +{ + if (CFGetTypeID(str) != CFStringGetTypeID()) { + CFShow(str); + return; + } + + UInt32 len = CFStringGetLength(str); + char* chars = (char*)CA_malloc (len * 2); // give us plenty of room for unichar chars + if (CFStringGetCString (str, chars, len * 2, kCFStringEncodingUTF8)) + fprintf (file, "%s", chars); + else + CFShow (str); + + free (chars); +} + +void CAComponent::Print(FILE* file) const +{ + fprintf (file, "CAComponent: %p", Comp()); + if (mManuName) { + fprintf (file, ", Manu:"); _ShowCF (file, mManuName); + if (mAUName) fprintf (file, ", Name:"); _ShowCF (file, mAUName); + } + fprintf (file, ", "); + Desc ().Print(file); +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAComponent.h b/distrho/src/CoreAudio106/PublicUtility/CAComponent.h new file mode 100755 index 00000000..c0ca63e4 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAComponent.h @@ -0,0 +1,115 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __CAComponent_h__ +#define __CAComponent_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) +#else + #include +#endif + +#include "CAComponentDescription.h" + +class CAComponent +{ +public: + CAComponent () + : mComp (0), mDesc(), mManuName(0), mAUName(0), mCompName(0) {} + + // if next is specifed that is used to find the next component after that one + CAComponent (const AudioComponentDescription& inDesc, CAComponent* next = 0); + + CAComponent (const CAComponent& y) + : mComp (0), mDesc(), mManuName(0), mAUName(0), mCompName(0) { *this = y; } + + CAComponent (const AudioComponent& comp); + + CAComponent (const AudioComponentInstance& compInst); + + CAComponent (OSType inType, OSType inSubtype = 0, OSType inManu = 0); + + ~CAComponent (); + + CAComponent& operator= (const CAComponent& y); + + // returns true if this object references a valid component + bool IsValid () const { return Comp() != 0; } + + bool HasAUStrings() const { SetCompNames (); return mManuName != 0; } + + // CFStringRef should be retained by caller if needed beyond lifetime of this object + + // Can return NULL if component doesn't follow AU naming conventions + CFStringRef GetAUManu () const { SetCompNames (); return mManuName; } + CFStringRef GetAUName () const { SetCompNames (); return mAUName ? mAUName : mCompName; } + + // Return value of NULL indicates a problem getting that information from the component + CFStringRef GetCompName () const { SetCompNames(); return mCompName; } + + const CAComponentDescription& Desc () const { return mDesc; } + + OSStatus Open (AudioComponentInstance& outInst) const + { + return AudioComponentInstanceNew (Comp(), &outInst); + } + + OSStatus GetVersion (UInt32 &outVersion) const; + + const AudioComponent& Comp() const { return mComp; } + + void Print(FILE* file = stdout) const; + + OSStatus Save (CFPropertyListRef *outData) const; + + OSStatus Restore (CFPropertyListRef &inData); + +private: + AudioComponent mComp; + CAComponentDescription mDesc; + + CFStringRef mManuName, mAUName, mCompName; + + void SetCompNames () const; + void SetCompInfo () const; + void Clear (); +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAComponentDescription.cpp b/distrho/src/CoreAudio106/PublicUtility/CAComponentDescription.cpp new file mode 100755 index 00000000..24108d1b --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAComponentDescription.cpp @@ -0,0 +1,104 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CAComponentDescription.h" +#include "CAStreamBasicDescription.h" +#include + +void CAShowComponentDescription(const AudioComponentDescription *desc) +{ + CAComponentDescription::_CAShowComponentDescription (desc, stdout); +} + +void CAComponentDescription::_CAShowComponentDescription(const AudioComponentDescription *desc, FILE* file) +{ + if (desc) + { + char str[24]; + fprintf (file, "AudioComponentDescription: %s - ", CAStringForOSType(desc->componentType, str)); + fprintf (file, "%s - ", CAStringForOSType(desc->componentSubType, str)); + fprintf (file, "%s", CAStringForOSType(desc->componentManufacturer, str)); + fprintf (file, ", 0x%X, 0x%X\n", (int)desc->componentFlags, (int)desc->componentFlagsMask); + } +} + +CAComponentDescription::CAComponentDescription (OSType inType, OSType inSubtype, OSType inManu) +{ + componentType = inType; + componentSubType = inSubtype; + componentManufacturer = inManu; + componentFlags = 0; + componentFlagsMask = 0; +} + +bool CAComponentDescription::IsAU () const +{ + bool flag = IsEffect() || IsMusicDevice() || IsOffline(); + if (flag) return true; + + switch (componentType) { + case kAudioUnitType_Output: + case kAudioUnitType_FormatConverter: + case kAudioUnitType_Mixer: + return true; + } + return false; +} + +inline bool _MatchTest (const OSType &inTypeA, const OSType &inTypeB) +{ + return ((inTypeA == inTypeB) || (!inTypeA && !inTypeB) || (inTypeA && !inTypeB) || (!inTypeA && inTypeB)); +} + +bool CAComponentDescription::Matches (const AudioComponentDescription &desc) const +{ + bool matches = false; + + // see if the type matches + matches = _MatchTest (componentType, desc.componentType); + + if (matches) + matches = _MatchTest (componentSubType, desc.componentSubType); + + if (matches) + matches = _MatchTest (componentManufacturer, desc.componentManufacturer); + + return matches; +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAComponentDescription.h b/distrho/src/CoreAudio106/PublicUtility/CAComponentDescription.h new file mode 100755 index 00000000..7254dbe5 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAComponentDescription.h @@ -0,0 +1,135 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __CAComponentDescription_h__ +#define __CAComponentDescription_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include + #include +#endif + +#include "CACFDictionary.h" +#include +#include + +void CAShowComponentDescription(const AudioComponentDescription *desc); + +// ____________________________________________________________________________ +// +// CAComponentDescription +class CAComponentDescription : public AudioComponentDescription { +public: + CAComponentDescription() { memset (this, 0, sizeof (AudioComponentDescription)); } + + CAComponentDescription (OSType inType, OSType inSubtype = 0, OSType inManu = 0); + + CAComponentDescription(const AudioComponentDescription& desc) { memcpy (this, &desc, sizeof (AudioComponentDescription)); } + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // interrogation + + bool IsAU () const; + + bool IsAUFX() const { return componentType == kAudioUnitType_Effect; } + bool IsAUFM() const { return componentType == kAudioUnitType_MusicEffect; } + + bool IsEffect () const { return IsAUFX() || IsAUFM() || IsPanner(); } + + bool IsOffline () const { return componentType == 'auol'; } + + bool IsFConv () const { return componentType == kAudioUnitType_FormatConverter; } + + bool IsPanner () const { return componentType == kAudioUnitType_Panner; } + + bool IsMusicDevice () const { return componentType == kAudioUnitType_MusicDevice; } + +#ifndef MAC_OS_X_VERSION_10_4 + bool IsGenerator () const { return componentType =='augn'; } +#else + bool IsGenerator () const { return componentType ==kAudioUnitType_Generator; } +#endif + + bool IsOutput () const { return componentType == kAudioUnitType_Output; } + + bool IsSource () const { return IsMusicDevice() || IsGenerator(); } + + OSType Type () const { return componentType; } + OSType SubType () const { return componentSubType; } + OSType Manu () const { return componentManufacturer; } + + int Count() const { return AudioComponentCount(const_cast(this)); } + + // does a semantic match where "wild card" values for type, subtype, manu will match + bool Matches (const AudioComponentDescription &desc) const; + + // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + // + // other + + void Print(FILE* file = stdout) const { _CAShowComponentDescription (this, file); } + + OSStatus Save (CFPropertyListRef *outData) const; + OSStatus Restore (CFPropertyListRef &inData); + +private: + static void _CAShowComponentDescription (const AudioComponentDescription *desc, FILE* file); + friend void CAShowComponentDescription (const AudioComponentDescription *desc); +}; + +inline bool operator< (const AudioComponentDescription& x, const AudioComponentDescription& y) +{ + return memcmp (&x, &y, offsetof (AudioComponentDescription, componentFlags)) < 0; +} + +inline bool operator== (const AudioComponentDescription& x, const AudioComponentDescription& y) +{ + return !memcmp (&x, &y, offsetof (AudioComponentDescription, componentFlags)); +} + +inline bool operator!= (const AudioComponentDescription& x, const AudioComponentDescription& y) +{ + return !(x == y); +} + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CADebugMacros.cpp b/distrho/src/CoreAudio106/PublicUtility/CADebugMacros.cpp new file mode 100755 index 00000000..345cab8c --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CADebugMacros.cpp @@ -0,0 +1,82 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CADebugMacros.h" +#include +#include +#if TARGET_API_MAC_OSX + #include +#endif + +#if DEBUG +#include + +void DebugPrint(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} +#endif // DEBUG + +#if TARGET_API_MAC_OSX +void LogError(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); +#if DEBUG + vprintf(fmt, args); +#endif + vsyslog(LOG_ERR, fmt, args); + va_end(args); +} + +void LogWarning(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); +#if DEBUG + vprintf(fmt, args); +#endif + vsyslog(LOG_WARNING, fmt, args); + va_end(args); +} +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CADebugMacros.h b/distrho/src/CoreAudio106/PublicUtility/CADebugMacros.h new file mode 100755 index 00000000..8ce8af88 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CADebugMacros.h @@ -0,0 +1,448 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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)) + +#pragma mark Basic Definitions + +#if DEBUG || CoreAudio_Debug + + // can be used to break into debugger immediately, also see CADebugger + #define BusError() (*(long *)0 = 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" + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: %s"DebugPrintfLineEnding, pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #elif CoreAudio_TimeStampMessages + #include "CAHostTimeBase.h" + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFileComma "%.4f: %s"DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn + #else + #define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFileComma "%s"DebugPrintfLineEnding, msg) FlushRtn + #define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1) FlushRtn + #define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2) FlushRtn + #define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3) FlushRtn + #define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4) FlushRtn + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5) FlushRtn + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6) FlushRtn + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7) FlushRtn + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7, N8, N9) 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 + + #if CoreAudio_StopOnFailure + #include "CADebugger.h" + #define STOP CADebuggerStop() + #else + #define STOP + #endif + +#else + #define DebugMessage(msg) + #define DebugMessageN1(msg, N1) + #define DebugMessageN2(msg, N1, N2) + #define DebugMessageN3(msg, N1, N2, N3) + #define DebugMessageN4(msg, N1, N2, N3, N4) + #define DebugMessageN5(msg, N1, N2, N3, N4, N5) + #define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) + #define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) + #define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) + #define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) + #ifndef DEBUGPRINT + #define DEBUGPRINT(msg) + #endif + #define vprint(msg) + #define STOP +#endif + +void LogError(const char *fmt, ...); // writes to syslog (and stderr if debugging) +void LogWarning(const char *fmt, ...); // writes to syslog (and stderr if debugging) + +#if DEBUG || CoreAudio_Debug + +#pragma mark Debug Macros + +#define Assert(inCondition, inMessage) \ + if(!(inCondition)) \ + { \ + DebugMessage(inMessage); \ + STOP; \ + } + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + char __4CC[5] = CA4CCToCString(__Err); \ + DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \ + STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + DebugMessageN1(inMessage ", Error: 0x%X", __Err); \ + 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)", __Err, __4CC); \ + STOP; \ + { inAction; } \ + goto inHandler; \ + } \ + } + +#if defined(__cplusplus) + +#define Throw(inException) 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) \ + { \ + unsigned 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)) \ + { \ + STOP; \ + } + +#define AssertNoError(inError, inMessage) \ + { \ + SInt32 __Err = (inError); \ + if(__Err != 0) \ + { \ + STOP; \ + } \ + } + +#define AssertNoKernelError(inError, inMessage) \ + { \ + unsigned int __Err = (unsigned int)(inError); \ + if(__Err != 0) \ + { \ + 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; \ + } + +#if defined(__cplusplus) + +#define Throw(inException) 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) \ + { \ + unsigned 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/distrho/src/CoreAudio106/PublicUtility/CADebugPrintf.cpp b/distrho/src/CoreAudio106/PublicUtility/CADebugPrintf.cpp new file mode 100755 index 00000000..3e77fac3 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CADebugPrintf.cpp @@ -0,0 +1,83 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CADebugPrintf.h" + +#if DEBUG || CoreAudio_Debug + + #if TARGET_OS_WIN32 + #include + #include + #include + extern "C" + int CAWin32DebugPrintf(char* inFormat, ...) + { + char theMessage[1024]; + va_list theArguments; + va_start(theArguments, inFormat); + _vsnprintf(theMessage, 1024, inFormat, theArguments); + va_end(theArguments); + OutputDebugString(theMessage); + return 0; + } + #endif + + #if defined(CoreAudio_UseSideFile) + #include + FILE* sDebugPrintfSideFile = NULL; + extern "C" + void OpenDebugPrintfSideFile() + { + if(sDebugPrintfSideFile == NULL) + { + char theFileName[1024]; + snprintf(theFileName, sizeof(theFileName), CoreAudio_UseSideFile, getpid()); + sDebugPrintfSideFile = fopen(theFileName, "a+"); + DebugPrintfRtn(DebugPrintfFileComma "\n------------------------------\n"); + } + } + #endif + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CADebugPrintf.h b/distrho/src/CoreAudio106/PublicUtility/CADebugPrintf.h new file mode 100755 index 00000000..98d611f6 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CADebugPrintf.h @@ -0,0 +1,107 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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 + +#else + #define DebugPrintfRtn + #define DebugPrintfFile + #define DebugPrintfLineEnding + #define DebugPrintfFileComma +#endif + + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CADebugger.cpp b/distrho/src/CoreAudio106/PublicUtility/CADebugger.cpp new file mode 100755 index 00000000..7f4831e1 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CADebugger.cpp @@ -0,0 +1,71 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CADebugger.h" + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include +#endif + +// on X, use the Unix routine, otherwise use Debugger() +#if TARGET_API_MAC_OSX + #include +#endif + +//============================================================================= +// CADebugger +//============================================================================= + +void CADebuggerStop() +{ + #if CoreAudio_Debug + #if TARGET_API_MAC_OSX + raise(SIGINT); + #else + __debugbreak(); + #endif + #endif +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CADebugger.h b/distrho/src/CoreAudio106/PublicUtility/CADebugger.h new file mode 100755 index 00000000..42fcb270 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CADebugger.h @@ -0,0 +1,50 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CADebugger_h__) +#define __CADebugger_h__ + +//============================================================================= +// CADebugger +//============================================================================= + +extern void CADebuggerStop(); + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAException.h b/distrho/src/CoreAudio106/PublicUtility/CAException.h new file mode 100755 index 00000000..e53fc7db --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAException.h @@ -0,0 +1,77 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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(const CAException& inException) {} catch(...) {} +#define CASwallowException(inExpression) try { inExpression; } catch(...) {} + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAFilePathUtils.cpp b/distrho/src/CoreAudio106/PublicUtility/CAFilePathUtils.cpp new file mode 100755 index 00000000..0150a92d --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAFilePathUtils.cpp @@ -0,0 +1,180 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#include "CAFilePathUtils.h" +#include + +#if !CA_NO_CORE_SERVICES +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include // FSRef +#else + #include +#endif + +OSStatus PosixPathToParentFSRefAndName(const char *path, FSRef &outParentDir, CFStringRef &outFileName) +{ + // convert C string to CFString +#if !TARGET_OS_WIN32 + CFStringRef cfFullPath = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8); +#else + CFStringRef cfFullPath = CFStringCreateWithCString(NULL, path, kCFStringEncodingWindowsLatin1); +#endif + // convert CF string to URL + CFURLRef fullurl = CFURLCreateWithFileSystemPath(NULL, cfFullPath, TARGET_OS_WIN32 ? kCFURLWindowsPathStyle : kCFURLPOSIXPathStyle, false); + CFRelease(cfFullPath); + // get the directory portion of the URL + CFURLRef dirurl = CFURLCreateCopyDeletingLastPathComponent(NULL, fullurl); + // get the directory's FSSpec + OSStatus err = CFURLGetFSRef(dirurl, &outParentDir) ? OSStatus(noErr) : OSStatus(fnfErr); + CFRelease(dirurl); + + CFStringRef lastPathComponent = CFURLCopyLastPathComponent(fullurl); + CFRelease(fullurl); + CFMutableStringRef filename = CFStringCreateMutableCopy(NULL, 0, lastPathComponent); + CFRelease(lastPathComponent); + // convert colons (legal in POSIX paths, illegal in File Manager) to slashes + CFStringFindAndReplace(filename, CFSTR(":"), CFSTR("/"), CFRangeMake(0, CFStringGetLength(filename)), 0); + + outFileName = filename; + + return err; +} +#endif // !CA_NO_CORE_SERVICES + + +#if TARGET_OS_WIN32 + +char* dirname(const char* inPath) +{ + static char sAnswer[1024]; + + char* theAnswer = NULL; + SInt32 thePathLength = strlen(inPath); + if(thePathLength < 1023) + { + // make a working copy + strcpy(sAnswer, inPath); + + // start at the end of the string + SInt32 theIndex = thePathLength - 1; + + // walk back over the '\' characters + while((theIndex > 0) && (sAnswer[theIndex] == '\\')) + { + --theIndex; + } + + // now keep walking back until we get to a '\' + while((theIndex > 0) && (sAnswer[theIndex] != '\\')) + { + --theIndex; + } + + // where we are now is either the first character of the path or the '\' that marks the end of the directory name + if(theIndex > 0) + { + // we have a name so put a '\0' in place of the '\' + sAnswer[theIndex] = 0; + } + else + { + // no name, so the answer is "." + sAnswer[0] = '.'; + sAnswer[1] = 0; + } + + // set the return value + theAnswer = sAnswer; + } + + return theAnswer; +} + +char* basename(const char* inPath) +{ + static char sAnswer[1024]; + + char* theAnswer = NULL; + SInt32 thePathLength = strlen(inPath); + if(thePathLength < 1023) + { + // make a working copy + strcpy(sAnswer, inPath); + + // start at the end of the string + SInt32 theLastIndex = thePathLength - 1; + + // walk back over the '\' characters + while((theLastIndex > 0) && (sAnswer[theLastIndex] == '\\')) + { + --theLastIndex; + } + + // check to see if we're at the beginning now + if(theLastIndex > 0) + { + // there's a name in there now, so start where we are and go back to the next '\' + UInt32 theFirstIndex = theLastIndex; + while((theFirstIndex > 0) && (sAnswer[theFirstIndex] != '\\')) + { + --theFirstIndex; + } + + // we now have a string, so put a '\0' after the last character + sAnswer[theLastIndex + 1] = 0; + + // and set the return value + theAnswer = &sAnswer[theFirstIndex]; + } + else + { + // the path was entirely '\' characters, so the return value is "\" + sAnswer[0] = '\\'; + sAnswer[1] = 0; + + // set the return value + theAnswer = sAnswer; + } + } + + return theAnswer; +} + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAFilePathUtils.h b/distrho/src/CoreAudio106/PublicUtility/CAFilePathUtils.h new file mode 100755 index 00000000..d0bb3d52 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAFilePathUtils.h @@ -0,0 +1,62 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __CAFilePathUtils_h__ +#define __CAFilePathUtils_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include +#else + #include + #include +#endif + +struct FSRef; + +OSStatus PosixPathToParentFSRefAndName(const char *path, FSRef &outParentDir, CFStringRef &outFileName); + +#if !TARGET_OS_WIN32 + #include +#else + char* dirname(const char* inPath); + char* basename(const char* inPath); +#endif + +#endif // __CAFilePathUtils_h__ diff --git a/distrho/src/CoreAudio106/PublicUtility/CAGuard.cpp b/distrho/src/CoreAudio106/PublicUtility/CAGuard.cpp new file mode 100755 index 00000000..c4ebec84 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAGuard.cpp @@ -0,0 +1,333 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAGuard.h" + +#if TARGET_OS_MAC + #include +#endif + +// PublicUtility Inludes +#include "CADebugMacros.h" +#include "CAException.h" +#include "CAHostTimeBase.h" + +//================================================================================================== +// Logging +//================================================================================================== + +#if CoreAudio_Debug +// #define Log_Ownership 1 +// #define Log_WaitOwnership 1 +// #define Log_TimedWaits 1 +// #define Log_Latency 1 +// #define Log_Errors 1 +#endif + +//#warning Need a try-based Locker too +//================================================================================================== +// CAGuard +//================================================================================================== + +CAGuard::CAGuard(const char* inName) +: + CAMutex(inName) +#if Log_Average_Latency + ,mAverageLatencyAccumulator(0.0), + mAverageLatencyCount(0) +#endif +{ +#if TARGET_OS_MAC + OSStatus theError = pthread_cond_init(&mCondVar, NULL); + ThrowIf(theError != 0, CAException(theError), "CAGuard::CAGuard: Could not init the cond var"); +#elif TARGET_OS_WIN32 + mEvent = CreateEvent(NULL, true, false, NULL); + ThrowIfNULL(mEvent, CAException(GetLastError()), "CAGuard::CAGuard: Could not create the event"); +#endif +} + +CAGuard::~CAGuard() +{ +#if TARGET_OS_MAC + pthread_cond_destroy(&mCondVar); +#elif TARGET_OS_WIN32 + if(mEvent != NULL) + { + CloseHandle(mEvent); + } +#endif +} + +void CAGuard::Wait() +{ +#if TARGET_OS_MAC + ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1), "CAGuard::Wait: A thread has to have locked a guard before it can wait"); + + mOwner = 0; + + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::Wait: thread %p is waiting on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + + OSStatus theError = pthread_cond_wait(&mCondVar, &mMutex); + ThrowIf(theError != 0, CAException(theError), "CAGuard::Wait: Could not wait for a signal"); + mOwner = pthread_self(); + + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::Wait: thread %p waited on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif +#elif TARGET_OS_WIN32 + ThrowIf(GetCurrentThreadId() != mOwner, CAException(1), "CAGuard::Wait: A thread has to have locked a guard before it can wait"); + + mOwner = 0; + + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::Wait: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + ReleaseMutex(mMutex); + HANDLE theHandles[] = { mMutex, mEvent }; + OSStatus theError = WaitForMultipleObjects(2, theHandles, true, INFINITE); + ThrowIfError(theError, CAException(GetLastError()), "CAGuard::Wait: Could not wait for the signal"); + mOwner = GetCurrentThreadId(); + ResetEvent(mEvent); + + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::Wait: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif +#endif +} + +bool CAGuard::WaitFor(UInt64 inNanos) +{ + bool theAnswer = false; + +#if TARGET_OS_MAC + ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1), "CAGuard::WaitFor: A thread has to have locked a guard be for it can wait"); + + #if Log_TimedWaits + DebugMessageN1("CAGuard::WaitFor: waiting %.0f", (Float64)inNanos); + #endif + + struct timespec theTimeSpec; + static const UInt64 kNanosPerSecond = 1000000000ULL; + if(inNanos >= kNanosPerSecond) + { + theTimeSpec.tv_sec = static_cast(inNanos / kNanosPerSecond); + theTimeSpec.tv_nsec = static_cast(inNanos % kNanosPerSecond); + } + else + { + theTimeSpec.tv_sec = 0; + theTimeSpec.tv_nsec = static_cast(inNanos); + } + + #if Log_TimedWaits || Log_Latency || Log_Average_Latency + UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos(); + #endif + + mOwner = 0; + + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::WaitFor: thread %p is waiting on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + + OSStatus theError = pthread_cond_timedwait_relative_np(&mCondVar, &mMutex, &theTimeSpec); + ThrowIf((theError != 0) && (theError != ETIMEDOUT), CAException(theError), "CAGuard::WaitFor: Wait got an error"); + mOwner = pthread_self(); + + #if Log_TimedWaits || Log_Latency || Log_Average_Latency + UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos(); + #endif + + #if Log_TimedWaits + DebugMessageN1("CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos)); + #endif + + #if Log_Latency + DebugMessageN1("CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos)); + #endif + + #if Log_Average_Latency + ++mAverageLatencyCount; + mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos; + if(mAverageLatencyCount >= 50) + { + DebugMessageN2("CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount); + mAverageLatencyCount = 0; + mAverageLatencyAccumulator = 0.0; + } + #endif + + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::WaitFor: thread %p waited on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + + theAnswer = theError == ETIMEDOUT; +#elif TARGET_OS_WIN32 + ThrowIf(GetCurrentThreadId() != mOwner, CAException(1), "CAGuard::WaitFor: A thread has to have locked a guard be for it can wait"); + + #if Log_TimedWaits + DebugMessageN1("CAGuard::WaitFor: waiting %.0f", (Float64)inNanos); + #endif + + // the time out is specified in milliseconds(!) + UInt32 theWaitTime = static_cast(inNanos / 1000000ULL); + + #if Log_TimedWaits || Log_Latency || Log_Average_Latency + UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos(); + #endif + + mOwner = 0; + + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::WaitFor: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + ReleaseMutex(mMutex); + HANDLE theHandles[] = { mMutex, mEvent }; + OSStatus theError = WaitForMultipleObjects(2, theHandles, true, theWaitTime); + ThrowIf((theError != WAIT_OBJECT_0) && (theError != WAIT_TIMEOUT), CAException(GetLastError()), "CAGuard::WaitFor: Wait got an error"); + mOwner = GetCurrentThreadId(); + ResetEvent(mEvent); + + #if Log_TimedWaits || Log_Latency || Log_Average_Latency + UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos(); + #endif + + #if Log_TimedWaits + DebugMessageN1("CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos)); + #endif + + #if Log_Latency + DebugMessageN1("CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos)); + #endif + + #if Log_Average_Latency + ++mAverageLatencyCount; + mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos; + if(mAverageLatencyCount >= 50) + { + DebugMessageN2("CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount); + mAverageLatencyCount = 0; + mAverageLatencyAccumulator = 0.0; + } + #endif + + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::WaitFor: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + theAnswer = theError == WAIT_TIMEOUT; +#endif + + return theAnswer; +} + +bool CAGuard::WaitUntil(UInt64 inNanos) +{ + bool theAnswer = false; + UInt64 theCurrentNanos = CAHostTimeBase::GetCurrentTimeInNanos(); + +#if Log_TimedWaits + DebugMessageN2("CAGuard::WaitUntil: now: %.0f, requested: %.0f", (double)theCurrentNanos, (double)inNanos); +#endif + + if(inNanos > theCurrentNanos) + { +#if Log_Errors + if((inNanos - theCurrentNanos) > 1000000000ULL) + { + DebugMessage("CAGuard::WaitUntil: about to wait for more than a second"); + } +#endif + theAnswer = WaitFor(inNanos - theCurrentNanos); + } + else + { +#if Log_Errors + DebugMessageN2("CAGuard::WaitUntil: Time has expired before waiting, now: %.0f, requested: %.0f", (double)theCurrentNanos, (double)inNanos); +#endif + theAnswer = true; + } + + return theAnswer; +} + +void CAGuard::Notify() +{ +#if TARGET_OS_MAC + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::Notify: thread %p is notifying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + + OSStatus theError = pthread_cond_signal(&mCondVar); + ThrowIf(theError != 0, CAException(theError), "CAGuard::Notify: failed"); +#elif TARGET_OS_WIN32 + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::Notify: thread %lu is notifying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + SetEvent(mEvent); +#endif +} + +void CAGuard::NotifyAll() +{ +#if TARGET_OS_MAC + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::NotifyAll: thread %p is notifying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); + #endif + + OSStatus theError = pthread_cond_broadcast(&mCondVar); + ThrowIf(theError != 0, CAException(theError), "CAGuard::NotifyAll: failed"); +#elif TARGET_OS_WIN32 + #if Log_WaitOwnership + DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::NotifyAll: thread %lu is notifying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); + #endif + + SetEvent(mEvent); +#endif +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAGuard.h b/distrho/src/CoreAudio106/PublicUtility/CAGuard.h new file mode 100755 index 00000000..c9e384cb --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAGuard.h @@ -0,0 +1,127 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CAGuard_h__) +#define __CAGuard_h__ + +//================================================================================================== +// Includes +//============================================================================= + +// Super Class Includes +#include "CAMutex.h" + +#if CoreAudio_Debug +// #define Log_Average_Latency 1 +#endif + +//================================================================================================== +// CAGuard +// +// This is your typical mutex with signalling implemented via pthreads. +// Lock() will return true if and only if the guard is locked on that call. +// A thread that already has the guard will receive 'false' if it locks it +// again. Use of the stack-based CAGuard::Locker class is highly recommended +// to properly manage the recursive nesting. The Wait calls with timeouts +// will return true if and only if the timeout period expired. They will +// return false if they receive notification any other way. +//================================================================================================== + +class CAGuard : public CAMutex +{ + +// Construction/Destruction +public: + CAGuard(const char* inName); + virtual ~CAGuard(); + +// Actions +public: + virtual void Wait(); + virtual bool WaitFor(UInt64 inNanos); + virtual bool WaitUntil(UInt64 inNanos); + + virtual void Notify(); + virtual void NotifyAll(); + +// Implementation +protected: +#if TARGET_OS_MAC + pthread_cond_t mCondVar; +#else + HANDLE mEvent; +#endif +#if Log_Average_Latency + Float64 mAverageLatencyAccumulator; + UInt32 mAverageLatencyCount; +#endif + +// Helper class to manage taking and releasing recursively +public: + class Locker + { + + // Construction/Destruction + public: + Locker(CAGuard& inGuard) : mGuard(inGuard), mNeedsRelease(false) { mNeedsRelease = mGuard.Lock(); } + ~Locker() { if(mNeedsRelease) { mGuard.Unlock(); } } + + private: + Locker(const Locker&); + Locker& operator=(const Locker&); + + // Actions + public: + void Wait() { mGuard.Wait(); } + bool WaitFor(UInt64 inNanos) { return mGuard.WaitFor(inNanos); } + bool WaitUntil(UInt64 inNanos) { return mGuard.WaitUntil(inNanos); } + + void Notify() { mGuard.Notify(); } + void NotifyAll() { mGuard.NotifyAll(); } + + // Implementation + private: + CAGuard& mGuard; + bool mNeedsRelease; + }; + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAHALAudioDevice.cpp b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioDevice.cpp new file mode 100755 index 00000000..13e2be67 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioDevice.cpp @@ -0,0 +1,1151 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAHALAudioDevice.h" + +// PublicUtility Includes +#include "CAAutoDisposer.h" +#include "CADebugMacros.h" +#include "CAException.h" +#include "CAHALAudioStream.h" +#include "CAHALAudioSystemObject.h" +#include "CAPropertyAddress.h" + +//================================================================================================== +// CAHALAudioDevice +//================================================================================================== + +CAHALAudioDevice::CAHALAudioDevice(AudioObjectID inAudioDevice) +: + CAHALAudioObject(inAudioDevice) +{ +} + +CAHALAudioDevice::CAHALAudioDevice(CFStringRef inUID) +: + CAHALAudioObject(CAHALAudioSystemObject().GetAudioDeviceForUID(inUID)) +{ +} + +CAHALAudioDevice::~CAHALAudioDevice() +{ +} + +CFStringRef CAHALAudioDevice::CopyDeviceUID() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDeviceUID); + return GetPropertyData_CFString(theAddress, 0, NULL); +} + +bool CAHALAudioDevice::HasModelUID() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyModelUID); + return HasProperty(theAddress); +} + +CFStringRef CAHALAudioDevice::CopyModelUID() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyModelUID); + return GetPropertyData_CFString(theAddress, 0, NULL); +} + +CFStringRef CAHALAudioDevice::CopyConfigurationApplicationBundleID() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyConfigurationApplication); + return GetPropertyData_CFString(theAddress, 0, NULL); +} + +CFURLRef CAHALAudioDevice::CopyIconLocation() const +{ + CFURLRef theAnswer = NULL; + CAPropertyAddress theAddress(kAudioDevicePropertyIcon); + UInt32 theSize = sizeof(CFURLRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +UInt32 CAHALAudioDevice::GetTransportType() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyTransportType); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +bool CAHALAudioDevice::CanBeDefaultDevice(bool inIsInput, bool inIsSystem) const +{ + CAPropertyAddress theAddress(inIsSystem ? kAudioDevicePropertyDeviceCanBeDefaultSystemDevice : kAudioDevicePropertyDeviceCanBeDefaultDevice, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + return GetPropertyData_UInt32(theAddress, 0, NULL) != 0; +} + +bool CAHALAudioDevice::HasDevicePlugInStatus() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlugIn); + return HasProperty(theAddress); +} + +OSStatus CAHALAudioDevice::GetDevicePlugInStatus() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlugIn); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +bool CAHALAudioDevice::IsAlive() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDeviceIsAlive); + return GetPropertyData_UInt32(theAddress, 0, NULL) != 0; +} + +bool CAHALAudioDevice::IsHidden() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyIsHidden); + return GetPropertyData_UInt32(theAddress, 0, NULL) != 0; +} + +pid_t CAHALAudioDevice::GetHogModeOwner() const +{ + pid_t theAnswer = -1; + CAPropertyAddress theAddress(kAudioDevicePropertyHogMode); + if(HasProperty(theAddress)) + { + UInt32 theSize = sizeof(pid_t); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + return theAnswer; +} + +bool CAHALAudioDevice::IsHogModeSettable() const +{ + bool theAnswer = false; + CAPropertyAddress theAddress(kAudioDevicePropertyHogMode); + if(HasProperty(theAddress)) + { + theAnswer = IsPropertySettable(theAddress); + } + return theAnswer; +} + +bool CAHALAudioDevice::TakeHogMode() +{ + CAPropertyAddress theAddress(kAudioDevicePropertyHogMode); + pid_t thePID = getpid(); + if(HasProperty(theAddress)) + { + SetPropertyData(theAddress, 0, NULL, sizeof(pid_t), &thePID); + } + return thePID == getpid(); +} + +void CAHALAudioDevice::ReleaseHogMode() +{ + CAPropertyAddress theAddress(kAudioDevicePropertyHogMode); + if(HasProperty(theAddress)) + { + pid_t thePID = -1; + SetPropertyData(theAddress, 0, NULL, sizeof(pid_t), &thePID); + } +} + +bool CAHALAudioDevice::HasPreferredStereoChannels(bool inIsInput) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelsForStereo, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + return HasProperty(theAddress); +} + +void CAHALAudioDevice::GetPreferredStereoChannels(bool inIsInput, UInt32& outLeft, UInt32& outRight) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelsForStereo, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theStereoPair[2] = { 0, 0 }; + UInt32 theSize = 2 * sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, theStereoPair); + outLeft = theStereoPair[0]; + outRight = theStereoPair[1]; +} + +void CAHALAudioDevice::SetPreferredStereoChannels(bool inIsInput, UInt32 inLeft, UInt32 inRight) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelsForStereo, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theStereoPair[2] = { inLeft, inRight }; + SetPropertyData(theAddress, 0, NULL, 2 * sizeof(UInt32), theStereoPair); +} + +bool CAHALAudioDevice::HasPreferredChannelLayout(bool inIsInput) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelLayout, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + return HasProperty(theAddress); +} + +void CAHALAudioDevice::GetPreferredChannelLayout(bool inIsInput, AudioChannelLayout& outChannelLayout) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelLayout, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theSize = OffsetOf32(AudioChannelLayout, mChannelDescriptions) + GetTotalNumberChannels(inIsInput) * SizeOf32(AudioChannelDescription); + GetPropertyData(theAddress, 0, NULL, theSize, &outChannelLayout); +} + +void CAHALAudioDevice::SetPreferredStereoChannels(bool inIsInput, AudioChannelLayout& inChannelLayout) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPreferredChannelLayout, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theSize = OffsetOf32(AudioChannelLayout, mChannelDescriptions) + GetTotalNumberChannels(inIsInput) * SizeOf32(AudioChannelDescription); + SetPropertyData(theAddress, 0, NULL, theSize, &inChannelLayout); +} + +UInt32 CAHALAudioDevice::GetNumberRelatedAudioDevices() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyRelatedDevices); + UInt32 theAnswer = 0; + if(HasProperty(theAddress)) + { + theAnswer = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer /= sizeof(AudioObjectID); + } + return theAnswer; +} + +void CAHALAudioDevice::GetRelatedAudioDevices(UInt32& ioNumberRelatedDevices, AudioObjectID* outRelatedDevices) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyRelatedDevices); + if(HasProperty(theAddress)) + { + UInt32 theSize = ioNumberRelatedDevices * sizeof(AudioObjectID); + GetPropertyData(theAddress, 0, NULL, theSize, outRelatedDevices); + ioNumberRelatedDevices = theSize / sizeof(AudioObjectID); + } + else + { + UInt32 theSize = ioNumberRelatedDevices * sizeof(AudioObjectID); + memset(outRelatedDevices, 0, theSize); + ioNumberRelatedDevices = 0; + } +} + +AudioObjectID CAHALAudioDevice::GetRelatedAudioDeviceByIndex(UInt32 inIndex) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + UInt32 theNumberRelatedDevices = GetNumberRelatedAudioDevices(); + if((theNumberRelatedDevices > 0) && (inIndex < theNumberRelatedDevices)) + { + CAAutoArrayDelete theRelatedDeviceList(theNumberRelatedDevices); + GetRelatedAudioDevices(theNumberRelatedDevices, theRelatedDeviceList); + if((theNumberRelatedDevices > 0) && (inIndex < theNumberRelatedDevices)) + { + theAnswer = theRelatedDeviceList[inIndex]; + } + } + return theAnswer; +} + +UInt32 CAHALAudioDevice::GetNumberStreams(bool inIsInput) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStreams, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theAnswer = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer /= sizeof(AudioObjectID); + return theAnswer; +} + +void CAHALAudioDevice::GetStreams(bool inIsInput, UInt32& ioNumberStreams, AudioObjectID* outStreamList) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStreams, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theSize = ioNumberStreams * sizeof(AudioObjectID); + GetPropertyData(theAddress, 0, NULL, theSize, outStreamList); + ioNumberStreams = theSize / sizeof(AudioObjectID); +} + +AudioObjectID CAHALAudioDevice::GetStreamByIndex(bool inIsInput, UInt32 inIndex) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + UInt32 theNumberStreams = GetNumberStreams(inIsInput); + if((theNumberStreams > 0) && (inIndex < theNumberStreams)) + { + CAAutoArrayDelete theStreamList(theNumberStreams); + GetStreams(inIsInput, theNumberStreams, theStreamList); + if((theNumberStreams > 0) && (inIndex < theNumberStreams)) + { + theAnswer = theStreamList[inIndex]; + } + } + return theAnswer; +} + +UInt32 CAHALAudioDevice::GetTotalNumberChannels(bool inIsInput) const +{ + UInt32 theAnswer = 0; + CAPropertyAddress theAddress(kAudioDevicePropertyStreamConfiguration, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + UInt32 theSize = GetPropertyDataSize(theAddress, 0, NULL); + CAAutoFree theBufferList(theSize); + GetPropertyData(theAddress, 0, NULL, theSize, theBufferList); + for(UInt32 theIndex = 0; theIndex < theBufferList->mNumberBuffers; ++theIndex) + { + theAnswer += theBufferList->mBuffers[theIndex].mNumberChannels; + } + return theAnswer; +} + +void CAHALAudioDevice::GetCurrentVirtualFormats(bool inIsInput, UInt32& ioNumberStreams, AudioStreamBasicDescription* outFormats) const +{ + ioNumberStreams = std::min(ioNumberStreams, GetNumberStreams(inIsInput)); + for(UInt32 theIndex = 0; theIndex < ioNumberStreams; ++theIndex) + { + CAHALAudioStream theStream(GetStreamByIndex(inIsInput, theIndex)); + theStream.GetCurrentVirtualFormat(outFormats[theIndex]); + } +} + +void CAHALAudioDevice::GetCurrentPhysicalFormats(bool inIsInput, UInt32& ioNumberStreams, AudioStreamBasicDescription* outFormats) const +{ + ioNumberStreams = std::min(ioNumberStreams, GetNumberStreams(inIsInput)); + for(UInt32 theIndex = 0; theIndex < ioNumberStreams; ++theIndex) + { + CAHALAudioStream theStream(GetStreamByIndex(inIsInput, theIndex)); + theStream.GetCurrentPhysicalFormat(outFormats[theIndex]); + } +} + +bool CAHALAudioDevice::IsRunning() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDeviceIsRunning); + UInt32 theAnswer = GetPropertyData_UInt32(theAddress, 0, NULL); + return theAnswer != 0; +} + +bool CAHALAudioDevice::IsRunningSomewhere() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDeviceIsRunningSomewhere); + UInt32 theAnswer = 0; + if(HasProperty(theAddress)) + { + theAnswer = GetPropertyData_UInt32(theAddress, 0, NULL); + } + return theAnswer != 0; +} + +UInt32 CAHALAudioDevice::GetLatency(bool inIsInput) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyLatency, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +UInt32 CAHALAudioDevice::GetSafetyOffset(bool inIsInput) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySafetyOffset, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +bool CAHALAudioDevice::HasClockDomain() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockDomain); + return HasProperty(theAddress); +} + +UInt32 CAHALAudioDevice::GetClockDomain() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockDomain); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +Float64 CAHALAudioDevice::GetActualSampleRate() const +{ + Float64 theAnswer = 0; + CAPropertyAddress theAddress(kAudioDevicePropertyActualSampleRate); + if(HasProperty(theAddress)) + { + UInt32 theSize = sizeof(Float64); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + else + { + theAnswer = GetNominalSampleRate(); + } + return theAnswer; +} + +Float64 CAHALAudioDevice::GetNominalSampleRate() const +{ + Float64 theAnswer = 0; + CAPropertyAddress theAddress(kAudioDevicePropertyNominalSampleRate); + UInt32 theSize = sizeof(Float64); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioDevice::SetNominalSampleRate(Float64 inSampleRate) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyNominalSampleRate); + SetPropertyData(theAddress, 0, NULL, sizeof(Float64), &inSampleRate); +} + +UInt32 CAHALAudioDevice::GetNumberAvailableNominalSampleRateRanges() const +{ + UInt32 theAnswer = 0; + CAPropertyAddress theAddress(kAudioDevicePropertyAvailableNominalSampleRates); + if(HasProperty(theAddress)) + { + UInt32 theSize = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer = theSize / sizeof(AudioValueRange); + } + return theAnswer; +} + +void CAHALAudioDevice::GetAvailableNominalSampleRateRanges(UInt32& ioNumberRanges, AudioValueRange* outRanges) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyAvailableNominalSampleRates); + if(HasProperty(theAddress)) + { + UInt32 theSize = ioNumberRanges * sizeof(AudioValueRange); + GetPropertyData(theAddress, 0, NULL, theSize, outRanges); + ioNumberRanges = theSize / sizeof(AudioValueRange); + } + else + { + ioNumberRanges = 0; + } +} + +void CAHALAudioDevice::GetAvailableNominalSampleRateRangeByIndex(UInt32 inIndex, Float64& outMinimum, Float64& outMaximum) const +{ + UInt32 theNumberRanges = GetNumberAvailableNominalSampleRateRanges(); + ThrowIf(inIndex >= theNumberRanges, CAException(kAudioHardwareIllegalOperationError), "CAHALAudioDevice::GetAvailableNominalSampleRateRangeByIndex: index out of range"); + CAAutoArrayDelete theRanges(theNumberRanges); + GetAvailableNominalSampleRateRanges(theNumberRanges, theRanges); + outMinimum = theRanges[inIndex].mMinimum; + outMaximum = theRanges[inIndex].mMaximum; +} + +bool CAHALAudioDevice::IsValidNominalSampleRate(Float64 inSampleRate) const +{ + bool theAnswer = false; + UInt32 theNumberRanges = GetNumberAvailableNominalSampleRateRanges(); + CAAutoArrayDelete theRanges(theNumberRanges); + GetAvailableNominalSampleRateRanges(theNumberRanges, theRanges); + for(UInt32 theIndex = 0; !theAnswer && (theIndex < theNumberRanges); ++theIndex) + { + theAnswer = (inSampleRate >= theRanges[theIndex].mMinimum) && (inSampleRate <= theRanges[theIndex].mMinimum); + } + return theAnswer; +} + +bool CAHALAudioDevice::IsIOBufferSizeSettable() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyBufferFrameSize); + return IsPropertySettable(theAddress); +} + +UInt32 CAHALAudioDevice::GetIOBufferSize() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyBufferFrameSize); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +void CAHALAudioDevice::SetIOBufferSize(UInt32 inBufferSize) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyBufferFrameSize); + SetPropertyData(theAddress, 0, NULL, sizeof(UInt32), &inBufferSize); +} + +bool CAHALAudioDevice::UsesVariableIOBufferSizes() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyUsesVariableBufferFrameSizes); + return HasProperty(theAddress); +} + +UInt32 CAHALAudioDevice::GetMaximumVariableIOBufferSize() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyUsesVariableBufferFrameSizes); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +bool CAHALAudioDevice::HasIOBufferSizeRange() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyBufferFrameSizeRange); + return HasProperty(theAddress); +} + +void CAHALAudioDevice::GetIOBufferSizeRange(UInt32& outMinimum, UInt32& outMaximum) const +{ + AudioValueRange theAnswer = { 0, 0 }; + CAPropertyAddress theAddress(kAudioDevicePropertyBufferFrameSizeRange); + UInt32 theSize = sizeof(AudioValueRange); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + outMinimum = static_cast(theAnswer.mMinimum); + outMaximum = static_cast(theAnswer.mMaximum); +} + +AudioDeviceIOProcID CAHALAudioDevice::CreateIOProcID(AudioDeviceIOProc inIOProc, void* inClientData) +{ + AudioDeviceIOProcID theAnswer = NULL; + OSStatus theError = AudioDeviceCreateIOProcID(mObjectID, inIOProc, inClientData, &theAnswer); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::CreateIOProcID: got an error creating the IOProc ID"); + return theAnswer; +} + +void CAHALAudioDevice::DestroyIOProcID(AudioDeviceIOProcID inIOProcID) +{ + OSStatus theError = AudioDeviceDestroyIOProcID(mObjectID, inIOProcID); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::DestroyIOProcID: got an error destroying the IOProc ID"); +} + +void CAHALAudioDevice::StartIOProc(AudioDeviceIOProcID inIOProcID) +{ + OSStatus theError = AudioDeviceStart(mObjectID, inIOProcID); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::StartIOProc: got an error starting an IOProc"); +} + +void CAHALAudioDevice::StartIOProcAtTime(AudioDeviceIOProcID inIOProcID, AudioTimeStamp& ioStartTime, bool inIsInput, bool inIgnoreHardware) +{ + UInt32 theFlags = 0; + if(inIsInput) + { + theFlags |= kAudioDeviceStartTimeIsInputFlag; + } + if(inIgnoreHardware) + { + theFlags |= kAudioDeviceStartTimeDontConsultDeviceFlag; + } + + OSStatus theError = AudioDeviceStartAtTime(mObjectID, inIOProcID, &ioStartTime, theFlags); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::StartIOProcAtTime: got an error starting an IOProc"); +} + +void CAHALAudioDevice::StopIOProc(AudioDeviceIOProcID inIOProcID) +{ + OSStatus theError = AudioDeviceStop(mObjectID, inIOProcID); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::StopIOProc: got an error stopping an IOProc"); +} + +void CAHALAudioDevice::GetIOProcStreamUsage(AudioDeviceIOProcID inIOProcID, bool inIsInput, bool* outStreamUsage) const +{ + // make an AudioHardwareIOProcStreamUsage the right size + UInt32 theNumberStreams = GetNumberStreams(inIsInput); + UInt32 theSize = sizeof(void*) + sizeof(UInt32) + (theNumberStreams * sizeof(UInt32)); + CAAutoFree theStreamUsage(theSize); + + // set it up + theStreamUsage->mIOProc = reinterpret_cast(inIOProcID); + theStreamUsage->mNumberStreams = theNumberStreams; + + // get the property + CAPropertyAddress theAddress(kAudioDevicePropertyIOProcStreamUsage, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + GetPropertyData(theAddress, 0, NULL, theSize, theStreamUsage); + + // fill out the return value + for(UInt32 theIndex = 0; theIndex < theNumberStreams; ++theIndex) + { + outStreamUsage[theIndex] = (theStreamUsage->mStreamIsOn[theIndex] != 0); + } +} + +void CAHALAudioDevice::SetIOProcStreamUsage(AudioDeviceIOProcID inIOProcID, bool inIsInput, const bool* inStreamUsage) +{ + // make an AudioHardwareIOProcStreamUsage the right size + UInt32 theNumberStreams = GetNumberStreams(inIsInput); + UInt32 theSize = sizeof(void*) + sizeof(UInt32) + (theNumberStreams * sizeof(UInt32)); + CAAutoFree theStreamUsage(theSize); + + // set it up + theStreamUsage->mIOProc = reinterpret_cast(inIOProcID); + theStreamUsage->mNumberStreams = theNumberStreams; + for(UInt32 theIndex = 0; theIndex < theNumberStreams; ++theIndex) + { + theStreamUsage->mStreamIsOn[theIndex] = (inStreamUsage[theIndex] ? 1 : 0); + } + + // set the property + CAPropertyAddress theAddress(kAudioDevicePropertyIOProcStreamUsage, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput); + SetPropertyData(theAddress, 0, NULL, theSize, theStreamUsage); +} + +Float32 CAHALAudioDevice::GetIOCycleUsage() const +{ + Float32 theAnswer = 0; + CAPropertyAddress theAddress(kAudioDevicePropertyIOCycleUsage); + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioDevice::SetIOCycleUsage(Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyIOCycleUsage); + SetPropertyData(theAddress, 0, NULL, sizeof(Float32), &inValue); +} + +void CAHALAudioDevice::GetCurrentTime(AudioTimeStamp& outTime) +{ + OSStatus theError = AudioDeviceGetCurrentTime(mObjectID, &outTime); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::GetCurrentTime: got an error getting the current time"); +} + +void CAHALAudioDevice::TranslateTime(const AudioTimeStamp& inTime, AudioTimeStamp& outTime) +{ + OSStatus theError = AudioDeviceTranslateTime(mObjectID, &inTime, &outTime); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::TranslateTime: got an error translating time"); +} + +void CAHALAudioDevice::GetNearestStartTime(AudioTimeStamp& ioTime, bool inIsInput, bool inIgnoreHardware) +{ + UInt32 theFlags = 0; + if(inIsInput) + { + theFlags |= kAudioDeviceStartTimeIsInputFlag; + } + if(inIgnoreHardware) + { + theFlags |= kAudioDeviceStartTimeDontConsultDeviceFlag; + } + + OSStatus theError = AudioDeviceGetNearestStartTime(mObjectID, &ioTime, theFlags); + ThrowIfError(theError, CAException(theError), "CAHALAudioDevice::GetNearestStartTime: got an error getting the start time"); +} + +bool CAHALAudioDevice::HasVolumeControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeScalar, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::VolumeControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeScalar, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +Float32 CAHALAudioDevice::GetVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeScalar, inScope, inChannel); + Float32 theValue = 0.0f; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +Float32 CAHALAudioDevice::GetVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeDecibels, inScope, inChannel); + Float32 theValue = 0.0f; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +void CAHALAudioDevice::SetVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeScalar, inScope, inChannel); + SetPropertyData(theAddress, 0, NULL, sizeof(Float32), &inValue); +} + +void CAHALAudioDevice::SetVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeDecibels, inScope, inChannel); + SetPropertyData(theAddress, 0, NULL, sizeof(Float32), &inValue); +} + +Float32 CAHALAudioDevice::GetVolumeControlScalarForDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeDecibelsToScalar, inScope, inChannel); + Float32 theValue = inValue; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +Float32 CAHALAudioDevice::GetVolumeControlDecibelForScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyVolumeScalarToDecibels, inScope, inChannel); + Float32 theValue = inValue; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +bool CAHALAudioDevice::HasSubVolumeControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeScalar, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::SubVolumeControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeScalar, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +Float32 CAHALAudioDevice::GetSubVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeScalar, inScope, inChannel); + Float32 theValue = 0.0f; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +Float32 CAHALAudioDevice::GetSubVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeDecibels, inScope, inChannel); + Float32 theValue = 0.0f; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +void CAHALAudioDevice::SetSubVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeScalar, inScope, inChannel); + SetPropertyData(theAddress, 0, NULL, sizeof(Float32), &inValue); +} + +void CAHALAudioDevice::SetSubVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeDecibels, inScope, inChannel); + SetPropertyData(theAddress, 0, NULL, sizeof(Float32), &inValue); +} + +Float32 CAHALAudioDevice::GetSubVolumeControlScalarForDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeDecibelsToScalar, inScope, inChannel); + Float32 theValue = inValue; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +Float32 CAHALAudioDevice::GetSubVolumeControlDecibelForScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubVolumeScalarToDecibels, inScope, inChannel); + Float32 theValue = inValue; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +bool CAHALAudioDevice::HasMuteControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyMute, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::MuteControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyMute, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +bool CAHALAudioDevice::GetMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyMute, inScope, inChannel); + UInt32 theValue = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue != 0; +} + +void CAHALAudioDevice::SetMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyMute, inScope, inChannel); + UInt32 theValue = (inValue ? 1 : 0); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &theValue); +} + +bool CAHALAudioDevice::HasSoloControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySolo, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::SoloControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySolo, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +bool CAHALAudioDevice::GetSoloControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySolo, inScope, inChannel); + UInt32 theValue = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue != 0; +} + +void CAHALAudioDevice::SetSoloControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertySolo, inScope, inChannel); + UInt32 theValue = (inValue ? 1 : 0); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &theValue); +} + +bool CAHALAudioDevice::HasStereoPanControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStereoPan, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::StereoPanControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStereoPan, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +Float32 CAHALAudioDevice::GetStereoPanControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStereoPan, inScope, inChannel); + Float32 theValue = 0.0f; + UInt32 theSize = sizeof(Float32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue; +} + +void CAHALAudioDevice::SetStereoPanControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStereoPan, inScope, inChannel); + UInt32 theSize = sizeof(Float32); + SetPropertyData(theAddress, 0, NULL, theSize, &inValue); +} + +void CAHALAudioDevice::GetStereoPanControlChannels(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& outLeftChannel, UInt32& outRightChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyStereoPan, inScope, inChannel); + UInt32 theValue[2] = { 0, 0 }; + UInt32 theSize = 2 * sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, theValue); + outLeftChannel = theValue[0]; + outRightChannel = theValue[1]; +} + +bool CAHALAudioDevice::HasJackControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyJackIsConnected, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::GetJackControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyJackIsConnected, inScope, inChannel); + UInt32 theValue = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue != 0; +} + +bool CAHALAudioDevice::HasSubMuteControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubMute, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::SubMuteControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubMute, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +bool CAHALAudioDevice::GetSubMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubMute, inScope, inChannel); + UInt32 theValue = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue != 0; +} + +void CAHALAudioDevice::SetSubMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertySubMute, inScope, inChannel); + UInt32 theValue = (inValue ? 1 : 0); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &theValue); +} + +bool CAHALAudioDevice::HasiSubOwnerControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDriverShouldOwniSub, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::iSubOwnerControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDriverShouldOwniSub, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +bool CAHALAudioDevice::GetiSubOwnerControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDriverShouldOwniSub, inScope, inChannel); + UInt32 theValue = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theValue != 0; +} + +void CAHALAudioDevice::SetiSubOwnerControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDriverShouldOwniSub, inScope, inChannel); + UInt32 theValue = (inValue ? 1 : 0); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &theValue); +} + +bool CAHALAudioDevice::HasDataSourceControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSource, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::DataSourceControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSource, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +UInt32 CAHALAudioDevice::GetCurrentDataSourceID(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSource, inScope, inChannel); + UInt32 theAnswer = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioDevice::SetCurrentDataSourceByID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSource, inScope, inChannel); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &inID); +} + +UInt32 CAHALAudioDevice::GetNumberAvailableDataSources(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSources, inScope, inChannel); + UInt32 theAnswer = 0; + if(HasProperty(theAddress)) + { + UInt32 theSize = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer = theSize / sizeof(UInt32); + } + return theAnswer; +} + +void CAHALAudioDevice::GetAvailableDataSources(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& ioNumberSources, UInt32* outSources) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSources, inScope, inChannel); + UInt32 theNumberSources = std::min(GetNumberAvailableDataSources(inScope, inChannel), ioNumberSources); + UInt32 theSize = theNumberSources * sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, outSources); + ioNumberSources = theSize / sizeof(UInt32); +} + +UInt32 CAHALAudioDevice::GetAvailableDataSourceByIndex(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inIndex) const +{ + AudioStreamID theAnswer = 0; + UInt32 theNumberSources = GetNumberAvailableDataSources(inScope, inChannel); + if((theNumberSources > 0) && (inIndex < theNumberSources)) + { + CAAutoArrayDelete theSourceList(theNumberSources); + GetAvailableDataSources(inScope, inChannel, theNumberSources, theSourceList); + theAnswer = theSourceList[inIndex]; + } + return theAnswer; +} + +CFStringRef CAHALAudioDevice::CopyDataSourceNameForID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyDataSourceNameForIDCFString, inScope, inChannel); + CFStringRef theAnswer = NULL; + AudioValueTranslation theTranslation = { &inID, sizeof(UInt32), &theAnswer, sizeof(CFStringRef) }; + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theTranslation); + return theAnswer; +} + +bool CAHALAudioDevice::HasDataDestinationControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestination, inScope, inChannel); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::DataDestinationControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestination, inScope, inChannel); + return IsPropertySettable(theAddress); +} + +UInt32 CAHALAudioDevice::GetCurrentDataDestinationID(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestination, inScope, inChannel); + UInt32 theAnswer = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioDevice::SetCurrentDataDestinationByID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestination, inScope, inChannel); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &inID); +} + +UInt32 CAHALAudioDevice::GetNumberAvailableDataDestinations(AudioObjectPropertyScope inScope, UInt32 inChannel) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestinations, inScope, inChannel); + UInt32 theAnswer = 0; + if(HasProperty(theAddress)) + { + UInt32 theSize = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer = theSize / sizeof(UInt32); + } + return theAnswer; +} + +void CAHALAudioDevice::GetAvailableDataDestinations(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& ioNumberDestinations, UInt32* outDestinations) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestinations, inScope, inChannel); + UInt32 theNumberDestinations = std::min(GetNumberAvailableDataDestinations(inScope, inChannel), ioNumberDestinations); + UInt32 theSize = theNumberDestinations * sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, outDestinations); + ioNumberDestinations = theSize / sizeof(UInt32); +} + +UInt32 CAHALAudioDevice::GetAvailableDataDestinationByIndex(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inIndex) const +{ + AudioStreamID theAnswer = 0; + UInt32 theNumberDestinations = GetNumberAvailableDataDestinations(inScope, inChannel); + if((theNumberDestinations > 0) && (inIndex < theNumberDestinations)) + { + CAAutoArrayDelete theDestinationList(theNumberDestinations); + GetAvailableDataDestinations(inScope, inChannel, theNumberDestinations, theDestinationList); + theAnswer = theDestinationList[inIndex]; + } + return theAnswer; +} + +CFStringRef CAHALAudioDevice::CopyDataDestinationNameForID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyPlayThruDestinationNameForIDCFString, inScope, inChannel); + CFStringRef theAnswer = NULL; + AudioValueTranslation theTranslation = { &inID, sizeof(UInt32), &theAnswer, sizeof(CFStringRef) }; + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theTranslation); + return theAnswer; +} + +bool CAHALAudioDevice::HasClockSourceControl() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSource); + return HasProperty(theAddress); +} + +bool CAHALAudioDevice::ClockSourceControlIsSettable() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSource); + return IsPropertySettable(theAddress); +} + +UInt32 CAHALAudioDevice::GetCurrentClockSourceID() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSource); + UInt32 theAnswer = 0; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioDevice::SetCurrentClockSourceByID(UInt32 inID) +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSource); + UInt32 theSize = sizeof(UInt32); + SetPropertyData(theAddress, 0, NULL, theSize, &inID); +} + +UInt32 CAHALAudioDevice::GetNumberAvailableClockSources() const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSources); + UInt32 theAnswer = 0; + if(HasProperty(theAddress)) + { + UInt32 theSize = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer = theSize / sizeof(UInt32); + } + return theAnswer; +} + +void CAHALAudioDevice::GetAvailableClockSources(UInt32& ioNumberSources, UInt32* outSources) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSources); + UInt32 theNumberSources = std::min(GetNumberAvailableClockSources(), ioNumberSources); + UInt32 theSize = theNumberSources * sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, outSources); + ioNumberSources = theSize / sizeof(UInt32); +} + +UInt32 CAHALAudioDevice::GetAvailableClockSourceByIndex(UInt32 inIndex) const +{ + AudioStreamID theAnswer = 0; + UInt32 theNumberSources = GetNumberAvailableClockSources(); + if((theNumberSources > 0) && (inIndex < theNumberSources)) + { + CAAutoArrayDelete theSourceList(theNumberSources); + GetAvailableClockSources(theNumberSources, theSourceList); + theAnswer = theSourceList[inIndex]; + } + return theAnswer; +} + +CFStringRef CAHALAudioDevice::CopyClockSourceNameForID(UInt32 inID) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSourceNameForIDCFString); + CFStringRef theAnswer = NULL; + AudioValueTranslation theTranslation = { &inID, sizeof(UInt32), &theAnswer, sizeof(CFStringRef) }; + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theTranslation); + return theAnswer; +} + +UInt32 CAHALAudioDevice::GetClockSourceKindForID(UInt32 inID) const +{ + CAPropertyAddress theAddress(kAudioDevicePropertyClockSourceKindForID); + UInt32 theAnswer = inID; + UInt32 theSize = sizeof(UInt32); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAHALAudioDevice.h b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioDevice.h new file mode 100755 index 00000000..ef75e4f2 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioDevice.h @@ -0,0 +1,219 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CAHALAudioDevice_h__) +#define __CAHALAudioDevice_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// Super Class Includes +#include "CAHALAudioObject.h" + +//================================================================================================== +// CAHALAudioDevice +//================================================================================================== + +class CAHALAudioDevice +: + public CAHALAudioObject +{ + +// Construction/Destruction +public: + CAHALAudioDevice(AudioObjectID inAudioDevice); + CAHALAudioDevice(CFStringRef inUID); + virtual ~CAHALAudioDevice(); + +// General Stuff +public: + CFStringRef CopyDeviceUID() const; + bool HasModelUID() const; + CFStringRef CopyModelUID() const; + CFStringRef CopyConfigurationApplicationBundleID() const; + CFURLRef CopyIconLocation() const; + UInt32 GetTransportType() const; + bool CanBeDefaultDevice(bool inIsInput, bool inIsSystem) const; + bool HasDevicePlugInStatus() const; + OSStatus GetDevicePlugInStatus() const; + bool IsAlive() const; + bool IsHidden() const; + pid_t GetHogModeOwner() const; + bool IsHogModeSettable() const; + bool TakeHogMode(); + void ReleaseHogMode(); + bool HasPreferredStereoChannels(bool inIsInput) const; + void GetPreferredStereoChannels(bool inIsInput, UInt32& outLeft, UInt32& outRight) const; + void SetPreferredStereoChannels(bool inIsInput, UInt32 inLeft, UInt32 inRight); + bool HasPreferredChannelLayout(bool inIsInput) const; + void GetPreferredChannelLayout(bool inIsInput, AudioChannelLayout& outChannelLayout) const; + void SetPreferredStereoChannels(bool inIsInput, AudioChannelLayout& inChannelLayout); + UInt32 GetNumberRelatedAudioDevices() const; + void GetRelatedAudioDevices(UInt32& ioNumberRelatedDevices, AudioObjectID* outRelatedDevices) const; + AudioObjectID GetRelatedAudioDeviceByIndex(UInt32 inIndex) const; + +// Stream Stuff +public: + UInt32 GetNumberStreams(bool inIsInput) const; + void GetStreams(bool inIsInput, UInt32& ioNumberStreams, AudioObjectID* outStreamList) const; + AudioObjectID GetStreamByIndex(bool inIsInput, UInt32 inIndex) const; + UInt32 GetTotalNumberChannels(bool inIsInput) const; + void GetCurrentVirtualFormats(bool inIsInput, UInt32& ioNumberStreams, AudioStreamBasicDescription* outFormats) const; + void GetCurrentPhysicalFormats(bool inIsInput, UInt32& ioNumberStreams, AudioStreamBasicDescription* outFormats) const; + +// IO Stuff +public: + bool IsRunning() const; + bool IsRunningSomewhere() const; + UInt32 GetLatency(bool inIsInput) const; + UInt32 GetSafetyOffset(bool inIsInput) const; + bool HasClockDomain() const; + UInt32 GetClockDomain() const; + Float64 GetActualSampleRate() const; + Float64 GetNominalSampleRate() const; + void SetNominalSampleRate(Float64 inSampleRate); + UInt32 GetNumberAvailableNominalSampleRateRanges() const; + void GetAvailableNominalSampleRateRanges(UInt32& ioNumberRanges, AudioValueRange* outRanges) const; + void GetAvailableNominalSampleRateRangeByIndex(UInt32 inIndex, Float64& outMinimum, Float64& outMaximum) const; + bool IsValidNominalSampleRate(Float64 inSampleRate) const; + bool IsIOBufferSizeSettable() const; + UInt32 GetIOBufferSize() const; + void SetIOBufferSize(UInt32 inBufferSize); + bool UsesVariableIOBufferSizes() const; + UInt32 GetMaximumVariableIOBufferSize() const; + bool HasIOBufferSizeRange() const; + void GetIOBufferSizeRange(UInt32& outMinimum, UInt32& outMaximum) const; + AudioDeviceIOProcID CreateIOProcID(AudioDeviceIOProc inIOProc, void* inClientData); + void DestroyIOProcID(AudioDeviceIOProcID inIOProcID); + void StartIOProc(AudioDeviceIOProcID inIOProcID); + void StartIOProcAtTime(AudioDeviceIOProcID inIOProcID, AudioTimeStamp& ioStartTime, bool inIsInput, bool inIgnoreHardware); + void StopIOProc(AudioDeviceIOProcID inIOProcID); + void GetIOProcStreamUsage(AudioDeviceIOProcID inIOProcID, bool inIsInput, bool* outStreamUsage) const; + void SetIOProcStreamUsage(AudioDeviceIOProcID inIOProcID, bool inIsInput, const bool* inStreamUsage); + Float32 GetIOCycleUsage() const; + void SetIOCycleUsage(Float32 inValue); + +// Time Operations +public: + void GetCurrentTime(AudioTimeStamp& outTime); + void TranslateTime(const AudioTimeStamp& inTime, AudioTimeStamp& outTime); + void GetNearestStartTime(AudioTimeStamp& ioTime, bool inIsInput, bool inIgnoreHardware); + +// Controls +public: + bool HasVolumeControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool VolumeControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + Float32 GetVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + Float32 GetVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue); + void SetVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue); + Float32 GetVolumeControlScalarForDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const; + Float32 GetVolumeControlDecibelForScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const; + + bool HasSubVolumeControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool SubVolumeControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + Float32 GetSubVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + Float32 GetSubVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetSubVolumeControlScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue); + void SetSubVolumeControlDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue); + Float32 GetSubVolumeControlScalarForDecibelValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const; + Float32 GetSubVolumeControlDecibelForScalarValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue) const; + + bool HasMuteControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool MuteControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool GetMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue); + + bool HasSoloControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool SoloControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool GetSoloControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetSoloControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue); + + bool HasStereoPanControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool StereoPanControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + Float32 GetStereoPanControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetStereoPanControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, Float32 inValue); + void GetStereoPanControlChannels(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& outLeftChannel, UInt32& outRightChannel) const; + + bool HasJackControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool GetJackControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + + bool HasSubMuteControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool SubMuteControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool GetSubMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetSubMuteControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue); + + bool HasiSubOwnerControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool iSubOwnerControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool GetiSubOwnerControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetiSubOwnerControlValue(AudioObjectPropertyScope inScope, UInt32 inChannel, bool inValue); + + bool HasDataSourceControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool DataSourceControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + UInt32 GetCurrentDataSourceID(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetCurrentDataSourceByID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID); + UInt32 GetNumberAvailableDataSources(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void GetAvailableDataSources(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& ioNumberSources, UInt32* outSources) const; + UInt32 GetAvailableDataSourceByIndex(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inIndex) const; + CFStringRef CopyDataSourceNameForID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) const; + + bool HasDataDestinationControl(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + bool DataDestinationControlIsSettable(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + UInt32 GetCurrentDataDestinationID(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void SetCurrentDataDestinationByID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID); + UInt32 GetNumberAvailableDataDestinations(AudioObjectPropertyScope inScope, UInt32 inChannel) const; + void GetAvailableDataDestinations(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32& ioNumberDestinations, UInt32* outDestinations) const; + UInt32 GetAvailableDataDestinationByIndex(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inIndex) const; + CFStringRef CopyDataDestinationNameForID(AudioObjectPropertyScope inScope, UInt32 inChannel, UInt32 inID) const; + + bool HasClockSourceControl() const; + bool ClockSourceControlIsSettable() const; + UInt32 GetCurrentClockSourceID() const; + void SetCurrentClockSourceByID(UInt32 inID); + UInt32 GetNumberAvailableClockSources() const; + void GetAvailableClockSources(UInt32& ioNumberSources, UInt32* outSources) const; + UInt32 GetAvailableClockSourceByIndex(UInt32 inIndex) const; + CFStringRef CopyClockSourceNameForID(UInt32 inID) const; + UInt32 GetClockSourceKindForID(UInt32 inID) const; + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAHALAudioObject.cpp b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioObject.cpp new file mode 100755 index 00000000..703b79be --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioObject.cpp @@ -0,0 +1,357 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAHALAudioObject.h" + +// PublicUtility Includes +#include "CAAutoDisposer.h" +#include "CADebugMacros.h" +#include "CAException.h" +#include "CAPropertyAddress.h" + +//================================================================================================== +// CAHALAudioObject +//================================================================================================== + +CAHALAudioObject::CAHALAudioObject(AudioObjectID inObjectID) +: + mObjectID(inObjectID) +{ +} + +CAHALAudioObject::~CAHALAudioObject() +{ +} + +AudioObjectID CAHALAudioObject::GetObjectID() const +{ + return mObjectID; +} + +void CAHALAudioObject::SetObjectID(AudioObjectID inObjectID) +{ + mObjectID = inObjectID; +} + +AudioClassID CAHALAudioObject::GetClassID() const +{ + // set up the return value + AudioClassID theAnswer = 0; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyClass); + + // make sure the property exists + if(HasProperty(theAddress)) + { + UInt32 theSize = sizeof(AudioClassID); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +AudioObjectID CAHALAudioObject::GetOwnerObjectID() const +{ + // set up the return value + AudioObjectID theAnswer = 0; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyOwner); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(AudioObjectID); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyOwningPlugInBundleID() const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyCreator); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyName() const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyName); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyManufacturer() const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyManufacturer); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyElementName, inScope, inElement); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyCategoryNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyElementCategoryName, inScope, inElement); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +CFStringRef CAHALAudioObject::CopyNumberNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const +{ + // set up the return value + CFStringRef theAnswer = NULL; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyElementNumberName, inScope, inElement); + + // make sure the property exists + if(HasProperty(theAddress)) + { + // get the property data + UInt32 theSize = sizeof(CFStringRef); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + } + + return theAnswer; +} + +UInt32 CAHALAudioObject::GetNumberOwnedObjects(AudioClassID inClass) const +{ + // set up the return value + UInt32 theAnswer = 0; + + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyOwnedObjects); + + // figure out the qualifier + UInt32 theQualifierSize = 0; + void* theQualifierData = NULL; + if(inClass != 0) + { + theQualifierSize = sizeof(AudioObjectID); + theQualifierData = &inClass; + } + + // get the property data size + theAnswer = GetPropertyDataSize(theAddress, theQualifierSize, theQualifierData); + + // calculate the number of object IDs + theAnswer /= sizeof(AudioObjectID); + + return theAnswer; +} + +void CAHALAudioObject::GetAllOwnedObjects(AudioClassID inClass, UInt32& ioNumberObjects, AudioObjectID* ioObjectIDs) const +{ + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyOwnedObjects); + + // figure out the qualifier + UInt32 theQualifierSize = 0; + void* theQualifierData = NULL; + if(inClass != 0) + { + theQualifierSize = sizeof(AudioObjectID); + theQualifierData = &inClass; + } + + // get the property data + UInt32 theDataSize = ioNumberObjects * sizeof(AudioClassID); + GetPropertyData(theAddress, theQualifierSize, theQualifierData, theDataSize, ioObjectIDs); + + // set the number of object IDs being returned + ioNumberObjects = theDataSize / sizeof(AudioObjectID); +} + +AudioObjectID CAHALAudioObject::GetOwnedObjectByIndex(AudioClassID inClass, UInt32 inIndex) +{ + // set up the property address + CAPropertyAddress theAddress(kAudioObjectPropertyOwnedObjects); + + // figure out the qualifier + UInt32 theQualifierSize = 0; + void* theQualifierData = NULL; + if(inClass != 0) + { + theQualifierSize = sizeof(AudioObjectID); + theQualifierData = &inClass; + } + + // figure out how much space to allocate + UInt32 theDataSize = GetPropertyDataSize(theAddress, theQualifierSize, theQualifierData); + UInt32 theNumberObjectIDs = theDataSize / sizeof(AudioObjectID); + + // set up the return value + AudioObjectID theAnswer = 0; + + // maker sure the index is in range + if(inIndex < theNumberObjectIDs) + { + // allocate it + CAAutoArrayDelete theObjectList(theDataSize / sizeof(AudioObjectID)); + + // get the property data + GetPropertyData(theAddress, theQualifierSize, theQualifierData, theDataSize, theObjectList); + + // get the return value + theAnswer = theObjectList[inIndex]; + } + + return theAnswer; +} + +bool CAHALAudioObject::HasProperty(const AudioObjectPropertyAddress& inAddress) const +{ + return AudioObjectHasProperty(mObjectID, &inAddress); +} + +bool CAHALAudioObject::IsPropertySettable(const AudioObjectPropertyAddress& inAddress) const +{ + Boolean isSettable = false; + OSStatus theError = AudioObjectIsPropertySettable(mObjectID, &inAddress, &isSettable); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::IsPropertySettable: got an error getting info about a property"); + return isSettable != 0; +} + +UInt32 CAHALAudioObject::GetPropertyDataSize(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData) const +{ + UInt32 theDataSize = 0; + OSStatus theError = AudioObjectGetPropertyDataSize(mObjectID, &inAddress, inQualifierDataSize, inQualifierData, &theDataSize); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::GetPropertyDataSize: got an error getting the property data size"); + return theDataSize; +} + +void CAHALAudioObject::GetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32& ioDataSize, void* outData) const +{ + OSStatus theError = AudioObjectGetPropertyData(mObjectID, &inAddress, inQualifierDataSize, inQualifierData, &ioDataSize, outData); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::GetPropertyData: got an error getting the property data"); +} + +void CAHALAudioObject::SetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData) +{ + OSStatus theError = AudioObjectSetPropertyData(mObjectID, &inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::SetPropertyData: got an error setting the property data"); +} + +void CAHALAudioObject::AddPropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData) +{ + OSStatus theError = AudioObjectAddPropertyListener(mObjectID, &inAddress, inListenerProc, inClientData); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::AddPropertyListener: got an error adding a property listener"); +} + +void CAHALAudioObject::RemovePropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData) +{ + OSStatus theError = AudioObjectRemovePropertyListener(mObjectID, &inAddress, inListenerProc, inClientData); + ThrowIfError(theError, CAException(theError), "CAHALAudioObject::RemovePropertyListener: got an error removing a property listener"); +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAHALAudioObject.h b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioObject.h new file mode 100755 index 00000000..314734d6 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioObject.h @@ -0,0 +1,131 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CAHALAudioObject_h__) +#define __CAHALAudioObject_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// PublicUtility Includes +#include "CADebugMacros.h" + +// System Includes +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include + #include +#else + #include + #include +#endif + +//================================================================================================== +// CAHALAudioObject +//================================================================================================== + +class CAHALAudioObject +{ + +// Construction/Destruction +public: + CAHALAudioObject(AudioObjectID inObjectID); + virtual ~CAHALAudioObject(); + +// Attributes +public: + AudioObjectID GetObjectID() const; + void SetObjectID(AudioObjectID inObjectID); + AudioClassID GetClassID() const; + AudioObjectID GetOwnerObjectID() const; + CFStringRef CopyOwningPlugInBundleID() const; + CFStringRef CopyName() const; + CFStringRef CopyManufacturer() const; + CFStringRef CopyNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const; + CFStringRef CopyCategoryNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const; + CFStringRef CopyNumberNameForElement(AudioObjectPropertyScope inScope, AudioObjectPropertyElement inElement) const; + +// Owned Objects +public: + UInt32 GetNumberOwnedObjects(AudioClassID inClass) const; + void GetAllOwnedObjects(AudioClassID inClass, UInt32& ioNumberObjects, AudioObjectID* ioObjectIDs) const; + AudioObjectID GetOwnedObjectByIndex(AudioClassID inClass, UInt32 inIndex); + +// Property Operations +public: + bool HasProperty(const AudioObjectPropertyAddress& inAddress) const; + bool IsPropertySettable(const AudioObjectPropertyAddress& inAddress) const; + UInt32 GetPropertyDataSize(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData) const; + + void GetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32& ioDataSize, void* outData) const; + void SetPropertyData(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData); + + UInt32 GetPropertyData_UInt32(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { UInt32 theAnswer = 0; UInt32 theDataSize = SizeOf32(UInt32); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &theAnswer); return theAnswer; } + void SetPropertyData_UInt32(const AudioObjectPropertyAddress& inAddress, UInt32 inValue, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(UInt32), &inValue); } + + Float32 GetPropertyData_Float32(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { Float32 theAnswer = 0; UInt32 theDataSize = SizeOf32(Float32); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &theAnswer); return theAnswer; } + void SetPropertyData_Float32(const AudioObjectPropertyAddress& inAddress, Float32 inValue, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(Float32), &inValue); } + + Float64 GetPropertyData_Float64(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { Float64 theAnswer = 0; UInt32 theDataSize = SizeOf32(Float64); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &theAnswer); return theAnswer; } + void SetPropertyData_Float64(const AudioObjectPropertyAddress& inAddress, Float64 inValue, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(Float64), &inValue); } + + CFTypeRef GetPropertyData_CFType(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { CFTypeRef theAnswer = NULL; UInt32 theDataSize = SizeOf32(CFTypeRef); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &theAnswer); return theAnswer; } + void SetPropertyData_CFType(const AudioObjectPropertyAddress& inAddress, UInt32 inValue, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(CFTypeRef), &inValue); } + + CFStringRef GetPropertyData_CFString(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { CFStringRef theAnswer = NULL; UInt32 theDataSize = SizeOf32(CFStringRef); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &theAnswer); return theAnswer; } + void SetPropertyData_CFString(const AudioObjectPropertyAddress& inAddress, UInt32 inValue, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(CFStringRef), &inValue); } + + template void GetPropertyData_Struct(const AudioObjectPropertyAddress& inAddress, T& outStruct, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { UInt32 theDataSize = SizeOf32(T); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, &outStruct); } + template void SetPropertyData_Struct(const AudioObjectPropertyAddress& inAddress, T& inStruct, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, SizeOf32(T), &inStruct); } + + template UInt32 GetPropertyData_ArraySize(const AudioObjectPropertyAddress& inAddress, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { return GetPropertyDataSize(inAddress, inQualifierDataSize, inQualifierData) / SizeOf32(T); } + template void GetPropertyData_Array(const AudioObjectPropertyAddress& inAddress, UInt32& ioNumberItems, T* outArray, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) const { UInt32 theDataSize = ioNumberItems * SizeOf32(T); GetPropertyData(inAddress, inQualifierDataSize, inQualifierData, theDataSize, outArray); ioNumberItems = theDataSize / SizeOf32(T); } + template void SetPropertyData_Array(const AudioObjectPropertyAddress& inAddress, UInt32 inNumberItems, T* inArray, UInt32 inQualifierDataSize = 0, const void* inQualifierData = NULL) { SetPropertyData(inAddress, inQualifierDataSize, inQualifierData, inNumberItems * SizeOf32(T), inArray); } + + void AddPropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData); + void RemovePropertyListener(const AudioObjectPropertyAddress& inAddress, AudioObjectPropertyListenerProc inListenerProc, void* inClientData); + +// Implementation +protected: + AudioObjectID mObjectID; + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAHALAudioStream.cpp b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioStream.cpp new file mode 100755 index 00000000..28ae4dfa --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioStream.cpp @@ -0,0 +1,176 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAHALAudioStream.h" + +// PublicUtility Includes +#include "CAAutoDisposer.h" +#include "CADebugMacros.h" +#include "CAException.h" +#include "CAPropertyAddress.h" + +//================================================================================================== +// CAHALAudioStream +//================================================================================================== + +CAHALAudioStream::CAHALAudioStream(AudioObjectID inAudioStream) +: + CAHALAudioObject(inAudioStream) +{ +} + +CAHALAudioStream::~CAHALAudioStream() +{ +} + +UInt32 CAHALAudioStream::GetDirection() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyDirection); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +UInt32 CAHALAudioStream::GetTerminalType() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyTerminalType); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +UInt32 CAHALAudioStream::GetStartingChannel() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyStartingChannel); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +UInt32 CAHALAudioStream::GetLatency() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyLatency); + return GetPropertyData_UInt32(theAddress, 0, NULL); +} + +void CAHALAudioStream::GetCurrentVirtualFormat(AudioStreamBasicDescription& outFormat) const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyVirtualFormat); + UInt32 theSize = sizeof(AudioStreamBasicDescription); + GetPropertyData(theAddress, 0, NULL, theSize, &outFormat); +} + +void CAHALAudioStream::SetCurrentVirtualFormat(const AudioStreamBasicDescription& inFormat) +{ + CAPropertyAddress theAddress(kAudioStreamPropertyVirtualFormat); + SetPropertyData(theAddress, 0, NULL, sizeof(AudioStreamBasicDescription), &inFormat); +} + +UInt32 CAHALAudioStream::GetNumberAvailableVirtualFormats() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyAvailableVirtualFormats); + UInt32 theAnswer = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer /= sizeof(AudioStreamRangedDescription); + return theAnswer; +} + +void CAHALAudioStream::GetAvailableVirtualFormats(UInt32& ioNumberFormats, AudioStreamRangedDescription* outFormats) const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyAvailableVirtualFormats); + UInt32 theSize = ioNumberFormats * sizeof(AudioStreamRangedDescription); + GetPropertyData(theAddress, 0, NULL, theSize, outFormats); + ioNumberFormats = theSize / sizeof(AudioStreamRangedDescription); +} + +void CAHALAudioStream::GetAvailableVirtualFormatByIndex(UInt32 inIndex, AudioStreamRangedDescription& outFormat) const +{ + UInt32 theNumberFormats = GetNumberAvailableVirtualFormats(); + if((theNumberFormats > 0) && (inIndex < theNumberFormats)) + { + CAAutoArrayDelete theFormats(theNumberFormats); + GetAvailableVirtualFormats(theNumberFormats, theFormats); + if((theNumberFormats > 0) && (inIndex < theNumberFormats)) + { + outFormat = theFormats[inIndex]; + } + } +} + +void CAHALAudioStream::GetCurrentPhysicalFormat(AudioStreamBasicDescription& outFormat) const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyPhysicalFormat); + UInt32 theSize = sizeof(AudioStreamBasicDescription); + GetPropertyData(theAddress, 0, NULL, theSize, &outFormat); +} + +void CAHALAudioStream::SetCurrentPhysicalFormat(const AudioStreamBasicDescription& inFormat) +{ + CAPropertyAddress theAddress(kAudioStreamPropertyPhysicalFormat); + SetPropertyData(theAddress, 0, NULL, sizeof(AudioStreamBasicDescription), &inFormat); +} + +UInt32 CAHALAudioStream::GetNumberAvailablePhysicalFormats() const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyAvailablePhysicalFormats); + UInt32 theAnswer = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer /= sizeof(AudioStreamRangedDescription); + return theAnswer; +} + +void CAHALAudioStream::GetAvailablePhysicalFormats(UInt32& ioNumberFormats, AudioStreamRangedDescription* outFormats) const +{ + CAPropertyAddress theAddress(kAudioStreamPropertyAvailablePhysicalFormats); + UInt32 theSize = ioNumberFormats * sizeof(AudioStreamRangedDescription); + GetPropertyData(theAddress, 0, NULL, theSize, outFormats); + ioNumberFormats = theSize / sizeof(AudioStreamRangedDescription); +} + +void CAHALAudioStream::GetAvailablePhysicalFormatByIndex(UInt32 inIndex, AudioStreamRangedDescription& outFormat) const +{ + UInt32 theNumberFormats = GetNumberAvailablePhysicalFormats(); + if((theNumberFormats > 0) && (inIndex < theNumberFormats)) + { + CAAutoArrayDelete theFormats(theNumberFormats); + GetAvailablePhysicalFormats(theNumberFormats, theFormats); + if((theNumberFormats > 0) && (inIndex < theNumberFormats)) + { + outFormat = theFormats[inIndex]; + } + } +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAHALAudioStream.h b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioStream.h new file mode 100755 index 00000000..e07c7834 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioStream.h @@ -0,0 +1,88 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CAHALAudioStream_h__) +#define __CAHALAudioStream_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// Super Class Includes +#include "CAHALAudioObject.h" + +//================================================================================================== +// CAHALAudioStream +//================================================================================================== + +class CAHALAudioStream +: + public CAHALAudioObject +{ + +// Construction/Destruction +public: + CAHALAudioStream(AudioObjectID inAudioStream); + virtual ~CAHALAudioStream(); + +// Attributes +public: + UInt32 GetDirection() const; + UInt32 GetTerminalType() const; + UInt32 GetStartingChannel() const; + UInt32 GetLatency() const; + +// Format Info +public: + void GetCurrentVirtualFormat(AudioStreamBasicDescription& outFormat) const; + void SetCurrentVirtualFormat(const AudioStreamBasicDescription& inFormat); + UInt32 GetNumberAvailableVirtualFormats() const; + void GetAvailableVirtualFormats(UInt32& ioNumberFormats, AudioStreamRangedDescription* outFormats) const; + void GetAvailableVirtualFormatByIndex(UInt32 inIndex, AudioStreamRangedDescription& outFormat) const; + + void GetCurrentPhysicalFormat(AudioStreamBasicDescription& outFormat) const; + void SetCurrentPhysicalFormat(const AudioStreamBasicDescription& inFormat); + UInt32 GetNumberAvailablePhysicalFormats() const; + void GetAvailablePhysicalFormats(UInt32& ioNumberFormats, AudioStreamRangedDescription* outFormats) const; + void GetAvailablePhysicalFormatByIndex(UInt32 inIndex, AudioStreamRangedDescription& outFormat) const; + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAHALAudioSystemObject.cpp b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioSystemObject.cpp new file mode 100755 index 00000000..f92c8cb6 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioSystemObject.cpp @@ -0,0 +1,146 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// Includes +//================================================================================================== + +// Self Include +#include "CAHALAudioSystemObject.h" + +// PublicUtility Includes +#include "CAAutoDisposer.h" +#include "CAPropertyAddress.h" + +//================================================================================================== +// CAHALAudioSystemObject +//================================================================================================== + +CAHALAudioSystemObject::CAHALAudioSystemObject() +: + CAHALAudioObject(kAudioObjectSystemObject) +{ +} + +CAHALAudioSystemObject::~CAHALAudioSystemObject() +{ +} + +UInt32 CAHALAudioSystemObject::GetNumberAudioDevices() const +{ + CAPropertyAddress theAddress(kAudioHardwarePropertyDevices); + UInt32 theAnswer = GetPropertyDataSize(theAddress, 0, NULL); + theAnswer /= sizeof(AudioObjectID); + return theAnswer; +} + +void CAHALAudioSystemObject::GetAudioDevices(UInt32& ioNumberAudioDevices, AudioObjectID* outAudioDevices) const +{ + CAPropertyAddress theAddress(kAudioHardwarePropertyDevices); + UInt32 theSize = ioNumberAudioDevices * sizeof(AudioObjectID); + GetPropertyData(theAddress, 0, NULL, theSize, outAudioDevices); + ioNumberAudioDevices = theSize / sizeof(AudioObjectID); +} + +AudioObjectID CAHALAudioSystemObject::GetAudioDeviceAtIndex(UInt32 inIndex) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + UInt32 theNumberDevices = GetNumberAudioDevices(); + if((theNumberDevices > 0) && (inIndex < theNumberDevices)) + { + CAAutoArrayDelete theDeviceList(theNumberDevices); + GetAudioDevices(theNumberDevices, theDeviceList); + if((theNumberDevices > 0) && (inIndex < theNumberDevices)) + { + theAnswer = theDeviceList[inIndex]; + } + } + return theAnswer; +} + +AudioObjectID CAHALAudioSystemObject::GetAudioDeviceForUID(CFStringRef inUID) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + AudioValueTranslation theValue = { &inUID, sizeof(CFStringRef), &theAnswer, sizeof(AudioObjectID) }; + CAPropertyAddress theAddress(kAudioHardwarePropertyDeviceForUID); + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theAnswer; +} + +static inline AudioObjectPropertySelector CAHALAudioSystemObject_CalculateDefaultDeviceProperySelector(bool inIsInput, bool inIsSystem) +{ + AudioObjectPropertySelector theAnswer = kAudioHardwarePropertyDefaultOutputDevice; + if(inIsInput) + { + theAnswer = kAudioHardwarePropertyDefaultInputDevice; + } + else if(inIsSystem) + { + theAnswer = kAudioHardwarePropertyDefaultSystemOutputDevice; + } + return theAnswer; +} + +AudioObjectID CAHALAudioSystemObject::GetDefaultAudioDevice(bool inIsInput, bool inIsSystem) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + CAPropertyAddress theAddress(CAHALAudioSystemObject_CalculateDefaultDeviceProperySelector(inIsInput, inIsSystem)); + UInt32 theSize = sizeof(AudioObjectID); + GetPropertyData(theAddress, 0, NULL, theSize, &theAnswer); + return theAnswer; +} + +void CAHALAudioSystemObject::SetDefaultAudioDevice(bool inIsInput, bool inIsSystem, AudioObjectID inNewDefaultDevice) +{ + CAPropertyAddress theAddress(CAHALAudioSystemObject_CalculateDefaultDeviceProperySelector(inIsInput, inIsSystem)); + UInt32 theSize = sizeof(AudioObjectID); + SetPropertyData(theAddress, 0, NULL, theSize, &inNewDefaultDevice); +} + +AudioObjectID CAHALAudioSystemObject::GetAudioPlugInForBundleID(CFStringRef inUID) const +{ + AudioObjectID theAnswer = kAudioObjectUnknown; + AudioValueTranslation theValue = { &inUID, sizeof(CFStringRef), &theAnswer, sizeof(AudioObjectID) }; + CAPropertyAddress theAddress(kAudioHardwarePropertyPlugInForBundleID); + UInt32 theSize = sizeof(AudioValueTranslation); + GetPropertyData(theAddress, 0, NULL, theSize, &theValue); + return theAnswer; +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAHALAudioSystemObject.h b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioSystemObject.h new file mode 100755 index 00000000..8f6b2717 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAHALAudioSystemObject.h @@ -0,0 +1,83 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CAHALAudioSystemObject_h__) +#define __CAHALAudioSystemObject_h__ + +//================================================================================================== +// Includes +//================================================================================================== + +// Super Class Includes +#include "CAHALAudioObject.h" + +//================================================================================================== +// CAHALAudioSystemObject +//================================================================================================== + +class CAHALAudioSystemObject +: + public CAHALAudioObject +{ + +// Construction/Destruction +public: + CAHALAudioSystemObject(); + virtual ~CAHALAudioSystemObject(); + +// Audio Device List Management +public: + UInt32 GetNumberAudioDevices() const; + void GetAudioDevices(UInt32& ioNumberAudioDevices, AudioObjectID* outAudioDevices) const; + AudioObjectID GetAudioDeviceAtIndex(UInt32 inIndex) const; + AudioObjectID GetAudioDeviceForUID(CFStringRef inUID) const; + +// Default Device Management +public: + AudioObjectID GetDefaultAudioDevice(bool inIsInput, bool inIsSystem) const; + void SetDefaultAudioDevice(bool inIsInput, bool inIsSystem, AudioObjectID inNewDefaultDevice); + +// PlugIns +public: + AudioObjectID GetAudioPlugInForBundleID(CFStringRef inBundleID) const; + +}; + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAHostTimeBase.cpp b/distrho/src/CoreAudio106/PublicUtility/CAHostTimeBase.cpp new file mode 100755 index 00000000..c5c70b98 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAHostTimeBase.cpp @@ -0,0 +1,104 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// Includes +//============================================================================= + +#include "CAHostTimeBase.h" + +Float64 CAHostTimeBase::sFrequency = 0; +Float64 CAHostTimeBase::sInverseFrequency = 0; +UInt32 CAHostTimeBase::sMinDelta = 0; +UInt32 CAHostTimeBase::sToNanosNumerator = 0; +UInt32 CAHostTimeBase::sToNanosDenominator = 0; +UInt32 CAHostTimeBase::sFromNanosNumerator = 0; +UInt32 CAHostTimeBase::sFromNanosDenominator = 0; +bool CAHostTimeBase::sUseMicroseconds = false; +bool CAHostTimeBase::sIsInited = false; +#if Track_Host_TimeBase +UInt64 CAHostTimeBase::sLastTime = 0; +#endif + +//============================================================================= +// CAHostTimeBase +// +// This class provides platform independent access to the host's time base. +//============================================================================= + +void CAHostTimeBase::Initialize() +{ + // get the info about Absolute time + #if TARGET_OS_MAC + struct mach_timebase_info theTimeBaseInfo; + mach_timebase_info(&theTimeBaseInfo); + sMinDelta = 1; + sToNanosNumerator = theTimeBaseInfo.numer; + sToNanosDenominator = theTimeBaseInfo.denom; + sFromNanosNumerator = sToNanosDenominator; + sFromNanosDenominator = sToNanosNumerator; + + // the frequency of that clock is: (sToNanosDenominator / sToNanosNumerator) * 10^9 + sFrequency = static_cast(sToNanosDenominator) / static_cast(sToNanosNumerator); + sFrequency *= 1000000000.0; + #elif TARGET_OS_WIN32 + LARGE_INTEGER theFrequency; + QueryPerformanceFrequency(&theFrequency); + sMinDelta = 1; + sToNanosNumerator = 1000000000ULL; + sToNanosDenominator = *((UInt64*)&theFrequency); + sFromNanosNumerator = sToNanosDenominator; + sFromNanosDenominator = sToNanosNumerator; + sFrequency = static_cast(*((UInt64*)&theFrequency)); + #endif + sInverseFrequency = 1.0 / sFrequency; + + #if Log_Host_Time_Base_Parameters + DebugMessage( "Host Time Base Parameters"); + DebugMessageN1(" Minimum Delta: %lu", sMinDelta); + DebugMessageN1(" Frequency: %f", sFrequency); + DebugMessageN1(" To Nanos Numerator: %lu", sToNanosNumerator); + DebugMessageN1(" To Nanos Denominator: %lu", sToNanosDenominator); + DebugMessageN1(" From Nanos Numerator: %lu", sFromNanosNumerator); + DebugMessageN1(" From Nanos Denominator: %lu", sFromNanosDenominator); + #endif + + sIsInited = true; +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAHostTimeBase.h b/distrho/src/CoreAudio106/PublicUtility/CAHostTimeBase.h new file mode 100755 index 00000000..ffdafbda --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAHostTimeBase.h @@ -0,0 +1,225 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CAHostTimeBase_h__) +#define __CAHostTimeBase_h__ + +//============================================================================= +// 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 + +#include "CADebugMacros.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() { if(!sIsInited) { Initialize(); } return sFrequency; } + static Float64 GetInverseFrequency() { if(!sIsInited) { Initialize(); } return sInverseFrequency; } + static UInt32 GetMinimumDelta() { if(!sIsInited) { Initialize(); } return sMinDelta; } + + static UInt64 AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime); + static SInt64 HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime); + +private: + static void Initialize(); + + static bool sIsInited; + + static Float64 sFrequency; + static Float64 sInverseFrequency; + static UInt32 sMinDelta; + static UInt32 sToNanosNumerator; + static UInt32 sToNanosDenominator; + static UInt32 sFromNanosNumerator; + static UInt32 sFromNanosDenominator; + static bool sUseMicroseconds; +#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) + { + DebugMessageN2("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) +{ + if(!sIsInited) + { + Initialize(); + } + + Float64 theNumerator = static_cast(sToNanosNumerator); + Float64 theDenominator = static_cast(sToNanosDenominator); + Float64 theHostTime = static_cast(inHostTime); + + Float64 thePartialAnswer = theHostTime / theDenominator; + Float64 theFloatAnswer = thePartialAnswer * theNumerator; + UInt64 theAnswer = static_cast(theFloatAnswer); + + //Assert(!((theNumerator > theDenominator) && (theAnswer < inHostTime)), "CAHostTimeBase::ConvertToNanos: The conversion wrapped"); + //Assert(!((theDenominator > theNumerator) && (theAnswer > inHostTime)), "CAHostTimeBase::ConvertToNanos: The conversion wrapped"); + + return theAnswer; +} + +inline UInt64 CAHostTimeBase::ConvertFromNanos(UInt64 inNanos) +{ + if(!sIsInited) + { + Initialize(); + } + + Float64 theNumerator = static_cast(sToNanosNumerator); + Float64 theDenominator = static_cast(sToNanosDenominator); + Float64 theNanos = static_cast(inNanos); + + Float64 thePartialAnswer = theNanos / theNumerator; + Float64 theFloatAnswer = thePartialAnswer * theDenominator; + UInt64 theAnswer = static_cast(theFloatAnswer); + + //Assert(!((theDenominator > theNumerator) && (theAnswer < inNanos)), "CAHostTimeBase::ConvertToNanos: The conversion wrapped"); + //Assert(!((theNumerator > theDenominator) && (theAnswer > inNanos)), "CAHostTimeBase::ConvertToNanos: The conversion wrapped"); + + 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 = inEndTime - inStartTime; + } + else + { + theAnswer = inStartTime - inEndTime; + theSign = -1; + } + + return theSign * ConvertToNanos(theAnswer); +} + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CALogMacros.h b/distrho/src/CoreAudio106/PublicUtility/CALogMacros.h new file mode 100755 index 00000000..7f7c69dc --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CALogMacros.h @@ -0,0 +1,134 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#if !defined(__CALogMacros_h__) +#define __CALogMacros_h__ + +//============================================================================= +// Log Macros +//============================================================================= + +#if CoreAudio_Debug + + #include "CADebugMacros.h" + #include "CADebugPrintf.h" + #include + #include + + #define PrintLine(msg) DebugPrintfRtn(DebugPrintfFileComma "%s\n", (msg)) + + #define PrintBool(msg, b) DebugPrintfRtn(DebugPrintfFileComma "%s%s\n", (msg), (b) ? "true" : "false") + #define PrintIndexedBool(msg, i, b) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %s\n", (msg), (long)(i), (b) ? "true" : "false") + + #define PrintToggle(msg, b) DebugPrintfRtn(DebugPrintfFileComma "%s%s\n", (msg), (b) ? "on" : "off") + #define PrintIndexedToggle(msg, i, b) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %s\n", (msg), (long)(i), (b) ? "on" : "off") + + #define PrintInt(msg, n) DebugPrintfRtn(DebugPrintfFileComma "%s%ld\n", (msg), (long)(n)) + #define PrintIndexedInt(msg, i, n) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %ld\n", (msg), (long)(i), (long)(n)) + + #define PrintHex(msg, n) DebugPrintfRtn(DebugPrintfFileComma "%s0x%lX\n", (msg), (unsigned long)(n)) + #define PrintIndexedHex(msg, i, n) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: 0x%lX\n", (msg), (long)(i), (unsigned long)(n)) + + #define PrintFloat(msg, f) DebugPrintfRtn(DebugPrintfFileComma "%s%.6f\n", (msg), (f)) + #define PrintIndexedFloat(msg, i, f) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %.6f\n", (msg), (long)(i), (f)) + #define PrintFloatIndexedFloat(msg, i, f) DebugPrintfRtn(DebugPrintfFileComma " %s %.6f: %.6f\n", (msg), (i), (f)) + + #define PrintString(msg, s) DebugPrintfRtn(DebugPrintfFileComma "%s%s\n", (msg), (s)) + #define PrintIndexedString(msg, i, s) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %s\n", (msg), (long)(i), (s)) + + #define PrintPointer(msg, p) DebugPrintfRtn(DebugPrintfFileComma "%s%p\n", (msg), (p)) + #define PrintIndexedPointer(msg, i, p) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %p\n", (msg), (long)(i), (p)) + + #define Print4CharCode(msg, c) { \ + UInt32 __4CC_number = (c); \ + char __4CC_string[5] = CA4CCToCString(__4CC_number); \ + DebugPrintfRtn(DebugPrintfFileComma "%s'%s'\n", (msg), __4CC_string); \ + } + #define PrintIndexed4CharCode(msg, i, c) { \ + UInt32 __4CC_number = (c); \ + char __4CC_string[5] = CA4CCToCString(__4CC_number); \ + DebugPrintfRtn(DebugPrintfFileComma " %s %ld: '%s'\n", (msg), (long)(i), __4CC_string); \ + } + + #define ErrorLine(s) DebugPrintfRtn(DebugPrintfFileComma "%s\n", (s)) + #define OSErrorLine(s, e) { \ + OSStatus __err_number = (e); \ + char __err_string[5] = CA4CCToCString(__err_number); \ + DebugPrintfRtn(DebugPrintfFileComma "%s, OSStatus code: %s\n", (s), __err_string); \ + } + + #define MessageIfOSError(e, s) if((e) != 0) { OSErrorLine(s, e); } + #define MessageIfNULL(p, s) if((p) == 0) { ErrorLine(s); } + +#else + + #define PrintLine(msg) + + #define PrintBool(msg, b) (b) + #define PrintIndexedBool(msg, i, b) (b) + + #define PrintInt(msg, n) (n) + #define PrintIndexedInt(msg, i, n) (n) + + #define PrintHex(msg, n) (n) + #define PrintIndexedHex(msg, i, n) (n) + + #define PrintFloat(msg, f) (f) + #define PrintIndexedFloat(msg, i, f) (f) + #define PrintFloatIndexedFloat(msg, i, f) (f) + + #define PrintString(msg, s) (s) + #define PrintIndexedString(msg, i, s) (s) + + #define PrintPointer(msg, p) (p) + #define PrintIndexedPointer(msg, i, p) (p) + + #define Print4CharCode(msg, c) (c) + #define PrintIndexed4CharCode(msg, i, c) (c) + + #define ErrorLine(s) (s) + #define OSErrorLine(s, e) (e) + + #define MessageIfOSError(e, s) (e) + #define MessageIfNULL(p, s) (p) + +#endif // CoreAudio_Debug + +#endif diff --git a/distrho/src/CoreAudio106/PublicUtility/CAMath.h b/distrho/src/CoreAudio106/PublicUtility/CAMath.h new file mode 100755 index 00000000..3fb0a1e4 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAMath.h @@ -0,0 +1,62 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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/distrho/src/CoreAudio106/PublicUtility/CAMixMap.h b/distrho/src/CoreAudio106/PublicUtility/CAMixMap.h new file mode 100755 index 00000000..2bb2a252 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAMixMap.h @@ -0,0 +1,121 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#ifndef __CAMixMap_h__ +#define __CAMixMap_h__ + + // manages the setting of mix map volumes + +class CAMixMap { +public: + CAMixMap () + : mIns(0), mOuts (0), mMixMap(NULL) + {} + + CAMixMap (const CAMixMap &mm) + : mIns(0), mOuts (0), mMixMap(NULL) + { *this = mm; } + + CAMixMap (UInt32 numIns, UInt32 numOuts) + : mIns(numIns), mOuts (numOuts), mMixMap(NULL) + { + mMixMap = new Float32[numIns * numOuts]; + memset (mMixMap, 0, ByteSize()); + } + + ~CAMixMap () { delete [] mMixMap; } + + CAMixMap& operator=(const CAMixMap& mm) + { + if (mMixMap) { delete [] mMixMap; mMixMap = NULL; } + mIns = mm.mIns; mOuts = mm.mOuts; + if (NumIns()) { + mMixMap = new Float32 [ NumIns() * NumOuts() ]; + memcpy (mMixMap, mm.mMixMap, ByteSize()); + } + return *this; + } + + UInt32 NumIns () const { return mIns; } + UInt32 NumOuts () const { return mOuts; } + + void SetCrossPoint (UInt32 inputChan, UInt32 outputChan, Float32 val) + { + if (inputChan < NumIns() && outputChan < NumOuts()) + mMixMap[inputChan * NumOuts() + outputChan] = val; + } + Float32 GetCrossPoint (UInt32 inputChan, UInt32 outputChan) const + { + return (inputChan < NumIns() && outputChan < NumOuts()) + ? mMixMap[inputChan * NumOuts() + outputChan] + : 0; + } + + void SetDiagonal (Float32 val) + { + for (UInt32 i = 0; i < NumIns() && i < NumOuts(); ++i) { + mMixMap[i * NumOuts() + i] = val; + } + } + + void Clear () { memset (mMixMap, 0, ByteSize()); } + + + Float32* MM() { return mMixMap; } + const Float32* MM() const { return mMixMap; } + UInt32 ByteSize () const { return NumIns() * NumOuts() * sizeof(Float32); } + + void Print () + { + printf ("Num Ins: %d, Num Outs: %d\n", (int)mIns, (int)mOuts); + for (unsigned int ins = 0; ins < mIns; ++ins) { + printf ("\t%d: ", ins); + for (unsigned int outs = 0; outs < mOuts; ++outs) + printf ("(%.3f) ", mMixMap[ins * NumOuts() + outs]); + printf("\n"); + } + } +private: + UInt32 mIns; + UInt32 mOuts; + Float32 *mMixMap; +}; + +#endif \ No newline at end of file diff --git a/distrho/src/CoreAudio106/PublicUtility/CAMutex.cpp b/distrho/src/CoreAudio106/PublicUtility/CAMutex.cpp new file mode 100755 index 00000000..c6ce0761 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAMutex.cpp @@ -0,0 +1,320 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//================================================================================================== +// 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; +} diff --git a/distrho/src/CoreAudio106/PublicUtility/CAMutex.h b/distrho/src/CoreAudio106/PublicUtility/CAMutex.h new file mode 100755 index 00000000..c014f395 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAMutex.h @@ -0,0 +1,138 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +#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() { if(mNeedsRelease) { mMutex.Unlock(); } } + + private: + Locker(const Locker&); + Locker& operator=(const Locker&); + + // Implementation + private: + CAMutex& mMutex; + bool mNeedsRelease; + + }; + + // 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/distrho/src/CoreAudio106/PublicUtility/CAPThread.cpp b/distrho/src/CoreAudio106/PublicUtility/CAPThread.cpp new file mode 100755 index 00000000..6c5563a2 --- /dev/null +++ b/distrho/src/CoreAudio106/PublicUtility/CAPThread.cpp @@ -0,0 +1,375 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + 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. +*/ +//============================================================================= +// Includes +//============================================================================= + +// Self Include +#include "CAPThread.h" + +// PublicUtility Includes +#include "CADebugMacros.h" +#include "CAException.h" + +// System Includes +#if TARGET_OS_MAC + #include +#endif + +// Standard Library Includes +#include + +//================================================================================================== +// CAPThread +//================================================================================================== + +// returns the thread's priority as it was last set by the API +#define CAPTHREAD_SET_PRIORITY 0 +// returns the thread's priority as it was last scheduled by the Kernel +#define CAPTHREAD_SCHEDULED_PRIORITY 1 + +//#define Log_SetPriority 1 + +CAPThread::CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPriority, bool inFixedPriority, bool inAutoDelete) +: +#if TARGET_OS_MAC + mPThread(0), + mSpawningThreadPriority(getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY)), +#elif TARGET_OS_WIN32 + mThreadHandle(NULL), + mThreadID(0), +#endif + mThreadRoutine(inThreadRoutine), + mThreadParameter(inParameter), + mPriority(inPriority), + mPeriod(0), + mComputation(0), + mConstraint(0), + mIsPreemptible(true), + mTimeConstraintSet(false), + mFixedPriority(inFixedPriority), + mAutoDelete(inAutoDelete) +{ +} + +CAPThread::CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible, bool inAutoDelete) +: +#if TARGET_OS_MAC + mPThread(0), + mSpawningThreadPriority(getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY)), +#elif TARGET_OS_WIN32 + mThreadHandle(NULL), + mThreadID(0), +#endif + mThreadRoutine(inThreadRoutine), + mThreadParameter(inParameter), + mPriority(kDefaultThreadPriority), + mPeriod(inPeriod), + mComputation(inComputation), + mConstraint(inConstraint), + mIsPreemptible(inIsPreemptible), + mTimeConstraintSet(true), + mFixedPriority(false), + mAutoDelete(inAutoDelete) +{ +} + +CAPThread::~CAPThread() +{ +} + +UInt32 CAPThread::GetScheduledPriority() +{ +#if TARGET_OS_MAC + return CAPThread::getScheduledPriority( mPThread, CAPTHREAD_SCHEDULED_PRIORITY ); +#elif TARGET_OS_WIN32 + UInt32 theAnswer = 0; + if(mThreadHandle != NULL) + { + theAnswer = GetThreadPriority(mThreadHandle); + } + return theAnswer; +#endif +} + +void CAPThread::SetPriority(UInt32 inPriority, bool inFixedPriority) +{ + mPriority = inPriority; + mTimeConstraintSet = false; + mFixedPriority = inFixedPriority; +#if TARGET_OS_MAC + if(mPThread != 0) + { + kern_return_t theError = 0; + + // set whether or not this is a fixed priority thread + if (mFixedPriority) + { + thread_extended_policy_data_t theFixedPolicy = { false }; + theError = thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT); + AssertNoKernelError(theError, "CAPThread::SetPriority: failed to set the fixed-priority policy"); + } + + // set the thread's absolute priority which is relative to the priority on which thread_policy_set() is called + UInt32 theCurrentThreadPriority = getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY); + thread_precedence_policy_data_t thePrecedencePolicy = { mPriority - theCurrentThreadPriority }; + theError = thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT); + AssertNoKernelError(theError, "CAPThread::SetPriority: failed to set the precedence policy"); + + #if Log_SetPriority + DebugMessageN4("CAPThread::SetPriority: requsted: %lu spawning: %lu current: %lu assigned: %d", mPriority, mSpawningThreadPriority, theCurrentThreadPriority, thePrecedencePolicy.importance); + #endif + } +#elif TARGET_OS_WIN32 + if(mThreadHandle != NULL) + { + SetThreadPriority(mThreadHandle, mPriority); + } +#endif +} + +void CAPThread::SetTimeConstraints(UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible) +{ + mPeriod = inPeriod; + mComputation = inComputation; + mConstraint = inConstraint; + mIsPreemptible = inIsPreemptible; + mTimeConstraintSet = true; +#if TARGET_OS_MAC + if(mPThread != 0) + { + thread_time_constraint_policy_data_t thePolicy; + thePolicy.period = mPeriod; + thePolicy.computation = mComputation; + thePolicy.constraint = mConstraint; + thePolicy.preemptible = mIsPreemptible; + AssertNoError(thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&thePolicy, THREAD_TIME_CONSTRAINT_POLICY_COUNT), "CAPThread::SetTimeConstraints: thread_policy_set failed"); + } +#elif TARGET_OS_WIN32 + if(mThreadHandle != NULL) + { + SetThreadPriority(mThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); + } +#endif +} + +void CAPThread::Start() +{ +#if TARGET_OS_MAC + Assert(mPThread == 0, "CAPThread::Start: can't start because the thread is already running"); + if(mPThread == 0) + { + OSStatus theResult; + pthread_attr_t theThreadAttributes; + + theResult = pthread_attr_init(&theThreadAttributes); + ThrowIf(theResult != 0, CAException(theResult), "CAPThread::Start: Thread attributes could not be created."); + + theResult = pthread_attr_setdetachstate(&theThreadAttributes, PTHREAD_CREATE_DETACHED); + ThrowIf(theResult != 0, CAException(theResult), "CAPThread::Start: A thread could not be created in the detached state."); + + theResult = pthread_create(&mPThread, &theThreadAttributes, (ThreadRoutine)CAPThread::Entry, this); + ThrowIf(theResult != 0 || !mPThread, CAException(theResult), "CAPThread::Start: Could not create a thread."); + + pthread_attr_destroy(&theThreadAttributes); + + } +#elif TARGET_OS_WIN32 + Assert(mThreadID == 0, "CAPThread::Start: can't start because the thread is already running"); + if(mThreadID == 0) + { + // clean up the existing thread handle + if(mThreadHandle != NULL) + { + CloseHandle(mThreadHandle); + mThreadHandle = NULL; + } + + // create a new thread + mThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Entry, this, 0, &mThreadID); + ThrowIf(mThreadHandle == NULL, CAException(GetLastError()), "CAPThread::Start: Could not create a thread."); + } +#endif +} + +#if TARGET_OS_MAC + +void* CAPThread::Entry(CAPThread* inCAPThread) +{ + void* theAnswer = NULL; + + try + { + if(inCAPThread->mTimeConstraintSet) + { + inCAPThread->SetTimeConstraints(inCAPThread->mPeriod, inCAPThread->mComputation, inCAPThread->mConstraint, inCAPThread->mIsPreemptible); + } + else + { + inCAPThread->SetPriority(inCAPThread->mPriority, inCAPThread->mFixedPriority); + } + + if(inCAPThread->mThreadRoutine != NULL) + { + theAnswer = inCAPThread->mThreadRoutine(inCAPThread->mThreadParameter); + } + } + catch (...) + { + // what should be done here? + } + inCAPThread->mPThread = 0; + if (inCAPThread->mAutoDelete) + delete inCAPThread; + return theAnswer; +} + +UInt32 CAPThread::getScheduledPriority(pthread_t inThread, int inPriorityKind) +{ + thread_basic_info_data_t threadInfo; + policy_info_data_t thePolicyInfo; + unsigned int count; + + if (inThread == NULL) + return 0; + + // get basic info + count = THREAD_BASIC_INFO_COUNT; + thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &count); + + switch (threadInfo.policy) { + case POLICY_TIMESHARE: + count = POLICY_TIMESHARE_INFO_COUNT; + thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&(thePolicyInfo.ts), &count); + if (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) { + return thePolicyInfo.ts.cur_priority; + } + return thePolicyInfo.ts.base_priority; + break; + + case POLICY_FIFO: + count = POLICY_FIFO_INFO_COUNT; + thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (thread_info_t)&(thePolicyInfo.fifo), &count); + if ( (thePolicyInfo.fifo.depressed) && (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) ) { + return thePolicyInfo.fifo.depress_priority; + } + return thePolicyInfo.fifo.base_priority; + break; + + case POLICY_RR: + count = POLICY_RR_INFO_COUNT; + thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (thread_info_t)&(thePolicyInfo.rr), &count); + if ( (thePolicyInfo.rr.depressed) && (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) ) { + return thePolicyInfo.rr.depress_priority; + } + return thePolicyInfo.rr.base_priority; + break; + } + + return 0; +} + +#elif TARGET_OS_WIN32 + +UInt32 WINAPI CAPThread::Entry(CAPThread* inCAPThread) +{ + UInt32 theAnswer = 0; + + try + { + if(inCAPThread->mTimeConstraintSet) + { + inCAPThread->SetTimeConstraints(inCAPThread->mPeriod, inCAPThread->mComputation, inCAPThread->mConstraint, inCAPThread->mIsPreemptible); + } + else + { + inCAPThread->SetPriority(inCAPThread->mPriority, inCAPThread->mFixedPriority); + } + + if(inCAPThread->mThreadRoutine != NULL) + { + theAnswer = reinterpret_cast(inCAPThread->mThreadRoutine(inCAPThread->mThreadParameter)); + } + inCAPThread->mThreadID = 0; + } + catch (...) + { + // what should be done here? + } + CloseHandle(inCAPThread->mThreadHandle); + inCAPThread->mThreadHandle = NULL; + if (inCAPThread->mAutoDelete) + delete inCAPThread; + return theAnswer; +} + +extern "C" +Boolean CompareAndSwap(UInt32 inOldValue, UInt32 inNewValue, UInt32* inOldValuePtr) +{ + return InterlockedCompareExchange((volatile LONG*)inOldValuePtr, inNewValue, inOldValue) == inOldValue; +} + +#endif + +#if CoreAudio_Debug +void CAPThread::DebugPriority(const char *label) +{ +#if !TARGET_OS_WIN32 + if (mTimeConstraintSet) + printf("CAPThread::%s %p: pri=