summaryrefslogtreecommitdiff
path: root/libs/appleutility/CoreAudio/AudioUnits/AUPublic/Utility/AUBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/appleutility/CoreAudio/AudioUnits/AUPublic/Utility/AUBuffer.cpp')
-rw-r--r--libs/appleutility/CoreAudio/AudioUnits/AUPublic/Utility/AUBuffer.cpp219
1 files changed, 219 insertions, 0 deletions
diff --git a/libs/appleutility/CoreAudio/AudioUnits/AUPublic/Utility/AUBuffer.cpp b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/Utility/AUBuffer.cpp
new file mode 100644
index 0000000000..36bb41fa58
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioUnits/AUPublic/Utility/AUBuffer.cpp
@@ -0,0 +1,219 @@
+/*
+ File: AUBuffer.cpp
+ Abstract: AUBuffer.h
+ Version: 1.1
+
+ 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.
+
+ Copyright (C) 2014 Apple Inc. All Rights Reserved.
+
+*/
+#include "AUBuffer.h"
+#include <stdlib.h>
+
+AUBufferList::~AUBufferList()
+{
+ Deallocate();
+ if (mPtrs)
+ free(mPtrs);
+}
+
+// a * b + c
+static UInt32 SafeMultiplyAddUInt32(UInt32 a, UInt32 b, UInt32 c)
+{
+ if (a == 0 || b == 0) return c; // prevent zero divide
+
+ if (a > (0xFFFFFFFF - c) / b)
+ throw std::bad_alloc();
+
+ return a * b + c;
+}
+
+void AUBufferList::Allocate(const CAStreamBasicDescription &format, UInt32 nFrames)
+{
+ UInt32 nStreams;
+ if (format.IsInterleaved()) {
+ nStreams = 1;
+ } else {
+ nStreams = format.mChannelsPerFrame;
+ }
+
+ // careful -- the I/O thread could be running!
+ if (nStreams > mAllocatedStreams) {
+ size_t theHeaderSize = sizeof(AudioBufferList) - sizeof(AudioBuffer);
+ mPtrs = (AudioBufferList *)CA_realloc(mPtrs,
+ SafeMultiplyAddUInt32(nStreams, sizeof(AudioBuffer), theHeaderSize));
+ mAllocatedStreams = nStreams;
+ }
+ UInt32 bytesPerStream = SafeMultiplyAddUInt32(nFrames, format.mBytesPerFrame, 0xF) & ~0xF;
+ UInt32 nBytes = SafeMultiplyAddUInt32(nStreams, bytesPerStream, 0);
+ 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