AUPublic/AUBase/AUScopeElement.h
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Part of Core Audio AUBase Classes |
*/ |
#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; |
#ifndef CA_CANONICAL_DEPRECATED |
#define CA_CANONICAL_DEPRECATED |
#endif |
// ____________________________________________________________________________ |
// |
// represents a parameter's value (either constant or ramped) |
/*! @class ParameterMapEvent */ |
class ParameterMapEvent |
{ |
public: |
/*! @ctor ParameterMapEvent */ |
ParameterMapEvent() |
: mEventType(kParameterEvent_Immediate), mBufferOffset(0), mDurationInFrames(0), mValue1(0.0f), mValue2(0.0f), mSliceDurationFrames(0) |
{} |
/*! @ctor ParameterMapEvent */ |
ParameterMapEvent(AudioUnitParameterValue inValue) |
: mEventType(kParameterEvent_Immediate), mBufferOffset(0), mDurationInFrames(0), mValue1(inValue), mValue2(inValue), mSliceDurationFrames(0) |
{} |
// constructor for scheduled event |
/*! @ctor ParameterMapEvent */ |
ParameterMapEvent( const AudioUnitParameterEvent &inEvent, |
UInt32 inSliceOffsetInBuffer, |
UInt32 inSliceDurationFrames ) |
{ |
SetScheduledEvent(inEvent, inSliceOffsetInBuffer, inSliceDurationFrames ); |
}; |
/*! @method SetScheduledEvent */ |
void SetScheduledEvent( const AudioUnitParameterEvent &inEvent, |
UInt32 inSliceOffsetInBuffer, |
UInt32 inSliceDurationFrames ) |
{ |
mEventType = inEvent.eventType; |
mSliceDurationFrames = inSliceDurationFrames; |
if(mEventType == kParameterEvent_Immediate ) |
{ |
// constant immediate value for the whole slice |
mValue1 = inEvent.eventValues.immediate.value; |
mValue2 = mValue1; |
mDurationInFrames = inSliceDurationFrames; |
mBufferOffset = 0; |
} |
else |
{ |
mDurationInFrames = inEvent.eventValues.ramp.durationInFrames; |
mBufferOffset = inEvent.eventValues.ramp.startBufferOffset - inSliceOffsetInBuffer; // shift over for this slice |
mValue1 = inEvent.eventValues.ramp.startValue; |
mValue2 = inEvent.eventValues.ramp.endValue; |
} |
}; |
/*! @method GetEventType */ |
AUParameterEventType GetEventType() const {return mEventType;}; |
/*! @method GetValue */ |
AudioUnitParameterValue GetValue() const {return mValue1;}; // only valid if immediate event type |
/*! @method GetEndValue */ |
AudioUnitParameterValue GetEndValue() const {return mValue2;}; // only valid if immediate event type |
/*! @method SetValue */ |
void SetValue(AudioUnitParameterValue inValue) |
{ |
mEventType = kParameterEvent_Immediate; |
mValue1 = inValue; |
mValue2 = inValue; |
} |
// interpolates the start and end values corresponding to the current processing slice |
// most ramp parameter implementations will want to use this method |
// the start value will correspond to the start of the slice |
// the end value will correspond to the end of the slice |
/*! @method GetRampSliceStartEnd */ |
void GetRampSliceStartEnd( AudioUnitParameterValue & outStartValue, |
AudioUnitParameterValue & outEndValue, |
AudioUnitParameterValue & outValuePerFrameDelta ) |
{ |
if (mEventType == kParameterEvent_Ramped) { |
outValuePerFrameDelta = (mValue2 - mValue1) / mDurationInFrames; |
outStartValue = mValue1 + outValuePerFrameDelta * (-mBufferOffset); // corresponds to frame 0 of this slice |
outEndValue = outStartValue + outValuePerFrameDelta * mSliceDurationFrames; |
} else { |
outValuePerFrameDelta = 0; |
outStartValue = outEndValue = mValue1; |
} |
}; |
// Some ramp parameter implementations will want to interpret the ramp using their |
// own interpolation method (perhaps non-linear) |
// This method gives the raw ramp information, relative to this processing slice |
// for the client to interpret as desired |
/*! @method GetRampInfo */ |
void GetRampInfo( SInt32 & outBufferOffset, |
UInt32 & outDurationInFrames, |
AudioUnitParameterValue & outStartValue, |
AudioUnitParameterValue & outEndValue ) |
{ |
outBufferOffset = mBufferOffset; |
outDurationInFrames = mDurationInFrames; |
outStartValue = mValue1; |
outEndValue = mValue2; |
}; |
#if DEBUG |
void Print() |
{ |
printf("ParameterEvent @ %p\n", this); |
printf(" mEventType = %d\n", (int)mEventType); |
printf(" mBufferOffset = %d\n", (int)mBufferOffset); |
printf(" mDurationInFrames = %d\n", (int)mDurationInFrames); |
printf(" mSliceDurationFrames = %d\n", (int)mSliceDurationFrames); |
printf(" mValue1 = %.5f\n", mValue1); |
printf(" mValue2 = %.5f\n", mValue2); |
} |
#endif |
private: |
AUParameterEventType mEventType; |
SInt32 mBufferOffset; // ramp start offset relative to start of this slice (may be negative) |
UInt32 mDurationInFrames; // total duration of ramp parameter |
AudioUnitParameterValue mValue1; // value if immediate : startValue if ramp |
AudioUnitParameterValue mValue2; // endValue (only used for ramp) |
UInt32 mSliceDurationFrames; // duration of this processing slice |
}; |
// ____________________________________________________________________________ |
// |
class AUIOElement; |
/*! @class AUElement */ |
class AUElement { |
public: |
/*! @ctor AUElement */ |
AUElement(AUBase *audioUnit) : mAudioUnit(audioUnit), |
mUseIndexedParameters(false), mElementName(0) { } |
/*! @dtor ~AUElement */ |
virtual ~AUElement() { if (mElementName) CFRelease (mElementName); } |
/*! @method GetNumberOfParameters */ |
virtual UInt32 GetNumberOfParameters() |
{ |
if(mUseIndexedParameters) return static_cast<UInt32>(mIndexedParameters.size()); else return static_cast<UInt32>(mParameters.size()); |
} |
/*! @method GetParameterList */ |
virtual void GetParameterList(AudioUnitParameterID *outList); |
/*! @method HasParameterID */ |
bool HasParameterID (AudioUnitParameterID paramID) const; |
/*! @method GetParameter */ |
AudioUnitParameterValue GetParameter(AudioUnitParameterID paramID); |
/*! @method SetParameter */ |
void SetParameter(AudioUnitParameterID paramID, AudioUnitParameterValue value, bool okWhenInitialized = false); |
// Only set okWhenInitialized to true when you know the outside world cannot access this element. Otherwise the parameter map could get corrupted. |
// interpolates the start and end values corresponding to the current processing slice |
// most ramp parameter implementations will want to use this method |
/*! @method GetRampSliceStartEnd */ |
void GetRampSliceStartEnd( AudioUnitParameterID paramID, |
AudioUnitParameterValue & outStartValue, |
AudioUnitParameterValue & outEndValue, |
AudioUnitParameterValue & outValuePerFrameDelta ); |
/*! @method GetEndValue */ |
AudioUnitParameterValue GetEndValue( AudioUnitParameterID paramID); |
/*! @method SetRampParameter */ |
void SetScheduledEvent( AudioUnitParameterID paramID, |
const AudioUnitParameterEvent &inEvent, |
UInt32 inSliceOffsetInBuffer, |
UInt32 inSliceDurationFrames, |
bool okWhenInitialized = false ); |
// Only set okWhenInitialized to true when you know the outside world cannot access this element. Otherwise the parameter map could get corrupted. |
/*! @method GetAudioUnit */ |
AUBase * GetAudioUnit() const { return mAudioUnit; }; |
/*! @method SaveState */ |
void SaveState(AudioUnitScope scope, CFMutableDataRef data); |
/*! @method RestoreState */ |
const UInt8 * RestoreState(const UInt8 *state); |
/*! @method GetName */ |
CFStringRef GetName () const { return mElementName; } |
/*! @method SetName */ |
void SetName (CFStringRef inName); |
/*! @method HasName */ |
bool HasName () const { return mElementName != 0; } |
/*! @method UseIndexedParameters */ |
virtual void UseIndexedParameters(int inNumberOfParameters); |
/*! @method AsIOElement*/ |
virtual AUIOElement* AsIOElement () { return NULL; } |
protected: |
inline ParameterMapEvent& GetParamEvent(AudioUnitParameterID paramID); |
private: |
typedef std::map<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 SetWillAllocateBuffer */ |
void SetWillAllocateBuffer(bool inFlag) { |
mWillAllocate = inFlag; |
} |
/*! @method WillAllocateBuffer */ |
bool WillAllocateBuffer() const { |
return mWillAllocate; |
} |
/*! @method UseExternalBuffer */ |
void UseExternalBuffer(const AudioUnitExternalBuffer &buf) { |
mIOBuffer.UseExternalBuffer(mStreamFormat, buf); |
} |
/*! @method PrepareBuffer */ |
AudioBufferList & PrepareBuffer(UInt32 nFrames) { |
if (mWillAllocate) |
return mIOBuffer.PrepareBuffer(mStreamFormat, nFrames); |
throw OSStatus(kAudioUnitErr_InvalidPropertyValue); |
} |
/*! @method PrepareNullBuffer */ |
AudioBufferList & PrepareNullBuffer(UInt32 nFrames) { |
return mIOBuffer.PrepareNullBuffer(mStreamFormat, nFrames); |
} |
/*! @method SetBufferList */ |
AudioBufferList & SetBufferList(AudioBufferList &abl) { return mIOBuffer.SetBufferList(abl); } |
/*! @method SetBuffer */ |
void SetBuffer(UInt32 index, AudioBuffer &ab) { mIOBuffer.SetBuffer(index, ab); } |
/*! @method InvalidateBufferList */ |
void InvalidateBufferList() { mIOBuffer.InvalidateBufferList(); } |
/*! @method GetBufferList */ |
AudioBufferList & GetBufferList() const { return mIOBuffer.GetBufferList(); } |
/*! @method GetChannelData */ |
CA_CANONICAL_DEPRECATED |
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); |
} |
Float32 * GetFloat32ChannelData(int ch) const { |
if (mStreamFormat.IsInterleaved()) |
return static_cast<Float32 *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch; |
else |
return static_cast<Float32 *>(mIOBuffer.GetBufferList().mBuffers[ch].mData); |
} |
SInt32 * GetSInt32ChannelData(int ch) const { |
if (mStreamFormat.IsInterleaved()) |
return static_cast<SInt32 *>(mIOBuffer.GetBufferList().mBuffers[0].mData) + ch; |
else |
return static_cast<SInt32 *>(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 (); |
/*! @method AsIOElement*/ |
virtual AUIOElement* AsIOElement () { return this; } |
protected: |
/*! @var mStreamFormat */ |
CAStreamBasicDescription mStreamFormat; |
/*! @var mIOBuffer */ |
AUBufferList mIOBuffer; // for input: input proc buffer, only allocated when needed |
// for output: output cache, usually allocated early on |
/*! @var mWillAllocate */ |
bool mWillAllocate; |
}; |
// ____________________________________________________________________________ |
// |
// AUScopeDelegates are a way to get virtual scopes. |
/*! @class AUScopeDelegate */ |
class AUScopeDelegate { |
public: |
/*! @ctor AUScopeDelegate */ |
AUScopeDelegate() : mCreator(NULL), mScope(0) { } |
/*! @dtor ~AUScopeDelegate */ |
virtual ~AUScopeDelegate() {} |
/*! @method Initialize */ |
void Initialize( AUBase *creator, |
AudioUnitScope scope, |
UInt32 numElements) |
{ |
mCreator = creator; |
mScope = scope; |
SetNumberOfElements(numElements); |
} |
/*! @method SetNumberOfElements */ |
virtual void SetNumberOfElements(UInt32 numElements) = 0; |
/*! @method GetNumberOfElements */ |
virtual UInt32 GetNumberOfElements() = 0; |
/*! @method GetElement */ |
virtual AUElement * GetElement(UInt32 elementIndex) = 0; |
AUBase * GetCreator() const { return mCreator; } |
AudioUnitScope GetScope() const { return mScope; } |
private: |
/*! @var mCreator */ |
AUBase * mCreator; |
/*! @var mScope */ |
AudioUnitScope mScope; |
}; |
// ____________________________________________________________________________ |
// |
/*! @class AUScope */ |
class AUScope { |
public: |
/*! @ctor AUScope */ |
AUScope() : mCreator(NULL), mScope(0), mDelegate(0) { } |
/*! @dtor ~AUScope */ |
~AUScope(); |
/*! @method Initialize */ |
void Initialize(AUBase *creator, |
AudioUnitScope scope, |
UInt32 numElements) |
{ |
mCreator = creator; |
mScope = scope; |
if (mDelegate) |
return mDelegate->Initialize(creator, scope, numElements); |
SetNumberOfElements(numElements); |
} |
/*! @method SetNumberOfElements */ |
void SetNumberOfElements(UInt32 numElements); |
/*! @method GetNumberOfElements */ |
UInt32 GetNumberOfElements() const |
{ |
if (mDelegate) |
return mDelegate->GetNumberOfElements(); |
return static_cast<UInt32>(mElements.size()); |
} |
/*! @method GetElement */ |
AUElement * GetElement(UInt32 elementIndex) const |
{ |
if (mDelegate) |
return mDelegate->GetElement(elementIndex); |
ElementVector::const_iterator i = mElements.begin() + elementIndex; |
// catch passing -1 in as the elementIndex - causes a wrap around |
return (i >= mElements.end() || i < mElements.begin()) ? NULL : *i; |
} |
/*! @method SafeGetElement */ |
AUElement * SafeGetElement(UInt32 elementIndex) |
{ |
AUElement *element = GetElement(elementIndex); |
if (element == NULL) |
COMPONENT_THROW(kAudioUnitErr_InvalidElement); |
return element; |
} |
/*! @method GetIOElement */ |
AUIOElement * GetIOElement(UInt32 elementIndex) const |
{ |
AUElement *element = GetElement(elementIndex); |
AUIOElement *ioel = element ? element->AsIOElement () : NULL; |
if (!ioel) |
COMPONENT_THROW (kAudioUnitErr_InvalidElement); |
return ioel; |
} |
/*! @method HasElementWithName */ |
bool HasElementWithName () const; |
/*! @method AddElementNamesToDict */ |
void AddElementNamesToDict (CFMutableDictionaryRef & inNameDict); |
bool RestoreElementNames (CFDictionaryRef& inNameDict); |
AudioUnitScope GetScope() const { return mScope; } |
void SetDelegate(AUScopeDelegate* inDelegate) { mDelegate = inDelegate; } |
/*! @method SaveState */ |
void SaveState(CFMutableDataRef data); |
/*! @method RestoreState */ |
const UInt8 * RestoreState(const UInt8 *state); |
private: |
typedef std::vector<AUElement *> ElementVector; |
/*! @var mCreator */ |
AUBase * mCreator; |
/*! @var mScope */ |
AudioUnitScope mScope; |
/*! @var mElements */ |
ElementVector mElements; |
/*! @var mDelegate */ |
AUScopeDelegate * mDelegate; |
}; |
#endif // __AUScopeElement_h__ |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-02-19