diff options
Diffstat (limited to 'distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.h')
-rwxr-xr-x | distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.h | 893 |
1 files changed, 893 insertions, 0 deletions
diff --git a/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.h b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.h new file mode 100755 index 00000000..18e0981e --- /dev/null +++ b/distrho/src/CoreAudio106/AudioUnits/AUPublic/AUBase/AUBase.h @@ -0,0 +1,893 @@ +/* Copyright © 2007 Apple Inc. All Rights Reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by + Apple Inc. ("Apple") in consideration of your agreement to the + following terms, and your use, installation, modification or + redistribution of this Apple software constitutes acceptance of these + terms. If you do not agree with these terms, please do not use, + install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. + may be used to endorse or promote products derived from the Apple + Software without specific prior written permission from Apple. Except + as expressly stated in this notice, no other rights or licenses, express + or implied, are granted by Apple herein, including but not limited to + any patent rights that may be infringed by your derivative works or by + other works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __AUBase_h__ +#define __AUBase_h__ + +#include <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__ |