| @@ -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 <TargetConditionals.h> | |||
| #if TARGET_OS_MAC | |||
| #include <pthread.h> | |||
| #elif TARGET_OS_WIN32 | |||
| #include <windows.h> | |||
| #else | |||
| #error Unsupported Operating System | |||
| #endif | |||
| #include <vector> | |||
| #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<AUInputElement *>(Inputs().SafeGetElement(inElement)); | |||
| } | |||
| /*! @method GetOutput */ | |||
| AUOutputElement * GetOutput( AudioUnitElement inElement) | |||
| { | |||
| return static_cast<AUOutputElement *>(Outputs().SafeGetElement(inElement)); | |||
| } | |||
| #if !TARGET_OS_IPHONE | |||
| /*! @method GetGroup */ | |||
| AUGroupElement * GetGroup( AudioUnitElement inElement) | |||
| { | |||
| return static_cast<AUGroupElement *>(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<AUInputElement *>(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<AudioUnitParameterEvent> 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<RenderCallback> 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<PropertyListener> 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<AudioUnitRenderProc>(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__ | |||
| @@ -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; | |||
| } | |||
| @@ -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 <TargetConditionals.h> | |||
| /*! @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__ | |||
| @@ -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); | |||
| } | |||
| @@ -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__ | |||
| @@ -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; | |||
| } | |||
| @@ -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__ | |||
| @@ -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 <CoreServices/CoreServices.r> | |||
| // 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 | |||
| @@ -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<AUScope*>(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<const void**>(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<CFStringRef>(CFDictionaryGetValue (inNameDict, keys[i])); | |||
| int intKey; | |||
| CFStringGetCString (keys[i], string, 32, kCFStringEncodingASCII); | |||
| sscanf (string, "%d", &intKey); | |||
| GetElement (intKey)->SetName (elName); | |||
| } | |||
| free (keys); | |||
| return didAddElements; | |||
| } | |||
| @@ -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 <map> | |||
| #include <vector> | |||
| #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
| #include <AudioUnit/AudioUnit.h> | |||
| #else | |||
| #include <AudioUnit.h> | |||
| #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<AudioUnitParameterID, ParameterMapEvent, std::less<AudioUnitParameterID> > ParameterMap; | |||
| /*! @var mAudioUnit */ | |||
| AUBase * mAudioUnit; | |||
| /*! @var mParameters */ | |||
| ParameterMap mParameters; | |||
| /*! @var mUseIndexedParameters */ | |||
| bool mUseIndexedParameters; | |||
| /*! @var mIndexedParameters */ | |||
| std::vector<ParameterMapEvent> 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<AudioUnitSampleType *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch; | |||
| else | |||
| return static_cast<AudioUnitSampleType *>(mIOBuffer.GetBufferList().mBuffers[ch].mData); | |||
| } | |||
| SInt16 * GetInt16ChannelData(int ch) const { | |||
| if (mStreamFormat.IsInterleaved()) | |||
| return static_cast<SInt16 *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch; | |||
| else | |||
| return static_cast<SInt16 *>(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<AUIOElement *>(element)) == NULL) | |||
| COMPONENT_THROW (kAudioUnitErr_InvalidElement); | |||
| #else | |||
| if (element == NULL || (ioel = static_cast<AUIOElement *>(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<AUElement *> ElementVector; | |||
| /*! @var mCreator */ | |||
| AUElementCreator * mCreator; | |||
| /*! @var mScope */ | |||
| AudioUnitScope mScope; | |||
| /*! @var mElements */ | |||
| ElementVector mElements; | |||
| /*! @var mDelegate */ | |||
| AUScopeDelegate * mDelegate; | |||
| }; | |||
| #endif // __AUScopeElement_h__ | |||
| @@ -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 <dlfcn.h> | |||
| #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 | |||
| @@ -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 <new> | |||
| #include "CADebugMacros.h" | |||
| #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
| #include <CoreAudio/CoreAudioTypes.h> | |||
| #include <AudioUnit/AudioUnit.h> | |||
| #if !TARGET_OS_IPHONE | |||
| #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Components.h> | |||
| #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 <pthread.h> | |||
| #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<OSStatus>(err); } while (0) | |||
| #else | |||
| #define COMPONENT_THROW(err) \ | |||
| throw static_cast<OSStatus>(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 Class> | |||
| 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<Class>::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<Class>::Dispatch(params, obj); \ | |||
| } | |||
| #endif | |||
| /*! @class ComponentRegistrar */ | |||
| template <class Class, OSType Type, OSType Subtype, OSType Manufacturer> | |||
| class ComponentRegistrar { | |||
| public: | |||
| /*! @ctor ComponentRegistrar */ | |||
| ComponentRegistrar() { ComponentEntryPoint<Class>::Register(Type, Subtype, Manufacturer); } | |||
| }; | |||
| #define COMPONENT_REGISTER(Class,Type,Subtype,Manufacturer) \ | |||
| static ComponentRegistrar<Class, Type, Subtype, Manufacturer> 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__ | |||
| @@ -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 <algorithm> | |||
| 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<AUCarbonViewBase*>(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; | |||
| } | |||
| @@ -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 <vector> | |||
| #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<AUCarbonViewControl *> 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__ | |||
| @@ -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; | |||
| } | |||
| @@ -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 <Carbon/Carbon.h> | |||
| #include <AudioUnit/AudioUnitCarbonView.h> | |||
| #include <AudioToolbox/AudioUnitUtilities.h> | |||
| #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__ | |||
| @@ -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; | |||
| } | |||
| @@ -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 <Carbon/Carbon.h> | |||
| #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); | |||
| } | |||
| @@ -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 <Carbon/Carbon.h> | |||
| 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__ | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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 <Carbon/Carbon.h> | |||
| /*! @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__ | |||
| @@ -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; i<mNumNotes; ++i) | |||
| { | |||
| SynthNote *note = GetNote(i); | |||
| note->Reset(); | |||
| mFreeNotes.AddNote(note); | |||
| } | |||
| } | |||
| UInt32 AUInstrumentBase::CountActiveNotes() | |||
| { | |||
| // debugging tool. | |||
| UInt32 sum = 0; | |||
| for (UInt32 i=0; i<mNumNotes; ++i) | |||
| { | |||
| SynthNote *note = GetNote(i); | |||
| if (note->mState <= 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; i<mNumNotes; ++i) | |||
| { | |||
| SynthNote *note = GetNote(i); | |||
| if (note->IsSounding()) | |||
| 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<SynthGroupElement*>(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<OSStatus>(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<OSStatus>(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; | |||
| } | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| @@ -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 <vector> | |||
| #include <stdexcept> | |||
| #include <AudioUnit/AudioUnit.h> | |||
| #include <CoreAudio/CoreAudio.h> | |||
| #include "MusicDeviceBase.h" | |||
| #include "LockFreeFIFO.h" | |||
| #include "SynthEvent.h" | |||
| #include "SynthNote.h" | |||
| #include "SynthElement.h" | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| typedef LockFreeFIFOWithFree<SynthEvent> 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 | |||
| @@ -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 <Carbon/Carbon.h> | |||
| template <class ITEM> | |||
| 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 ITEM> | |||
| 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; | |||
| }; | |||
| @@ -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<kNumberOfSoundingNoteStates; ++i) | |||
| mNoteList[i].mState = i; | |||
| } | |||
| void SynthGroupElement::SetGroupID (MusicDeviceGroupID inGroup) | |||
| { | |||
| // can't re-assign a group once its been assigned | |||
| if (mGroupID != kUnassignedGroup) throw static_cast<OSStatus>(kAudioUnitErr_InvalidElement); | |||
| mGroupID = inGroup; | |||
| } | |||
| void SynthGroupElement::Reset() | |||
| { | |||
| #if DEBUG_PRINT | |||
| printf("SynthGroupElement::Reset\n"); | |||
| #endif | |||
| mMidiControls.Reset(); | |||
| for (UInt32 i=0; i<kNumberOfSoundingNoteStates; ++i) | |||
| mNoteList[i].Empty(); | |||
| } | |||
| SynthPartElement::SynthPartElement(AUInstrumentBase *audioUnit, UInt32 inElement) | |||
| : SynthElement(audioUnit, inElement) | |||
| { | |||
| } | |||
| void SynthGroupElement::NoteOff(NoteInstanceID inNoteID, UInt32 inFrame) | |||
| { | |||
| #if DEBUG_PRINT | |||
| printf("SynthGroupElement::NoteOff %d\n", inNoteID); | |||
| #endif | |||
| SynthNote *note = mNoteList[kNoteState_Attacked].mHead; | |||
| // see if this note is attacked. | |||
| while (note && note->mNoteID != 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 ; i<kNumberOfActiveNoteStates; ++i) | |||
| { | |||
| note = mNoteList[i].mHead; | |||
| while (note) | |||
| { | |||
| SynthNote *nextNote = note->mNext; | |||
| 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 ; i<kNumberOfSoundingNoteStates; ++i) | |||
| { | |||
| note = mNoteList[i].mHead; | |||
| while (note) | |||
| { | |||
| #if DEBUG_PRINT | |||
| printf(" note %d %08X %d\n", i, note, inNumberFrames); | |||
| #endif | |||
| SynthNote *nextNote = note->mNext; | |||
| OSStatus err = note->Render(inNumberFrames, bufferList); | |||
| if (err) return err; | |||
| note = nextNote; | |||
| } | |||
| } | |||
| return noErr; | |||
| } | |||
| @@ -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 <Carbon/Carbon.h> | |||
| #include <AudioUnit/AudioUnit.h> | |||
| #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 | |||
| @@ -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 <Carbon/Carbon.h> | |||
| #include <AudioUnit/AudioUnit.h> | |||
| #include <CoreAudio/CoreAudio.h> | |||
| #include "MusicDeviceBase.h" | |||
| #include <stdexcept> | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| 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 | |||
| @@ -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; | |||
| } | |||
| @@ -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 <Carbon/Carbon.h> | |||
| #include <AudioUnit/AudioUnit.h> | |||
| #include <CoreAudio/CoreAudio.h> | |||
| #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 | |||
| @@ -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 <stdexcept> | |||
| 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; | |||
| } | |||
| } | |||
| @@ -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 | |||
| @@ -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__ | |||
| @@ -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; | |||
| } | |||
| @@ -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<AUKernelBase *> 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__ | |||
| @@ -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 <CoreMIDI/CoreMIDI.h> | |||
| #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<AUParameterMIDIMapping*>(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<AUParameterMIDIMapping*>(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<const MIDIPacket *>(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; | |||
| } | |||
| @@ -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__ | |||
| @@ -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<AUMIDIEffectBase *>(inComponentStorage); | |||
| if (This == NULL) return paramErr; | |||
| result = This->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame); | |||
| } | |||
| COMPONENT_CATCH | |||
| return result; | |||
| } | |||
| @@ -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__ | |||
| @@ -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 | |||
| @@ -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__ | |||
| @@ -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 <AudioToolbox/AudioToolbox.h> | |||
| #include <Accelerate/Accelerate.h> | |||
| 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<AudioChannelLayoutTag> tags(numTags); | |||
| GetChannelLayoutTags(inScope, inElement, tags()); | |||
| for (UInt32 i = 0; i < numTags; ++i) | |||
| { | |||
| if (tags[i] == inTag) | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| @@ -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 <math.h> | |||
| #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<Float32> mBypassMatrix; | |||
| /*! @var mInputLayout */ | |||
| CAAudioChannelLayout mInputLayout; | |||
| /*! @var mOutputLayout */ | |||
| CAAudioChannelLayout mOutputLayout; | |||
| }; | |||
| #endif /* __AUPannerBase_h__ */ | |||
| @@ -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<MusicDeviceBase *>(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<MusicDeviceBase *>(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<MusicDeviceBase *>(inComponentStorage); | |||
| if (This == NULL) return paramErr; | |||
| result = This->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame); | |||
| } | |||
| COMPONENT_CATCH | |||
| return result; | |||
| } | |||
| @@ -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__ | |||
| @@ -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 <AudioUnit/AudioUnitProperties.h> | |||
| #else | |||
| #include <AudioUnitProperties.h> | |||
| #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 | |||
| @@ -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 <CoreFoundation/CoreFoundation.h> | |||
| #include <AudioUnit/AUComponent.h> | |||
| #else | |||
| #include <CoreFoundation.h> | |||
| #include <AUComponent.h> | |||
| #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__ | |||
| @@ -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 <stdlib.h> | |||
| 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 | |||
| @@ -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 <TargetConditionals.h> | |||
| #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) | |||
| #include <AudioUnit/AudioUnit.h> | |||
| #else | |||
| #include <AudioUnit.h> | |||
| #endif | |||
| #include <string.h> | |||
| #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<OSStatus>(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 T> | |||
| 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__ | |||
| @@ -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 | |||
| @@ -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__ | |||
| @@ -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__ | |||
| @@ -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 | |||
| @@ -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; | |||
| } | |||
| @@ -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 <math.h> | |||
| #include "CAHostTimeBase.h" | |||
| #include <stdio.h> | |||
| #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 <CoreAudio/HostTime.h> | |||
| // 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__ | |||
| @@ -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 <AudioUnit/AUComponent.h> | |||
| #else | |||
| #include <AUComponent.h> | |||
| #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<AudioBufferList*>(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 | |||
| @@ -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__ | |||
| @@ -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; | |||
| } | |||
| @@ -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 <map> | |||
| #include <vector> | |||
| #include <AudioUnit/AudioUnit.h> | |||
| #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<CAAUParameter>) | |||
| 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 <CAAUParameter> ParameterList; | |||
| typedef std::map <UInt32, ParameterList, std::less<UInt32> > 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; } | |||
| }; | |||
| @@ -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); | |||
| } | |||
| @@ -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 <AudioUnit/AudioUnitProperties.h> | |||
| #include <algorithm> | |||
| /* | |||
| 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 | |||
| @@ -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 <AudioToolbox/AudioUnitUtilities.h> | |||
| 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; | |||
| } | |||
| @@ -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 <AUBase.h> | |||
| #include <CAAUMIDIMap.h> | |||
| #include <vector> | |||
| #include <AudioToolbox/AudioUnitUtilities.h> | |||
| class CAAUMIDIMapManager { | |||
| protected: | |||
| typedef std::vector<CAAUMIDIMap> 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 | |||
| @@ -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 | |||
| @@ -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 <AudioToolbox/AudioUnitUtilities.h> | |||
| // ____________________________________________________________________________ | |||
| // 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__ | |||
| @@ -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 <windows.h> | |||
| #include <intrin.h> | |||
| #else | |||
| #include <CoreFoundation/CFBase.h> | |||
| #include <libkern/OSAtomic.h> | |||
| #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__ | |||
| @@ -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 <libkern/OSAtomic.h> | |||
| #else | |||
| // #include <DriverSynchronization.h> | |||
| #include <CAAtomic.h> | |||
| #endif | |||
| #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4 | |||
| #include <CoreServices/CoreServices.h> | |||
| #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 T> | |||
| 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. | |||
| // <rdar://problem/4606346> 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<T> 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 <libkern/OSAtomic.h> | |||
| 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 T> | |||
| 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__ | |||
| @@ -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 <stdlib.h> | |||
| #include <string.h> | |||
| //============================================================================= | |||
| // CAAudioBufferList | |||
| //============================================================================= | |||
| AudioBufferList* CAAudioBufferList::Create(UInt32 inNumberBuffers) | |||
| { | |||
| UInt32 theSize = CalculateByteSize(inNumberBuffers); | |||
| AudioBufferList* theAnswer = static_cast<AudioBufferList*>(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<const Float32*>(inSource.mData); | |||
| Float32* theDestination = static_cast<Float32*>(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<Float32*>(inSourceBufferList.mBuffers[theBufferIndex].mData); | |||
| Float32* theSummedBuffer = static_cast<Float32*>(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 } } }; | |||
| @@ -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 <CoreAudio/CoreAudioTypes.h> | |||
| #else | |||
| #include <CoreAudioTypes.h> | |||
| #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 | |||
| @@ -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 <stdlib.h> | |||
| #include <string.h> | |||
| //============================================================================= | |||
| // CAAudioChannelLayout | |||
| //============================================================================= | |||
| AudioChannelLayout* CAAudioChannelLayout::Create(UInt32 inNumberChannelDescriptions) | |||
| { | |||
| UInt32 theSize = CalculateByteSize(inNumberChannelDescriptions); | |||
| AudioChannelLayout* theAnswer = static_cast<AudioChannelLayout*>(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]); | |||
| } | |||
| } | |||
| } | |||
| @@ -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 <CoreAudio/CoreAudioTypes.h> | |||
| #include <CoreFoundation/CoreFoundation.h> | |||
| #else | |||
| #include <CoreAudioTypes.h> | |||
| #include <CoreFoundation.h> | |||
| #endif | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #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 | |||
| @@ -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 <AudioToolbox/AudioFormat.h> | |||
| #else | |||
| #include <AudioFormat.h> | |||
| #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()); | |||
| } | |||
| @@ -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 <algorithm> | |||
| #include <ctype.h> | |||
| 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 | |||
| @@ -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 <AudioToolbox/AudioToolbox.h> | |||
| #else | |||
| #include <AudioToolbox.h> | |||
| #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__ | |||
| @@ -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; | |||
| } | |||
| @@ -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 <CoreAudio/CoreAudioTypes.h> | |||
| #else | |||
| #include <CoreAudioTypes.h> | |||
| #endif | |||
| #include <string.h> | |||
| //============================================================================= | |||
| // 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 | |||
| @@ -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 <CoreAudio/CoreAudio.h> | |||
| #include <AudioUnit/AudioUnit.h> | |||
| #if !TARGET_OS_IPHONE | |||
| #include <AudioUnit/MusicDevice.h> | |||
| #endif | |||
| #include <AudioToolbox/AUGraph.h> | |||
| #else | |||
| #include <ConditionalMacros.h> | |||
| #include <CoreAudioTypes.h> | |||
| #include <AudioUnit.h> | |||
| #include <MusicDevice.h> | |||
| #include <AUGraph.h> | |||
| #include <MusicDevice.h> | |||
| #endif | |||
| #include <vector> | |||
| #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<AudioChannelLayoutTag> 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 | |||
| @@ -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 <AudioToolbox/ExtendedAudioFile.h> | |||
| /* | |||
| 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__ | |||
| @@ -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 <algorithm> | |||
| //================================================================================================== | |||
| // 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); | |||
| } | |||
| } | |||
| @@ -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 <CoreAudio/CoreAudioTypes.h> | |||
| #else | |||
| #include <CoreAudioTypes.h> | |||
| #endif | |||
| // Standard Library Includes | |||
| #include <functional> | |||
| #include <vector> | |||
| //============================================================================= | |||
| // 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<AudioValueRange, AudioValueRange, bool> | |||
| { | |||
| 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<CAAudioValueRange> CAAudioValueRangeList; | |||
| void CAAudioValueRange_ComputeUnion(const AudioValueRange& inRange, const CAAudioValueRangeList& inRangeList, CAAudioValueRangeList& outUnion); | |||
| void CAAudioValueRange_ComputeIntersection(const AudioValueRange& inRange, const CAAudioValueRangeList& inRangeList, CAAudioValueRangeList& outIntersections); | |||
| #endif | |||
| @@ -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 <stdlib.h> // for malloc | |||
| #include <new> // for bad_alloc | |||
| #include <string.h> // 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 <typename T> | |||
| struct CAPtrRef | |||
| { | |||
| T* ptr_; | |||
| explicit CAPtrRef(T* ptr) : ptr_(ptr) {} | |||
| }; | |||
| template <typename T> | |||
| class CAAutoFree | |||
| { | |||
| private: | |||
| T* ptr_; | |||
| public: | |||
| CAAutoFree() : ptr_(0) {} | |||
| explicit CAAutoFree(T* ptr) : ptr_(ptr) {} | |||
| template<typename U> | |||
| CAAutoFree(CAAutoFree<U>& that) : ptr_(that.release()) {} // take ownership | |||
| // C++ std says: a template constructor is never a copy constructor | |||
| CAAutoFree(CAAutoFree<T>& 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<T*>(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<T*>(clear ? CA_calloc(numItems, sizeof(T)) : CA_malloc(numItems * sizeof(T))); | |||
| } | |||
| void allocBytes(size_t numBytes, bool clear = false) | |||
| { | |||
| free(); | |||
| ptr_ = static_cast<T*>(clear ? CA_calloc(1, numBytes) : CA_malloc(numBytes)); | |||
| } | |||
| void reallocBytes(size_t numBytes) | |||
| { | |||
| ptr_ = static_cast<T*>(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<T*>(CA_realloc(ptr_, numItems * sizeof(T))); | |||
| } | |||
| template <typename U> | |||
| CAAutoFree& operator=(CAAutoFree<U>& 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 <typename U> | |||
| 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<T> ref) : ptr_(ref.ptr_) { } | |||
| CAAutoFree& operator=(CAPtrRef<T> ref) | |||
| { | |||
| set(ref.ptr_); | |||
| return *this; | |||
| } | |||
| template<typename U> | |||
| operator CAPtrRef<U>() | |||
| { return CAPtrRef<U>(release()); } | |||
| template<typename U> | |||
| operator CAAutoFree<U>() | |||
| { return CAAutoFree<U>(release()); } | |||
| }; | |||
| template <typename T> | |||
| class CAAutoDelete | |||
| { | |||
| private: | |||
| T* ptr_; | |||
| public: | |||
| CAAutoDelete() : ptr_(0) {} | |||
| explicit CAAutoDelete(T* ptr) : ptr_(ptr) {} | |||
| template<typename U> | |||
| CAAutoDelete(CAAutoDelete<U>& that) : ptr_(that.release()) {} // take ownership | |||
| // C++ std says: a template constructor is never a copy constructor | |||
| CAAutoDelete(CAAutoDelete<T>& that) : ptr_(that.release()) {} // take ownership | |||
| ~CAAutoDelete() { free(); } | |||
| template <typename U> | |||
| CAAutoDelete& operator=(CAAutoDelete<U>& 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 <typename U> | |||
| 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<T> ref) : ptr_(ref.ptr_) { } | |||
| CAAutoDelete& operator=(CAPtrRef<T> ref) | |||
| { | |||
| set(ref.ptr_); | |||
| return *this; | |||
| } | |||
| template<typename U> | |||
| operator CAPtrRef<U>() | |||
| { return CAPtrRef<U>(release()); } | |||
| template<typename U> | |||
| operator CAAutoFree<U>() | |||
| { return CAAutoFree<U>(release()); } | |||
| }; | |||
| template <typename T> | |||
| class CAAutoArrayDelete | |||
| { | |||
| private: | |||
| T* ptr_; | |||
| public: | |||
| CAAutoArrayDelete() : ptr_(0) {} | |||
| explicit CAAutoArrayDelete(T* ptr) : ptr_(ptr) {} | |||
| template<typename U> | |||
| CAAutoArrayDelete(CAAutoArrayDelete<U>& that) : ptr_(that.release()) {} // take ownership | |||
| // C++ std says: a template constructor is never a copy constructor | |||
| CAAutoArrayDelete(CAAutoArrayDelete<T>& 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 <typename U> | |||
| CAAutoArrayDelete& operator=(CAAutoArrayDelete<U>& 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 <typename U> | |||
| 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<T> ref) : ptr_(ref.ptr_) { } | |||
| CAAutoArrayDelete& operator=(CAPtrRef<T> ref) | |||
| { | |||
| set(ref.ptr_); | |||
| return *this; | |||
| } | |||
| template<typename U> | |||
| operator CAPtrRef<U>() | |||
| { return CAPtrRef<U>(release()); } | |||
| template<typename U> | |||
| operator CAAutoArrayDelete<U>() | |||
| { return CAAutoFree<U>(release()); } | |||
| }; | |||
| // convenience function | |||
| template <typename T> | |||
| void free(CAAutoFree<T>& p) | |||
| { | |||
| p.free(); | |||
| } | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| #if 0 | |||
| // example program showing ownership transfer | |||
| CAAutoFree<char> source() | |||
| { | |||
| // source allocates and returns ownership to the caller. | |||
| const char* str = "this is a test"; | |||
| size_t size = strlen(str) + 1; | |||
| CAAutoFree<char> captr(size, false); | |||
| strlcpy(captr(), str, size); | |||
| printf("source %08X %08X '%s'\n", &captr, captr(), captr()); | |||
| return captr; | |||
| } | |||
| void user(CAAutoFree<char> 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<char> 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<char> 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 | |||
| @@ -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 <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h> | |||
| #include <CoreFoundation/CFBase.h> | |||
| #else | |||
| // #include <MacTypes.h> | |||
| #include "CFBase.h" | |||
| #endif | |||
| #include <TargetConditionals.h> | |||
| // 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 | |||
| @@ -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 | |||
| @@ -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); | |||
| } | |||
| @@ -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 <stddef.h> | |||
| #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__ | |||
| @@ -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 <pthread.h> | |||
| /* | |||
| 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); | |||
| } | |||
| @@ -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 | |||
| @@ -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 <CoreFoundation/CoreFoundation.h> | |||
| #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 | |||
| @@ -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<CFBooleanRef>(theValue)); | |||
| theAnswer = true; | |||
| } | |||
| else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) | |||
| { | |||
| SInt32 theNumericValue = 0; | |||
| CFNumberGetValue(static_cast<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFStringRef>(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<CFArrayRef>(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<CFDictionaryRef>(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<CFDataRef>(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<CFUUIDRef>(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<CFStringRef>(NULL); | |||
| CFTypeRef theItem = NULL; | |||
| if(GetCFType(inIndex, theItem)) | |||
| { | |||
| if((theItem != NULL) && (CFGetTypeID(theItem) == CFStringGetTypeID())) | |||
| { | |||
| outItem = static_cast<CFStringRef>(theItem); | |||
| } | |||
| } | |||
| } | |||
| void CACFArray::GetCACFArray(UInt32 inIndex, CACFArray& outItem) const | |||
| { | |||
| outItem = static_cast<CFArrayRef>(NULL); | |||
| CFTypeRef theItem = NULL; | |||
| if(GetCFType(inIndex, theItem)) | |||
| { | |||
| if((theItem != NULL) && (CFGetTypeID(theItem) == CFArrayGetTypeID())) | |||
| { | |||
| outItem = static_cast<CFArrayRef>(theItem); | |||
| } | |||
| } | |||
| } | |||
| void CACFArray::GetCACFDictionary(UInt32 inIndex, CACFDictionary& outItem) const | |||
| { | |||
| outItem = static_cast<CFDictionaryRef>(NULL); | |||
| CFTypeRef theItem = NULL; | |||
| if(GetCFType(inIndex, theItem)) | |||
| { | |||
| if((theItem != NULL) && (CFGetTypeID(theItem) == CFDictionaryGetTypeID())) | |||
| { | |||
| outItem = static_cast<CFDictionaryRef>(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; | |||
| } | |||
| @@ -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 <CoreAudio/CoreAudioTypes.h> | |||
| #include <CoreFoundation/CoreFoundation.h> | |||
| #else | |||
| #include <CoreAudioTypes.h> | |||
| #include <CoreFoundation.h> | |||
| #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<CFMutableArrayRef>(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<CFMutableArrayRef>(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 | |||
| @@ -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 <CoreAudio/CoreAudioTypes.h> | |||
| #include <CoreFoundation/CFData.h> | |||
| #else | |||
| #include <CoreAudioTypes.h> | |||
| #include <CFData.h> | |||
| #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<const UInt8*>(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<UInt8*>(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 | |||
| @@ -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<CFBooleanRef>(theValue)); | |||
| theAnswer = true; | |||
| } | |||
| else if((theValue != NULL) && (CFGetTypeID(theValue) == CFNumberGetTypeID())) | |||
| { | |||
| SInt32 theNumericValue = 0; | |||
| CFNumberGetValue(static_cast<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(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<CFNumberRef>(theValue), kCFNumberSInt64Type, &theFixed64); | |||
| outValue = static_cast<Float64>(theFixed64 >> 32); | |||
| outValue += static_cast<Float64>(theFixed64 & 0x00000000FFFFFFFFLL) / static_cast<Float64>(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<CFStringRef>(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<CFArrayRef>(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<CFDictionaryRef>(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<CFDataRef>(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<CFStringRef>(NULL); | |||
| CFTypeRef theValue = NULL; | |||
| if(GetCFType(inKey, theValue)) | |||
| { | |||
| if((theValue != NULL) && (CFGetTypeID(theValue) == CFStringGetTypeID())) | |||
| { | |||
| outValue = static_cast<CFStringRef>(theValue); | |||
| } | |||
| } | |||
| } | |||
| void CACFDictionary::GetCACFArray(const CFStringRef inKey, CACFArray& outValue) const | |||
| { | |||
| outValue = static_cast<CFArrayRef>(NULL); | |||
| CFTypeRef theValue = NULL; | |||
| if(GetCFType(inKey, theValue)) | |||
| { | |||
| if((theValue != NULL) && (CFGetTypeID(theValue) == CFArrayGetTypeID())) | |||
| { | |||
| outValue = static_cast<CFArrayRef>(theValue); | |||
| } | |||
| } | |||
| } | |||
| void CACFDictionary::GetCACFDictionary(const CFStringRef inKey, CACFDictionary& outValue) const | |||
| { | |||
| outValue = static_cast<CFDictionaryRef>(NULL); | |||
| CFTypeRef theValue = NULL; | |||
| if(GetCFType(inKey, theValue)) | |||
| { | |||
| if((theValue != NULL) && (CFGetTypeID(theValue) == CFDictionaryGetTypeID())) | |||
| { | |||
| outValue = static_cast<CFDictionaryRef>(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; | |||
| } | |||
| @@ -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 <CoreFoundation/CoreFoundation.h> | |||
| #else | |||
| #include <CoreFoundation.h> | |||
| #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<CFMutableDictionaryRef>(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<CFMutableDictionaryRef>(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__ | |||
| @@ -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); | |||
| } | |||
| @@ -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 <CoreAudio/CoreAudioTypes.h> | |||
| #include <CoreFoundation/CoreFoundation.h> | |||
| //================================================================================================== | |||
| // 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 | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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 <CoreFoundation/CFMachPort.h> | |||
| //================================================================================================== | |||
| // 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 | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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 <CoreFoundation/CFMessagePort.h> | |||
| #else | |||
| #include <CFMessagePort.h> | |||
| #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 | |||