Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/util/pa_ringbuffer.c

Go to the documentation of this file.
00001 /*
00002  * $Id: pa_ringbuffer.c 1738 2011-08-18 11:47:28Z rossb $
00003  * Portable Audio I/O Library
00004  * Ring Buffer utility.
00005  *
00006  * Author: Phil Burk, http://www.softsynth.com
00007  * modified for SMP safety on Mac OS X by Bjorn Roche
00008  * modified for SMP safety on Linux by Leland Lucius
00009  * also, allowed for const where possible
00010  * modified for multiple-byte-sized data elements by Sven Fischer
00011  *
00012  * Note that this is safe only for a single-thread reader and a
00013  * single-thread writer.
00014  *
00015  * This program uses the PortAudio Portable Audio Library.
00016  * For more information see: http://www.portaudio.com
00017  * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
00018  *
00019  * Permission is hereby granted, free of charge, to any person obtaining
00020  * a copy of this software and associated documentation files
00021  * (the "Software"), to deal in the Software without restriction,
00022  * including without limitation the rights to use, copy, modify, merge,
00023  * publish, distribute, sublicense, and/or sell copies of the Software,
00024  * and to permit persons to whom the Software is furnished to do so,
00025  * subject to the following conditions:
00026  *
00027  * The above copyright notice and this permission notice shall be
00028  * included in all copies or substantial portions of the Software.
00029  *
00030  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00031  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00032  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00033  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
00034  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
00035  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00036  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00037  */
00038 
00039 /*
00040  * The text above constitutes the entire PortAudio license; however,
00041  * the PortAudio community also makes the following non-binding requests:
00042  *
00043  * Any person wishing to distribute modifications to the Software is
00044  * requested to send the modifications to the original developer so that
00045  * they can be incorporated into the canonical version. It is also
00046  * requested that these non-binding requests be included along with the
00047  * license above.
00048  */
00049 
00055 #include <stdio.h>
00056 #include <stdlib.h>
00057 #include <math.h>
00058 #include <string.h>
00059 
00060 #include "util/pa_memorybarrier.h"
00061 #include "util/pa_ringbuffer.h"
00062 
00063 /***************************************************************************
00064  * Initialize FIFO.
00065  * elementCount must be power of 2, returns -1 if not.
00066  */
00067 ring_buffer_size_t PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementSizeBytes, ring_buffer_size_t elementCount, void *dataPtr )
00068 {
00069     if( ((elementCount-1) & elementCount) != 0) return -1; /* Not Power of two. */
00070     rbuf->bufferSize = elementCount;
00071     rbuf->buffer = (char *)dataPtr;
00072     PaUtil_FlushRingBuffer( rbuf );
00073     rbuf->bigMask = (elementCount*2)-1;
00074     rbuf->smallMask = (elementCount)-1;
00075     rbuf->elementSizeBytes = elementSizeBytes;
00076     return 0;
00077 }
00078 
00079 /***************************************************************************
00080 ** Return number of elements available for reading. */
00081 ring_buffer_size_t PaUtil_GetRingBufferReadAvailable( const PaUtilRingBuffer *rbuf )
00082 {
00083     return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );
00084 }
00085 /***************************************************************************
00086 ** Return number of elements available for writing. */
00087 ring_buffer_size_t PaUtil_GetRingBufferWriteAvailable( const PaUtilRingBuffer *rbuf )
00088 {
00089     return ( rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf));
00090 }
00091 
00092 /***************************************************************************
00093 ** Clear buffer. Should only be called when buffer is NOT being read or written. */
00094 void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf )
00095 {
00096     rbuf->writeIndex = rbuf->readIndex = 0;
00097 }
00098 
00099 /***************************************************************************
00100 ** Get address of region(s) to which we can write data.
00101 ** If the region is contiguous, size2 will be zero.
00102 ** If non-contiguous, size2 will be the size of second region.
00103 ** Returns room available to be written or elementCount, whichever is smaller.
00104 */
00105 ring_buffer_size_t PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount,
00106                                        void **dataPtr1, ring_buffer_size_t *sizePtr1,
00107                                        void **dataPtr2, ring_buffer_size_t *sizePtr2 )
00108 {
00109     ring_buffer_size_t   index;
00110     ring_buffer_size_t   available = PaUtil_GetRingBufferWriteAvailable( rbuf );
00111     if( elementCount > available ) elementCount = available;
00112     /* Check to see if write is not contiguous. */
00113     index = rbuf->writeIndex & rbuf->smallMask;
00114     if( (index + elementCount) > rbuf->bufferSize )
00115     {
00116         /* Write data in two blocks that wrap the buffer. */
00117         ring_buffer_size_t   firstHalf = rbuf->bufferSize - index;
00118         *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
00119         *sizePtr1 = firstHalf;
00120         *dataPtr2 = &rbuf->buffer[0];
00121         *sizePtr2 = elementCount - firstHalf;
00122     }
00123     else
00124     {
00125         *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
00126         *sizePtr1 = elementCount;
00127         *dataPtr2 = NULL;
00128         *sizePtr2 = 0;
00129     }
00130 
00131     if( available )
00132         PaUtil_FullMemoryBarrier(); /* (write-after-read) => full barrier */
00133 
00134     return elementCount;
00135 }
00136 
00137 
00138 /***************************************************************************
00139 */
00140 ring_buffer_size_t PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount )
00141 {
00142     /* ensure that previous writes are seen before we update the write index
00143        (write after write)
00144     */
00145     PaUtil_WriteMemoryBarrier();
00146     return rbuf->writeIndex = (rbuf->writeIndex + elementCount) & rbuf->bigMask;
00147 }
00148 
00149 /***************************************************************************
00150 ** Get address of region(s) from which we can read data.
00151 ** If the region is contiguous, size2 will be zero.
00152 ** If non-contiguous, size2 will be the size of second region.
00153 ** Returns room available to be read or elementCount, whichever is smaller.
00154 */
00155 ring_buffer_size_t PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount,
00156                                 void **dataPtr1, ring_buffer_size_t *sizePtr1,
00157                                 void **dataPtr2, ring_buffer_size_t *sizePtr2 )
00158 {
00159     ring_buffer_size_t   index;
00160     ring_buffer_size_t   available = PaUtil_GetRingBufferReadAvailable( rbuf ); /* doesn't use memory barrier */
00161     if( elementCount > available ) elementCount = available;
00162     /* Check to see if read is not contiguous. */
00163     index = rbuf->readIndex & rbuf->smallMask;
00164     if( (index + elementCount) > rbuf->bufferSize )
00165     {
00166         /* Write data in two blocks that wrap the buffer. */
00167         ring_buffer_size_t firstHalf = rbuf->bufferSize - index;
00168         *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
00169         *sizePtr1 = firstHalf;
00170         *dataPtr2 = &rbuf->buffer[0];
00171         *sizePtr2 = elementCount - firstHalf;
00172     }
00173     else
00174     {
00175         *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
00176         *sizePtr1 = elementCount;
00177         *dataPtr2 = NULL;
00178         *sizePtr2 = 0;
00179     }
00180 
00181     if( available )
00182         PaUtil_ReadMemoryBarrier(); /* (read-after-read) => read barrier */
00183 
00184     return elementCount;
00185 }
00186 /***************************************************************************
00187 */
00188 ring_buffer_size_t PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount )
00189 {
00190     /* ensure that previous reads (copies out of the ring buffer) are always completed before updating (writing) the read index.
00191        (write-after-read) => full barrier
00192     */
00193     PaUtil_FullMemoryBarrier();
00194     return rbuf->readIndex = (rbuf->readIndex + elementCount) & rbuf->bigMask;
00195 }
00196 
00197 /***************************************************************************
00198 ** Return elements written. */
00199 ring_buffer_size_t PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, ring_buffer_size_t elementCount )
00200 {
00201     ring_buffer_size_t size1, size2, numWritten;
00202     void *data1, *data2;
00203     numWritten = PaUtil_GetRingBufferWriteRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 );
00204     if( size2 > 0 )
00205     {
00206 
00207         memcpy( data1, data, size1*rbuf->elementSizeBytes );
00208         data = ((char *)data) + size1*rbuf->elementSizeBytes;
00209         memcpy( data2, data, size2*rbuf->elementSizeBytes );
00210     }
00211     else
00212     {
00213         memcpy( data1, data, size1*rbuf->elementSizeBytes );
00214     }
00215     PaUtil_AdvanceRingBufferWriteIndex( rbuf, numWritten );
00216     return numWritten;
00217 }
00218 
00219 /***************************************************************************
00220 ** Return elements read. */
00221 ring_buffer_size_t PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, ring_buffer_size_t elementCount )
00222 {
00223     ring_buffer_size_t size1, size2, numRead;
00224     void *data1, *data2;
00225     numRead = PaUtil_GetRingBufferReadRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 );
00226     if( size2 > 0 )
00227     {
00228         memcpy( data, data1, size1*rbuf->elementSizeBytes );
00229         data = ((char *)data) + size1*rbuf->elementSizeBytes;
00230         memcpy( data, data2, size2*rbuf->elementSizeBytes );
00231     }
00232     else
00233     {
00234         memcpy( data, data1, size1*rbuf->elementSizeBytes );
00235     }
00236     PaUtil_AdvanceRingBufferReadIndex( rbuf, numRead );
00237     return numRead;
00238 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines