1/********************************************************************************************************************************** 2 * 3 * OpenAL cross platform audio library 4 * Copyright (c) 2004, Apple Computer, Inc., Copyright (c) 2012, Apple Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without modification, are permitted provided 7 * that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 11 * disclaimer in the documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its contributors may be used to endorse or promote 13 * products derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 18 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 19 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 20 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21 * 22 **********************************************************************************************************************************/ 23 24#include "oalRingBuffer.h" 25 26// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 27// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 28#pragma mark ***** OALRingBuffer ***** 29// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 30OALRingBuffer::OALRingBuffer() : mBuffer(NULL), mCapacityFrames(0), mCapacityBytes(0) 31{ 32} 33 34OALRingBuffer::OALRingBuffer(UInt32 bytesPerFrame, UInt32 capacityFrames) : 35mBuffer(NULL) 36{ 37 Allocate(bytesPerFrame, capacityFrames); 38} 39 40OALRingBuffer::~OALRingBuffer() 41{ 42 Deallocate(); 43} 44 45void OALRingBuffer::Allocate(UInt32 bytesPerFrame, UInt32 capacityFrames) 46{ 47 Deallocate(); 48 mBytesPerFrame = bytesPerFrame; 49 mCapacityFrames = capacityFrames; 50 mCapacityBytes = bytesPerFrame * capacityFrames; 51 mBuffer = (Byte *)malloc(mCapacityBytes); 52 Clear(); 53} 54 55void OALRingBuffer::Deallocate() 56{ 57 if (mBuffer) { 58 free(mBuffer); 59 mBuffer = NULL; 60 } 61 mCapacityBytes = 0; 62 mCapacityFrames = 0; 63 Clear(); 64} 65 66void OALRingBuffer::Clear() 67{ 68 if (mBuffer) 69 memset(mBuffer, 0, mCapacityBytes); 70 mStartOffset = 0; 71 mStartFrame = 0; 72 mEndFrame = 0; 73} 74 75bool OALRingBuffer::Store(const Byte *data, UInt32 nFrames, SInt64 startFrame) 76{ 77 if (nFrames > mCapacityFrames) return false; 78 79 // reading and writing could well be in separate threads 80 81 SInt64 endFrame = startFrame + nFrames; 82 if (startFrame >= mEndFrame + mCapacityFrames) 83 // writing more than one buffer ahead -- fine but that means that everything we have is now too far in the past 84 Clear(); 85 86 if (mStartFrame == 0) { 87 // empty buffer 88 mStartOffset = 0; 89 mStartFrame = startFrame; 90 mEndFrame = endFrame; 91 memcpy(mBuffer, data, nFrames * mBytesPerFrame); 92 } else { 93 UInt32 offset0, offset1, nBytes; 94 if (endFrame > mEndFrame) { 95 // advancing (as will be usual with sequential stores) 96 97 if (startFrame > mEndFrame) { 98 // we are skipping some samples, so zero the range we are skipping 99 offset0 = FrameOffset(mEndFrame); 100 offset1 = FrameOffset(startFrame); 101 if (offset0 < offset1) 102 memset(mBuffer + offset0, 0, offset1 - offset0); 103 else { 104 nBytes = mCapacityBytes - offset0; 105 memset(mBuffer + offset0, 0, nBytes); 106 memset(mBuffer, 0, offset1); 107 } 108 } 109 mEndFrame = endFrame; 110 111 // except for the case of not having wrapped yet, we will normally 112 // have to advance the start 113 SInt64 newStart = mEndFrame - mCapacityFrames; 114 if (newStart > mStartFrame) { 115 mStartOffset = (mStartOffset + (newStart - mStartFrame) * mBytesPerFrame) % mCapacityBytes; 116 mStartFrame = newStart; 117 } 118 } 119 // now everything is lined up and we can just write the new data 120 offset0 = FrameOffset(startFrame); 121 offset1 = FrameOffset(endFrame); 122 if (offset0 < offset1) 123 memcpy(mBuffer + offset0, data, offset1 - offset0); 124 else { 125 nBytes = mCapacityBytes - offset0; 126 memcpy(mBuffer + offset0, data, nBytes); 127 memcpy(mBuffer, data + nBytes, offset1); 128 } 129 } 130 return true; 131} 132 133OSStatus OALRingBuffer::Fetch(Byte *data, UInt32 nFrames, SInt64 startFrame) 134{ 135 SInt64 endFrame = startFrame + nFrames; 136 if (startFrame < mStartFrame || endFrame > mEndFrame) { 137 return -1; 138 } 139 140 UInt32 offset0 = FrameOffset(startFrame); 141 UInt32 offset1 = FrameOffset(endFrame); 142 143 if (offset0 < offset1) 144 memcpy(data, mBuffer + offset0, offset1 - offset0); 145 else { 146 UInt32 nBytes = mCapacityBytes - offset0; 147 memcpy(data, mBuffer + offset0, nBytes); 148 memcpy(data + nBytes, mBuffer, offset1); 149 } 150 return noErr; 151} 152 153Byte * OALRingBuffer::GetFramePtr(SInt64 frameNumber, UInt32 &outNFrames) 154{ 155 if (frameNumber < mStartFrame || frameNumber >= mEndFrame) { 156 outNFrames = 0; 157 return NULL; 158 } 159 UInt32 offset0 = FrameOffset(frameNumber); 160 UInt32 offset1 = FrameOffset(mEndFrame); 161 if (offset0 < offset1) { 162 outNFrames = static_cast<UInt32>(mEndFrame - frameNumber); 163 } else { 164 outNFrames = (mCapacityBytes - offset0) / mBytesPerFrame; 165 } 166 return mBuffer + offset0; 167} 168