1 /* 2 Copyright (C) 2016 Apple Inc. All Rights Reserved. 3 See LICENSE.txt for this sample’s licensing information 4 5 Abstract: 6 Part of Core Audio AUBase Classes 7 */ 8 9 #ifndef __AUBuffer_h__ 10 #define __AUBuffer_h__ 11 12 #include <TargetConditionals.h> 13 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) 14 #include <AudioUnit/AudioUnit.h> 15 #else 16 #include <AudioUnit.h> 17 #endif 18 19 #include <string.h> 20 #include "CAStreamBasicDescription.h" 21 #include "CAAutoDisposer.h" 22 #include "CADebugMacros.h" 23 24 // make this usable outside the stricter context of AudiUnits 25 #ifndef COMPONENT_THROW 26 #define COMPONENT_THROW(err) \ 27 do { DebugMessage(#err); throw static_cast<OSStatus>(err); } while (0) 28 #endif 29 30 31 /*! @class AUBufferList */ 32 class AUBufferList { 33 enum EPtrState { 34 kPtrsInvalid, 35 kPtrsToMyMemory, 36 kPtrsToExternalMemory 37 }; 38 public: 39 /*! @ctor AUBufferList */ AUBufferList()40 AUBufferList() : mPtrState(kPtrsInvalid), mExternalMemory(false), mPtrs(NULL), mMemory(NULL), 41 mAllocatedStreams(0), mAllocatedFrames(0), mAllocatedBytes(0) { } 42 /*! @dtor ~AUBufferList */ 43 ~AUBufferList(); 44 45 /*! @method PrepareBuffer */ 46 AudioBufferList & PrepareBuffer(const CAStreamBasicDescription &format, UInt32 nFrames); 47 /*! @method PrepareNullBuffer */ 48 AudioBufferList & PrepareNullBuffer(const CAStreamBasicDescription &format, UInt32 nFrames); 49 50 /*! @method SetBufferList */ SetBufferList(const AudioBufferList & abl)51 AudioBufferList & SetBufferList(const AudioBufferList &abl) { 52 if (mAllocatedStreams < abl.mNumberBuffers) 53 COMPONENT_THROW(-1); 54 mPtrState = kPtrsToExternalMemory; 55 memcpy(mPtrs, &abl, (char *)&abl.mBuffers[abl.mNumberBuffers] - (char *)&abl); 56 return *mPtrs; 57 } 58 59 /*! @method SetBuffer */ SetBuffer(UInt32 index,const AudioBuffer & ab)60 void SetBuffer(UInt32 index, const AudioBuffer &ab) { 61 if (mPtrState == kPtrsInvalid || index >= mPtrs->mNumberBuffers) 62 COMPONENT_THROW(-1); 63 mPtrState = kPtrsToExternalMemory; 64 mPtrs->mBuffers[index] = ab; 65 } 66 67 /*! @method InvalidateBufferList */ InvalidateBufferList()68 void InvalidateBufferList() { mPtrState = kPtrsInvalid; } 69 70 /*! @method GetBufferList */ GetBufferList()71 AudioBufferList & GetBufferList() const { 72 if (mPtrState == kPtrsInvalid) 73 COMPONENT_THROW(-1); 74 return *mPtrs; 75 } 76 77 /*! @method CopyBufferListTo */ CopyBufferListTo(AudioBufferList & abl)78 void CopyBufferListTo(AudioBufferList &abl) const { 79 if (mPtrState == kPtrsInvalid) 80 COMPONENT_THROW(-1); 81 memcpy(&abl, mPtrs, (char *)&abl.mBuffers[abl.mNumberBuffers] - (char *)&abl); 82 } 83 84 /*! @method CopyBufferContentsTo */ CopyBufferContentsTo(AudioBufferList & abl)85 void CopyBufferContentsTo(AudioBufferList &abl) const { 86 if (mPtrState == kPtrsInvalid) 87 COMPONENT_THROW(-1); 88 const AudioBuffer *srcbuf = mPtrs->mBuffers; 89 AudioBuffer *destbuf = abl.mBuffers; 90 91 for (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++srcbuf, ++destbuf) { 92 if (i >= mPtrs->mNumberBuffers) // duplicate last source to additional outputs [4341137] 93 --srcbuf; 94 if (destbuf->mData != srcbuf->mData) 95 memmove(destbuf->mData, srcbuf->mData, srcbuf->mDataByteSize); 96 destbuf->mDataByteSize = srcbuf->mDataByteSize; 97 } 98 } 99 100 /*! @method Allocate */ 101 void Allocate(const CAStreamBasicDescription &format, UInt32 nFrames); 102 /*! @method Deallocate */ 103 void Deallocate(); 104 105 /*! @method UseExternalBuffer */ 106 void UseExternalBuffer(const CAStreamBasicDescription &format, const AudioUnitExternalBuffer &buf); 107 108 // AudioBufferList utilities 109 /*! @method ZeroBuffer */ ZeroBuffer(AudioBufferList & abl)110 static void ZeroBuffer(AudioBufferList &abl) { 111 AudioBuffer *buf = abl.mBuffers; 112 for (UInt32 i = abl.mNumberBuffers ; i--; ++buf) 113 memset(buf->mData, 0, buf->mDataByteSize); 114 } 115 #if DEBUG 116 /*! @method PrintBuffer */ 117 static void PrintBuffer(const char *label, int subscript, const AudioBufferList &abl, UInt32 nFrames = 8, bool asFloats = true); 118 #endif 119 120 /*! @method GetAllocatedFrames */ GetAllocatedFrames()121 UInt32 GetAllocatedFrames() const { return mAllocatedFrames; } 122 123 private: 124 /*! @ctor AUBufferList */ AUBufferList(AUBufferList &)125 AUBufferList(AUBufferList &) { } // prohibit copy constructor 126 127 /*! @var mPtrState */ 128 EPtrState mPtrState; 129 /*! @var mExternalMemory */ 130 bool mExternalMemory; 131 /*! @var mPtrs */ 132 AudioBufferList * mPtrs; 133 /*! @var mMemory */ 134 Byte * mMemory; 135 /*! @var mAllocatedStreams */ 136 UInt32 mAllocatedStreams; 137 /*! @var mAllocatedFrames */ 138 UInt32 mAllocatedFrames; 139 /*! @var mAllocatedBytes */ 140 UInt32 mAllocatedBytes; 141 }; 142 143 144 // Allocates an array of samples (type T), to be optimally aligned for the processor 145 /*! @class TAUBuffer */ 146 template <class T> 147 class TAUBuffer { 148 public: 149 enum { 150 kAlignInterval = 0x10, 151 kAlignMask = kAlignInterval - 1 152 }; 153 154 /*! @ctor TAUBuffer.0 */ TAUBuffer()155 TAUBuffer() : mMemObject(NULL), mAlignedBuffer(NULL), mBufferSizeBytes(0) 156 { 157 } 158 159 /*! @ctor TAUBuffer.1 */ TAUBuffer(UInt32 numElems,UInt32 numChannels)160 TAUBuffer(UInt32 numElems, UInt32 numChannels) : mMemObject(NULL), mAlignedBuffer(NULL), 161 mBufferSizeBytes(0) 162 { 163 Allocate(numElems, numChannels); 164 } 165 166 /*! @dtor ~TAUBuffer */ ~TAUBuffer()167 ~TAUBuffer() 168 { 169 Deallocate(); 170 } 171 172 /*! @method Allocate */ Allocate(UInt32 numElems)173 void Allocate(UInt32 numElems) // can also re-allocate 174 { 175 UInt32 reqSize = numElems * sizeof(T); 176 177 if (mMemObject != NULL && reqSize == mBufferSizeBytes) 178 return; // already allocated 179 180 mBufferSizeBytes = reqSize; 181 mMemObject = CA_realloc(mMemObject, reqSize); 182 UInt32 misalign = (uintptr_t)mMemObject & kAlignMask; 183 if (misalign) { 184 mMemObject = CA_realloc(mMemObject, reqSize + kAlignMask); 185 mAlignedBuffer = (T *)((char *)mMemObject + kAlignInterval - misalign); 186 } else 187 mAlignedBuffer = (T *)mMemObject; 188 } 189 190 /*! @method Deallocate */ Deallocate()191 void Deallocate() 192 { 193 if (mMemObject == NULL) return; // so this method has no effect if we're using 194 // an external buffer 195 196 free(mMemObject); 197 mMemObject = NULL; 198 mAlignedBuffer = NULL; 199 mBufferSizeBytes = 0; 200 } 201 202 /*! @method AllocateClear */ AllocateClear(UInt32 numElems)203 void AllocateClear(UInt32 numElems) // can also re-allocate 204 { 205 Allocate(numElems); 206 Clear(); 207 } 208 209 /*! @method Clear */ Clear()210 void Clear() 211 { 212 memset(mAlignedBuffer, 0, mBufferSizeBytes); 213 } 214 215 // accessors 216 217 /*! @method operator T *()@ */ 218 operator T *() { return mAlignedBuffer; } 219 220 private: 221 /*! @var mMemObject */ 222 void * mMemObject; // null when using an external buffer 223 /*! @var mAlignedBuffer */ 224 T * mAlignedBuffer; // always valid once allocated 225 /*! @var mBufferSizeBytes */ 226 UInt32 mBufferSizeBytes; 227 }; 228 229 #endif // __AUBuffer_h__ 230