1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
// ring.h -- lightweight ring buffers for sound i/o
//
// Author: Ian.Piumarta@INRIA.Fr
//
// Last edited:
//
// Copyright (C) 1996-2004 by Ian Piumarta and other authors/contributors
// listed elsewhere in this file.
// All rights reserved.
//
// This file is part of Unix Squeak.
//
// You are NOT ALLOWED to distribute modified versions of this file
// under its original name. If you modify this file then you MUST
// rename it before making your modifications available publicly.
//
// This file is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// You may use and/or distribute this file ONLY as part of Squeak, under
// the terms of the Squeak License as described in `LICENSE' in the base of
// this distribution, subject to the following additional restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment to the original author(s) (and any
// other contributors mentioned herein) in the product documentation
// would be appreciated but is not required.
//
// 2. You must not distribute (or make publicly available by any
// means) a modified copy of this file unless you first rename it.
//
// 3. This notice must not be removed or altered in any source distribution.
//
// Using (or modifying this file for use) in any context other than Squeak
// changes these copyright conditions. Read the file `COPYING' in the
// directory `platforms/unix/doc' before proceeding with any such use.
typedef struct _ring
{
char **bufs;
int bufCount;
int bufSize;
int iBuf;
int oBuf;
int nBufs;
} ring;
static ring *ring_new(int bufCount, int bufSize)
{
ring *r= (ring *)malloc(sizeof(ring));
if (r)
{
if ((r->bufs= (char **)malloc(bufCount * sizeof(char *))))
{
// Would there be any advantage to allocating wired memory
// via mmap() and mlock()?
int i;
for (i= 0; i < bufCount; ++i)
if (!(r->bufs[i]= (char *)malloc(bufSize)))
goto fail;
r->bufCount = bufCount;
r->bufSize = bufSize;
r->iBuf = 0;
r->oBuf = 0;
r->nBufs = 0;
return r;
fail:
printf("sound: could not allocate ring buffer memory\n");
while (i--)
free(r->bufs[i]);
free(r->bufs);
}
free(r);
}
return 0;
}
static void ring_delete(ring *r)
{
int i;
assert(r);
assert(r->bufs);
for (i= 0; i < r->bufCount; ++i)
{
assert(r->bufs[i]);
free(r->bufs[i]);
}
free(r->bufs);
free(r);
}
// counting the number of filled buffers saves an awful lot of tedious
// logic involving the front and back pointers, which in turn saves an
// awful lot of tedious locking of mutexes. the incr/decrs are
// effectively atomic and races will always fail conservatively (no
// data for input when 1 buffer has just been filled by the ioproc, no
// space for output when 1 buffer was just emptied by the ioproc) and
// cause an immediate retry (since the reader/writer is always the
// image -- the ioproc chugs along happily irrespective of the
// apparent buffer state).
static inline int ring_isEmpty(ring *r) { return r->nBufs == 0; }
static inline int ring_freeBufs(ring *r) { return r->bufCount - r->nBufs; }
static inline int ring_availBufs(ring *r) { return r->nBufs; }
static inline int ring_freeBytes(ring *r) { return ring_freeBufs(r) * r->bufSize; }
static inline int ring_availBytes(ring *r) { return ring_availBufs(r) * r->bufSize; }
static inline void ring_oAdvance(ring *r)
{
assert(r->nBufs > 0);
r->oBuf= (r->oBuf + 1) % r->bufCount;
r->nBufs--;
}
static inline void ring_iAdvance(ring *r)
{
assert(r->nBufs < r->bufCount);
r->iBuf= (r->iBuf + 1) % r->bufCount;
r->nBufs++;
}
static inline char *ring_inputPointer(ring *r)
{
return r->bufs[r->iBuf];
}
#if 0
static int ring_copyIn(ring *r, char *bytes, int size)
{
int freeBufs= ring_freeBufs(r);
char *in= bytes;
while (freeBufs-- && (size >= r->bufSize))
{
memcpy(r->bufs[r->iBuf], bytes, r->bufSize);
in += r->bufSize;
size -= r->bufSize;
ring_iAdvance(r);
}
return in - bytes;
}
#endif
static int ring_copyOut(ring *r, char *bytes, int size)
{
int availBufs= ring_availBufs(r);
char *out= bytes;
while (availBufs-- && (size >= r->bufSize))
{
memcpy(out, r->bufs[r->oBuf], r->bufSize);
out += r->bufSize;
size -= r->bufSize;
ring_oAdvance(r);
}
return out - bytes;
}
|