CLAM-Development
1.1
|
00001 /* 00002 * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG) 00003 * UNIVERSITAT POMPEU FABRA 00004 * 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 * 00020 */ 00021 00022 #ifndef _CircularBuffer_ 00023 #define _CircularBuffer_ 00024 00025 #include "Array.hxx" 00026 #include "DataTypes.hxx" 00027 #include "Err.hxx" 00028 00029 namespace CLAM 00030 { 00031 00032 00046 template <class T> class CircularBuffer 00047 { 00048 protected: 00049 Array<T> mBuffer; 00050 TSize mLogicalSize; 00051 TSize mReadSize; 00052 TSize mWriteSize; 00053 TSize mWriteIndex; // XXX: might want these mutable and read-like methods declared const 00054 TSize mReadIndex; // XXX: might want these mutable and read-like methods declared const 00055 TSize mInitialReadOffset; 00056 TSize mInitialWriteOffset; 00057 00058 public: 00059 00066 CircularBuffer() : mBuffer() 00067 { 00068 mWriteIndex = 0; 00069 mReadIndex = 0; 00070 mReadSize = mWriteSize = 1; 00071 mInitialReadOffset = 0; 00072 mInitialWriteOffset = 0; 00073 SetBufferSize(0); 00074 mLogicalSize = 0; 00075 } 00076 00082 CircularBuffer(TSize bufferSize) : mBuffer(bufferSize) 00083 { 00084 CLAM_ASSERT(bufferSize > 0, "CircularBuffer:CircularBuffer: BufferSize has to be larger than zero"); 00085 SetBufferSize(bufferSize); 00086 mWriteIndex = 0; 00087 mReadIndex = 0; 00088 mReadSize = mWriteSize = 1; 00089 mInitialReadOffset = 0; 00090 mInitialWriteOffset = 0; 00091 mLogicalSize = 0; 00092 } 00093 00094 // Methods for setting up the buffer: ------------------------------------------- 00095 00099 TSize GetBufferSize() const 00100 { 00101 return mBuffer.Size()-GetReadSize(); 00102 } 00103 00109 void SetBufferSize(TSize size) 00110 { 00111 mBuffer.Resize(size+GetReadSize()); 00112 mBuffer.SetSize(size+GetReadSize()); 00113 InitPointers(); 00114 } 00115 00120 TSize GetWriteIndex() const 00121 { 00122 return mWriteIndex; 00123 } 00124 00129 TSize GetReadIndex() const 00130 { 00131 return mReadIndex; 00132 } 00133 00139 TSize GetInitialReadOffset() const 00140 { 00141 return mInitialReadOffset; 00142 } 00143 00150 void SetInitialReadOffset(TSize size) 00151 { 00152 CLAM_ASSERT((size >= 0)&&(size < GetBufferSize()-1), 00153 "CircularBuffer:SetInitialReadOffset: InitialReadOffset has to be larger than zero"); 00154 mInitialReadOffset = size; 00155 } 00156 00162 TSize GetInitialWriteOffset() const 00163 { 00164 return mInitialWriteOffset; 00165 } 00166 00173 void SetInitialWriteOffset(TSize size) 00174 { 00175 CLAM_ASSERT((size >= 0)&&(size < GetBufferSize()-1), 00176 "CircularBuffer:SetInitialWriteOffset: InitialWriteOffset has to be larger than zero"); 00177 mInitialWriteOffset = size; 00178 } 00179 00180 // Methods for data acces: ------------------------------------------------------ 00181 00187 void Init() 00188 { 00189 SetBufferToZero(); 00190 InitPointers(); 00191 } 00192 00196 void SetBufferToZero() 00197 { 00198 T *pBuffer; 00199 pBuffer = mBuffer.GetPtr(); 00200 memset(pBuffer, 0, GetBufferSize()*sizeof(T)); 00201 } 00202 00207 void InitPointers() 00208 { 00209 if(mInitialReadOffset < 0) 00210 mReadIndex = GetBufferSize() + mInitialReadOffset; 00211 else 00212 mReadIndex = mInitialReadOffset; 00213 if(mInitialWriteOffset < 0) 00214 mWriteIndex = GetBufferSize() + mInitialWriteOffset; 00215 else 00216 mWriteIndex = mInitialWriteOffset; 00217 mLogicalSize=0; 00218 } 00219 00220 // Methods for reading and writing: --------------------------------------------- 00221 00226 void Read(T& element) 00227 { 00228 element = mBuffer[mReadIndex]; 00229 IncreaseReadIndex(); 00230 } 00231 00232 00233 void NonCopyRead(Array<T>& buffer) 00234 { 00235 TSize limit; 00236 if((limit=mReadIndex+mReadSize)>GetBufferSize()) 00237 { 00238 //will have to use phantom zone 00239 memcpy(mBuffer.GetPtr()+GetBufferSize(),mBuffer.GetPtr(),mReadSize*sizeof(T)); 00240 } 00241 buffer.SetPtr(mBuffer.GetPtr()+mReadIndex,mReadSize); 00242 IncreaseReadIndex(mReadSize); 00243 00244 00245 } 00246 00253 void Read(T* buffer) 00254 { 00255 TSize limit; 00256 if((limit=mReadIndex+mReadSize)>GetBufferSize()) 00257 { 00258 TSize secondHalf=limit%GetBufferSize(); 00259 TSize firstHalf=mReadSize-secondHalf; 00260 memcpy(buffer,mBuffer.GetPtr()+mReadIndex,firstHalf*sizeof(T)); 00261 memcpy(buffer+firstHalf,mBuffer.GetPtr(),secondHalf*sizeof(T)); 00262 } 00263 else 00264 { 00265 memcpy(buffer,mBuffer.GetPtr()+mReadIndex,mReadSize*sizeof(T)); 00266 } 00267 00268 IncreaseReadIndex(mReadSize); 00269 } 00270 00280 void Read(Array<T>& in, TSize offset = 0) // XXX: maybe call in, out instead? 00281 { 00282 CLAM_ASSERT(GetReadSize() <= in.Size()+offset, "Error, input buffer is not large enough"); // XXX: maybe call the input buffer the output buffer? 00283 00284 #ifdef CLAM_HIGH_OPTIMIZATIONS 00285 Read(in.GetPtr()+offset); 00286 #else 00287 for(int i=0;i<mReadSize;i++) 00288 Read(in[i+offset]); 00289 #endif 00290 } 00291 00295 void Write(const T& element) 00296 { 00297 mBuffer[mWriteIndex] = element; 00298 IncreaseWriteIndex(); 00299 } 00300 00306 void Write(const T* buffer) 00307 { 00308 TSize limit; 00309 if((limit=mWriteIndex+mWriteSize)>GetBufferSize()) 00310 { 00311 TSize secondHalf=limit%GetBufferSize(); 00312 TSize firstHalf=mWriteSize-secondHalf; 00313 memcpy(mBuffer.GetPtr()+mWriteIndex,buffer,firstHalf*sizeof(T)); 00314 memcpy(mBuffer.GetPtr(),buffer+firstHalf,secondHalf*sizeof(T)); 00315 } 00316 else 00317 { 00318 memcpy(mBuffer.GetPtr()+mWriteIndex,buffer,mWriteSize*sizeof(T)); 00319 } 00320 00321 IncreaseWriteIndex(mWriteSize); 00322 } 00323 00331 void Write(const Array<T>& in, TSize offset = 0) 00332 { 00333 CLAM_ASSERT(GetWriteSize()<=in.Size()+offset,"Error, input buffer is not large enough"); 00334 #ifdef CLAM_HIGH_OPTIMIZATIONS 00335 Write(in.GetPtr()+offset); 00336 #else 00337 for(int i=0;i<mWriteSize;i++) 00338 Write(in[i+offset]); 00339 #endif 00340 } 00341 00347 void Add(const T& elem) 00348 { 00349 mBuffer[mWriteIndex] += elem; 00350 IncreaseWriteIndex(); 00351 } 00352 00360 void Add(const Array<T>& in, TSize offset = 0) 00361 { 00362 CLAM_ASSERT(GetWriteSize()<=in.Size()+offset,"Error, input buffer is not large enough"); 00363 for(int i=0;i<mWriteSize;i++) 00364 Add(in[i+offset]); 00365 // XXX: might also want a CLAM_HIGH_OPTIMIZATIONS version of this method... 00366 } 00367 00372 void IncreaseReadIndex(TSize step = 1) 00373 { 00374 mReadIndex += step; 00375 mReadIndex=mReadIndex%GetBufferSize(); 00376 mLogicalSize-=step; 00377 CLAM_ASSERT(mLogicalSize>=0,"Error:Read Index surpassed Write Index"); 00378 } 00379 00384 void IncreaseWriteIndex(TSize step = 1) 00385 { 00386 // XXX: might want to assert that step > 0 00387 mWriteIndex += step; 00388 mWriteIndex =mWriteIndex%GetBufferSize(); 00389 mLogicalSize+=step; 00390 CLAM_ASSERT(mLogicalSize<=GetBufferSize(),"Error:Write Index surpassed Read Index"); 00391 } 00392 00397 void DecreaseReadIndex(TSize step = 1) 00398 { 00399 // XXX: might want to assert that step > 0 00400 mReadIndex -= step; 00401 mReadIndex =mReadIndex%GetBufferSize(); 00402 if(mReadIndex<0) mReadIndex=GetBufferSize()+mReadIndex; 00403 mLogicalSize+=step; 00404 CLAM_ASSERT(mLogicalSize<=GetBufferSize(),"Error:Write Index surpassed Read Index"); 00405 } 00406 00411 void DecreaseWriteIndex(TSize step = 1) 00412 { 00413 // XXX: might want to assert that step > 0 00414 mWriteIndex -= step; 00415 mWriteIndex =mWriteIndex%GetBufferSize(); 00416 if(mWriteIndex<0) mWriteIndex =GetBufferSize()+mWriteIndex ; 00417 mLogicalSize-=step; 00418 CLAM_ASSERT(mLogicalSize>=0,"Error:Read Index surpassed Write Index"); 00419 } 00420 00426 T& GetPtrToElement(int absPos) 00427 { 00428 int index = absPos%GetBufferSize(); // XXX: unnecessary copy. 00429 00430 return mBuffer[index]; 00431 } 00432 00433 // Getters and setters: --------------------------------------------------------- 00434 00440 TSize GetReadSize() const 00441 { 00442 return mReadSize; 00443 } 00444 00450 TSize GetWriteSize() const 00451 { 00452 return mWriteSize; 00453 } 00454 00459 void SetReadSize(TSize size) 00460 { 00461 CLAM_ASSERT(size>=0&&size<=GetBufferSize(),"AudioCircularBuffer:SetReadSize: ReadSize has to be larger than zero"); 00462 TSize previousBufferSize=GetBufferSize(); 00463 mReadSize = size; 00464 SetBufferSize(previousBufferSize); 00465 } 00466 00471 void SetWriteSize(TSize size) 00472 { 00473 CLAM_ASSERT(size>=0&&size<=GetBufferSize(),"AudioCircularBuffer:SetWriteSize: WriteSize has to be larger than zero"); 00474 mWriteSize = size; 00475 } 00476 }; 00477 00478 00479 00480 }; //end of namespace 00481 00482 #endif //_CircularBuffer_ 00483